Files
qad/qglview/water_system.cpp

231 lines
6.7 KiB
C++

/*
QGLView
Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "water_system.h"
WaterSystem::WaterSystem(): GLObjectBase() {
texture = 0;
near_offsets
<< Vector3i(-1, 0, 0)
<< Vector3i( 1, 0, 0)
<< Vector3i(-1, -1, 0)
<< Vector3i( 1, -1, 0)
<< Vector3i( 0, -1, 0)
<< Vector3i(-1, 1, 0)
<< Vector3i( 1, 1, 0)
<< Vector3i( 0, 1, 0)
<< Vector3i(-1, 0, -1)
<< Vector3i( 1, 0, -1)
<< Vector3i( 0, 0, -1)
<< Vector3i(-1, -1, -1)
<< Vector3i( 1, -1, -1)
<< Vector3i( 0, -1, -1)
<< Vector3i(-1, 1, -1)
<< Vector3i( 1, 1, -1)
<< Vector3i( 0, 1, -1)
<< Vector3i(-1, 0, 1)
<< Vector3i( 1, 0, 1)
<< Vector3i( 0, 0, 1)
<< Vector3i(-1, -1, 1)
<< Vector3i( 1, -1, 1)
<< Vector3i( 0, -1, 1)
<< Vector3i(-1, 1, 1)
<< Vector3i( 1, 1, 1)
<< Vector3i( 0, 1, 1);
}
WaterSystem::~WaterSystem() {
QList<BigChunk * > cv = big_chunks.values();
foreach (BigChunk * i, cv) {
qDebug() << "delete" << i;
delete i;
}
cv.clear();
}
void WaterSystem::update() {
QList<BigChunk * > cv = big_chunks.values();
//qDebug() << "save states" << cv.size();
foreach (BigChunk * i, cv)
i->saveState();
Particle tp;
if (part_count < 5000)
for (int i = 0; i < 10; ++i) {
tp.pos = QVector3D(urand()*20+30, urand()*20+30, 30);
tp.speed = QVector3D(urand(1.), urand(1.), 0.);
newBigChunk(tp.bigChunkIndex())->newChunk(tp.chunkIndex())->particles << tp;
}
QList<BigChunk * > near_big;
QList<Chunk * > near_;
QList<QVector<Particle> * > near_parts;
Vector3i cind, nind;
#if QT_VERSION >= 0x040700
near_big.reserve(27);
near_.reserve(27);
near_parts.reserve(27);
#endif
foreach (BigChunk * bc, cv) {
Vector3i bci = bc->index;
near_big.clear();
near_big << bc;
foreach (const Vector3i & o, near_offsets)
near_big << big_chunks.value(bci + o);
near_big.removeAll(0);
for (int i = 0; i < BIG_CHUNK_SIZE; ++i)
for (int j = 0; j < BIG_CHUNK_SIZE; ++j)
for (int k = 0; k < BIG_CHUNK_SIZE; ++k) {
Chunk * cc = bc->chunks[i][j][k];
if (cc == 0) continue;
near_.clear();
//foreach (const Vector3i & o, near_offsets)
// near_ << big_chunks.value(bci + o);
near_ << cc;
near_.removeAll(0);
near_parts.clear();
foreach (Chunk * ci, near_)
if (!ci->prev_particles.isEmpty())
near_parts << &(ci->prev_particles);
QVector<Particle> & parts(cc->particles);
//qDebug() << "chunk" << cc->index.toQVector3D() << "proc" << parts.size() << "particles";
for (int p = 0; p < parts.size(); ++p) {
Particle & cp(parts[p]);
//Vector3i obi = cp.bigChunkIndex(), oi = cp.chunkIndex();
if (cp.processed) continue;
cp.processed = true;
cind = cp.chunkIndex();
cp.process(near_parts);
nind = cp.chunkIndex();
if (nind == cind) continue;
newBigChunk(cp.bigChunkIndex())->newChunk(nind)->particles << cp;
parts.remove(p);
--p;
}
}
}
}
void WaterSystem::Particle::process(const QList<QVector<Particle> * > & near_parts) {
accel += Vector3d(0., 0., -0.98 / 60.) / mass;
speed += accel;
pos += speed;
speed *= 0.95;
GLfloat sm = speed.length();//piMax<GLfloat>(fabs(speed.x), fabs(speed.y), fabs(speed.z));
if (sm > 0.2)
speed.normalize() *= 0.2;
if (pos.z - radius < 0.) {
pos.z = radius;
speed.z = -speed.z * 0.2;
speed *= 0.9;
accel.clear();
}
GLfloat sdist, srad, ssrad;
Vector3d dpos;
//return;
/*int cnt = 0;
foreach (QVector<Particle> * pl, near_parts)
cnt += pl->size();
qDebug() << cnt;*/
foreach (QVector<Particle> * pl, near_parts) {
QVector<Particle> & rpl(*pl);
for (int i = 0; i < rpl.size(); ++i) {
Particle & cp(rpl[i]);
srad = radius + cp.radius;
dpos = pos - cp.pos;
if (fabs(dpos.x) >= srad || fabs(dpos.y) >= srad || fabs(dpos.z) >= srad) continue;
ssrad = srad * srad;
sdist = dpos.lengthSquared();
if (sdist >= ssrad) continue;
//continue;
sdist = sqrt(sdist);
ssrad = (srad - sdist) / 2;
dpos *= ssrad / sdist;
//pos += dpos;
//cp.pos -= dpos;
//qDebug() << "intersect" << sdist << (pos - cp.pos).length();
speed -= speed.projectTo(dpos) * 2.;
cp.speed -= cp.speed.projectTo(dpos) * 2.;
speed *= 0.8;
cp.speed *= 0.8;
accel *= 0.8;
cp.accel *= 0.8;
}
}
}
void WaterSystem::draw(QGLShaderProgram * prog, bool simplest) {
//return;
pass_ = GLObjectBase::Transparent;
//qDebug() << "save states" << cv.size();
glPointSize(20);
GLfloat pp[] = {1.f, 1.f, 0.f};
//glEnable(GL_BLEND);
glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, pp);
//glDepthMask(GL_FALSE);
glNormal3f(0.f, 0.f, 1.f);
//glEnable(GL_POINT_SPRITE);
glDisable(GL_TEXTURE_2D);
glEnable(GL_VERTEX_ARRAY);
//glDisable(GL_BLEND);
//glDisable(GL_ALPHA_TEST);
glDisable(GL_NORMAL_ARRAY);
glDisable(GL_COLOR_ARRAY);
glDisable(GL_TEXTURE_COORD_ARRAY);
double ha = 1. / (big_chunks.size() + 1.), ch = 0.;
QVector<GLfloat> v;
QList<BigChunk * > cv = big_chunks.values();
part_count = 0;
foreach (BigChunk * bc, cv) {
for (int i = 0; i < BIG_CHUNK_SIZE; ++i)
for (int j = 0; j < BIG_CHUNK_SIZE; ++j)
for (int k = 0; k < BIG_CHUNK_SIZE; ++k) {
Chunk * cc = bc->chunks[i][j][k];
if (cc == 0) continue;
const QVector<Particle> & cp(cc->particles);
part_count += cp.size();
v.clear();
foreach (const Particle & p, cp)
v << p.pos.x << p.pos.y << p.pos.z;
qglColor(QColor::fromHsvF(ch, 1., 1.));
glVertexPointer(3, GL_FLOAT, 0, v.constData());
glDrawArrays(GL_POINTS, 0, v.size() / 3);
ch += ha;
while (ch > 1.) ch -= 1.;
}
}
qDebug() << "draw" << part_count << "water particles";
//glDepthMask(GL_TRUE);
/*if (!d_vertices.isEmpty()) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexPointer(3, GL_FLOAT, 0, d_vertices.constData());
glTexCoordPointer(2, GL_FLOAT, 0, d_uvs.constData());
//glColorPointer(4, GL_FLOAT, 0, d_colors.constData());
glNormalPointer(GL_FLOAT, 0, d_normals.constData());
glDrawArrays(geom_prim, 0, d_vertices.size() / 3);*/
/*if (pass_ == Reflection) {
glActiveTexture(GL_TEXTURE1);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
}*/
//}
}