/*************************************************************************** * Copyright (C) 2005 by Peter Müller * * pmueller@cs.tu-berlin.de * * Copyright (C) 2008 by John Stamp <jstamp@users.sourceforge.net> * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "rotatecomet.h" RotateComet::RotateComet(CometenScene * scene, double time, double _lifeTime, const Vec3f & _pos, const Vec3f & _vel, const Vec4f & _acolor1, const Vec4f & _ecolor1, const Vec4f & _acolor2, const Vec4f & _ecolor2) : Comet(scene, 1.0, _pos), startTime(time), lifeTime(_lifeTime), acolor1(_acolor1), ecolor1(_ecolor1), acolor2(_acolor2), ecolor2(_ecolor2) { GLuint tex = scene->textures[T_PARTICLE]; dir = _vel; vel = dir.normalize(); Vec3f::generateOrthonormalBasis(dir, up, right); radius = 1.75; psystem1 = new ParticleSystem(time, tex, _pos, _pos, 800, 0, 1.5, 2.0, true, 400, 0.0, 4.0, true, 3.0, acolor1, ecolor1); decal1 = new Decal(tex, _pos, 6.0, true, Vec3f::UNIT_X, acolor1); psystem2 = new ParticleSystem(time, tex, _pos, _pos, 800, 0, 1.5, 2.0, true, 400, 0.0, 4.0, false, 3.0, acolor2, ecolor2); decal2 = new Decal(tex, _pos, 6.0, true, Vec3f::UNIT_X, acolor2); destroyed = false; } RotateComet::~RotateComet() { delete psystem1; delete decal1; delete psystem2; delete decal2; } void RotateComet::process(double time, double deltat) { int i; int hitplane; double hittime; double t; double r; double w; if (!destroyed) { hitplane = -1; hittime = deltat; for (i = 0; i != scene->getNumPlanes(); i++) { // kill comets outside of the box if (position.dot(scene->getPlane(i).N) < scene->getPlane(i).d) { destroy(time); break; } if (TestDynamicSpherePlane(position, radius, dir*vel, scene->getPlane(i), t) && t <= hittime) { hitplane = i; hittime = t; } } position += dir * (vel * hittime); if (hitplane != -1) { hitPlane(time + hittime, scene->getPlane(hitplane)); } if (time - startTime > lifeTime) { destroy(time); } } t = (time - startTime) / lifeTime; if (t < 0.05) { r = 20 * t * radius; } else if (t > 0.95) { r = 20 * (1-t) * radius; } else { r = radius; } w = 12.0*time; pos1 = sinf(w)*r*up+cosf(w)*r*right + position; pos2 = sinf(w+Pi)*r*up+cosf(w+Pi)*r*right + position; decal1->setPosition(pos1); psystem1->setEmitterPos1(psystem1->getEmitterPos2()); psystem1->setEmitterPos2(pos1); psystem1->process(time); decal2->setPosition(pos2); psystem2->setEmitterPos1(psystem2->getEmitterPos2()); psystem2->setEmitterPos2(pos2); psystem2->process(time); if (destroyed) { psystem1->stop(); psystem2->stop(); } } void RotateComet::render(const Vec3f& campos) { if (!destroyed) { decal1->render(campos); decal2->render(campos); } psystem1->render(campos); psystem2->render(campos); } void RotateComet::hitPlane(double time, const Plane & plane) { double distance; const double e = 0.0001; Vec3f hitPoint1; Vec3f hitPoint2; double decalSize; Comet* glow; distance = pos1.dot(plane.N) - plane.d; hitPoint1 = pos1 - plane.N * (distance - 0.0001); distance = pos2.dot(plane.N) - plane.d; hitPoint2 = pos2 - plane.N * (distance - 0.0001); distance = position.dot(plane.N) - plane.d; // if comet intersects plane move along normal if (distance >= 0 && distance <= radius + e) { position += (plane.N * (radius + e - distance)); } else if (distance < 0 && distance >= -radius - e) { position += (plane.N * (-radius - e + distance)); } // bounce comet dir.reflect(plane.N); Vec3f::generateOrthonormalBasis(dir, up, right); decalSize = 50; glow = new Glow(scene, time, hitPoint1, decalSize, plane.N, acolor1); scene->addComet(glow); glow = new Glow(scene, time, hitPoint2, decalSize, plane.N, acolor2); scene->addComet(glow); } void RotateComet::destroy(double time) { Comet * newc; Vec3f pos1, pos2; int numChildren = rand(4,6); double w; Vec3f normal; for (int i = 0; i < numChildren; i++) { double t1 = frand(); double t2 = frand(); w = Pi*(double)i/numChildren; normal = sinf(w) * up + cosf(w) * right; newc = new SpComet(scene, time, position, normal, 18, t1*acolor1+(1-t1)*acolor2, t2*ecolor1+(1-t2)*ecolor2); scene->addComet(newc); } newc = new Explosion(scene, time, 1.0, position, 6, 400, acolor2, ecolor2); scene->addComet(newc); psystem1->stop(); psystem2->stop(); destroyed = true; } bool RotateComet::isDestroyed() { return destroyed; } bool RotateComet::isDone() { return destroyed && psystem1->done() && psystem2->done(); } SpComet::SpComet(CometenScene * scene, double time, const Vec3f & _pos, const Vec3f & normal, double _maxRadius, const Vec4f & _acolor, const Vec4f & _ecolor) : Comet(scene, 0.25, _pos), startPos(_pos), maxRadius(_maxRadius), startTime(time), acolor(_acolor), ecolor(_ecolor), destroyed(false) { GLuint tex = scene->textures[T_PARTICLE]; dir = normal; Vec3f::generateOrthonormalBasis(dir, up, right); up = Vec3f::randomUnitOnPlane(up, right); right = dir.cross(up); lifeTime = 0.75; psystem = new ParticleSystem(time, tex, _pos, _pos, 500, 0, 2.5, 3.0, true, 670, 0.0, 2.5, true, 2, acolor, ecolor); decal = new Decal(tex, _pos, 2.5, true, Vec3f::UNIT_X, acolor); } SpComet::~SpComet() { delete psystem; delete decal; } void SpComet::process(double time, double /*unused*/) { double t; double r; double w; double bw = scene->getBoxWidth()/2; double bh = scene->getBoxHeight()/2; t = (time - startTime) / lifeTime; if (t <= 0.25) { r = 4*t*maxRadius; } else if (t >= 0.75) { r = (1 - t) * 4 * maxRadius; } else { r = maxRadius; } w = t*4*Pi; position = sinf(w)*r*up+cosf(w)*r*right + startPos; position[0] = clamp<float>(position[0], -bw, bw); position[1] = clamp<float>(position[1], -bh, bh); position[2] = clamp<float>(position[2], -bw, bw); decal->setPosition(position); psystem->setEmitterPos1(psystem->getEmitterPos2()); psystem->setEmitterPos2(position); psystem->process(time); if (!destroyed) { if (time - startTime > lifeTime) { destroy(time); } } } void SpComet::render(const Vec3f& campos) { if (!destroyed) { decal->render(campos); } psystem->render(campos); } void SpComet::destroy(double time) { Comet * newc = 0; newc = new Explosion(scene, time, 1.0, position, 6, 100, acolor, ecolor); scene->addComet(newc); psystem->stop(); destroyed = true; } bool SpComet::isDestroyed() { return destroyed; } bool SpComet::isDone() { return destroyed && psystem->done(); }