216 lines
7.7 KiB
C++
216 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(QGLShaderProgram * prog, bool) {
|
|
if (particles.isEmpty()) return;
|
|
if (view_ == 0) return;
|
|
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);
|
|
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);
|
|
}
|