Files
qad/qglview/glparticles_system.cpp

217 lines
7.7 KiB
C++

/*
QGLView
Copyright (C) 2017 Ivan Pelipenko peri4ko@yandex.ru
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 "glparticles_system.h"
GLParticlesSystem::GLParticlesSystem(const QVector3D & pos): GLObjectBase() {
pass_ = GLObjectBase::Transparent;
freq = 40.f;
birthRate_ = 10.f;
lifeDuration_ = 2.f;
fade_time = 0.5f;
size_ = 1.f;
additionalSpeed = 0.f;
initialSpeed_ = 1.f;
need_birth = -1.f;
tex_rect.setRect(0., 0., 1., 1.);
tex_scale = QSizeF();
emitterPosition_ = pos;
emitterDirection_.setZ(1.);
speedDirection_.setZ(1.);
speedDecay_ = initialAngle_ = enlargeSpeed_ = enlargeSpeedJitter_ = baseAngle_ = 0.f;
lifeDurationJitter_ = speedJitter_ = speedDirectionJitter_ = sizeJitter_ = angleJitter_ = 0.f;
active_ = birthEnabled_ = true;
is_diffuse_anim = add_vert_face = false;
emitterType_ = Cone;
tick_life = 1.f / freq;
tick_birth = birthRate_ / freq;
}
void GLParticlesSystem::update() {
//qDebug() << "update" << need_birth << tick_birth;
if (!active_) return;
//QMutexLocker locker(&mutex);
Particle cp(lifeDuration_);
if (birthEnabled_) need_birth += tick_birth;
qDebug() << "update" << particles.size();
if (need_birth >= 1.f) {
cp.pos = emitterPosition_;
//qDebug() << "speed" << cp.speed;
cp.speedDecay = 1.f + speedDecay_;
for (int i = 0; i < floor(need_birth); ++i) {
cp.lifeDuration = lifeDuration_ + urand(lifeDurationJitter_);
switch (emitterType_) {
case Omni:
cp.speed = QVector3D(urand(), urand(), urand()).normalized() * initialSpeed_ * (1.f + urand(speedJitter_));
break;
case Cone: case Box:
cp.speed = emitterDirection_ * initialSpeed_ * (1.f + urand(speedJitter_));
cp.speed += orthToVector(cp.speed, speedDirectionJitter_);
break;
}
if (emitterType_ == Box)
cp.pos = emitterRect_.randomPoint();
//qDebug() << "before" << cp.speed.length();
lengthenVector(cp.speed, additionalSpeed);
//qDebug() << "after" << cp.speed.length();
cp.size = size_ + urand(sizeJitter_);
cp.angle = initialAngle_ + urand(angleJitter_);
cp.enlargeSpeed = (enlargeSpeed_ + urand(enlargeSpeedJitter_)) * tick_life;
/*if (is_diffuse_anim) {
if (material_.diffuse.animation_frame_rate < 0 && animation->bitmaps.size() > 0)
cp.animationFrameRate = animation->bitmaps.size() / cp.lifeDuration;
else
cp.animationFrameRate = material_.diffuse.animation_frame_rate;
}*/
if (tex_scale.isEmpty()) cp.tex_rect.setSize(tex_rect.size());
else cp.tex_rect.setSize(tex_rect.size() * tex_scale);
cp.tex_rect.moveTopLeft(tex_rect.topLeft() + QPointF(uprand(tex_rect.width() - cp.tex_rect.width()), uprand(tex_rect.height() - cp.tex_rect.height())));
//cp.tex_rect = tex_rect;
particles.push_back(cp);
}
need_birth -= floor(need_birth);
}
for (int i = 0; i < particles.size(); ++i) {
Particle & c(particles[i]);
foreach (const QVector3D & f, forces)
c.speed += f;
c.lifeCurrent += tick_life;
//qDebug() << "life" << c.lifeCurrent << c.lifeDuration;
if (c.lifeCurrent > c.lifeDuration) {
//qDebug() << "remove" << i;
particles.remove(i);
i--;
continue;
}
c.pos += c.speed * tick_life;
c.speed /= c.speedDecay;
c.size += c.enlargeSpeed;
//if (c.lifeCurrent > 1.) c.angle += urand(5.);
}
}
void GLParticlesSystem::draw(__GLShaderProgram__ * prog, bool) {
if (particles.isEmpty()) return;
if (view_ == 0) return;
QGLCI
pass_ = GLObjectBase::Transparent;
Camera & camera(view_->camera());
QVector3D apos = camera.pos(), dir = camera.direction();
//qDebug() << dir;
//qDebug() << camera.angles();
//qDebug() << camera.angle_xy;
GLfloat cxyc, czs, czc;
GLfloat dx, dy, cdx, cdy, cdz, a, tr_r = material_.color_diffuse.redF(),
tr_g = material_.color_diffuse.greenF(),
tr_b = material_.color_diffuse.blueF(),
tr_a = material_.color_diffuse.alphaF() * (1.f - material_.transparency);
//cxys = sin(camera.angle_xy * deg2rad);
cxyc = cos(camera.angles_.y() * deg2rad);
czs = sin(camera.angles_.z() * deg2rad);
czc = cos(camera.angles_.z() * deg2rad);
dx = -czc;
dy = czs;
vertices.clear();
texcoords.clear();
colors.clear();
for (int i = 0; i < particles.size(); ++i)
//particles[i].pos_h.setZ((particles[i].pos - apos).lengthSquared());
particles[i].pos_h.setZ(particles[i].pos.distanceToPlane(apos, dir));
qSort(particles.begin(), particles.end());
glBegin(GL_POINTS);
foreach (const Particle & i, particles) {
//glVertex3f(i.pos.x(), i.pos.y(), i.pos.z());
a = (i.lifeDuration - i.lifeCurrent) / fade_time;
if (a > 1.f) a = 1.f;
a *= tr_a;
cdx = dx * i.size;
cdy = dy * i.size;
cdz = i.size;
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z() - cdz;
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z() + cdz;
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z() + cdz;
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z() - cdz;
cdx = i.size;
cdy = i.size;
texcoords << i.tex_rect.right() << i.tex_rect.top();
texcoords << i.tex_rect.right() << i.tex_rect.bottom();
texcoords << i.tex_rect.left() << i.tex_rect.bottom();
texcoords << i.tex_rect.left() << i.tex_rect.top();
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
if (add_vert_face) {
if (cxyc > 0.) {
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z();
vertices << i.pos.x() + cdx << i.pos.y() - cdy << i.pos.z();
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z();
vertices << i.pos.x() - cdx << i.pos.y() + cdy << i.pos.z();
} else {
vertices << i.pos.x() - cdx << i.pos.y() - cdy << i.pos.z();
vertices << i.pos.x() - cdx << i.pos.y() + cdy << i.pos.z();
vertices << i.pos.x() + cdx << i.pos.y() + cdy << i.pos.z();
vertices << i.pos.x() + cdx << i.pos.y() - cdy << i.pos.z();
}
texcoords << i.tex_rect.right() << i.tex_rect.top();
texcoords << i.tex_rect.right() << i.tex_rect.bottom();
texcoords << i.tex_rect.left() << i.tex_rect.bottom();
texcoords << i.tex_rect.left() << i.tex_rect.top();
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
colors << tr_r << tr_g << tr_b << a;
}
}
glEnd();
//bool cae = glIsEnabled(GL_COLOR_ARRAY), nae = glIsEnabled(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
QGLC glBindBuffer(GL_ARRAY_BUFFER, 0);
//glNormal3f(vn.x(), vn.y(), vn.z());
glNormal3f(0., 0., 1.);
glDepthMask(false);
glEnable(GL_COLOR_ARRAY);
glDisable(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
glTexCoordPointer(2, GL_FLOAT, 0, texcoords.constData());
glColorPointer(4, GL_FLOAT, 0, colors.constData());
//glEnable(GL_ALPHA_TEST);
//glAlphaFunc();
glDrawArrays(GL_QUADS, 0, vertices.size() / 3);
glDepthMask(true);
//glDisable(GL_ALPHA_TEST);
//if (!cae) glDisable(GL_COLOR_ARRAY);
//if (nae) glEnable(GL_NORMAL_ARRAY);
}
GLParticlesSystem::Particle::Particle(float life_dur) {
size = 1.;
angle = lifeCurrent = 0.;
speedDecay = 0.;
lifeDuration = life_dur;
tex_rect = QRectF(0, 0, 1, 1);
}