/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsiteс.ch; http://colobot.info; http://github.com/colobot * * 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://gnu.org/licenses */ #include "graphics/engine/particle.h" #include "app/app.h" #include "common/iman.h" #include "common/logger.h" #include "graphics/core/device.h" #include "graphics/engine/engine.h" #include "graphics/engine/terrain.h" #include "graphics/engine/water.h" #include "math/geometry.h" #include "object/object.h" #include "object/robotmain.h" #include // Graphics module namespace namespace Gfx { const float FOG_HSUP = 10.0f; const float FOG_HINF = 100.0f; //! Check if an object can be destroyed, but is not an enemy bool IsSoft(ObjectType type) { return ( type == OBJECT_HUMAN || type == OBJECT_MOBILEfa || type == OBJECT_MOBILEta || type == OBJECT_MOBILEwa || type == OBJECT_MOBILEia || type == OBJECT_MOBILEfc || type == OBJECT_MOBILEtc || type == OBJECT_MOBILEwc || type == OBJECT_MOBILEic || type == OBJECT_MOBILEfi || type == OBJECT_MOBILEti || type == OBJECT_MOBILEwi || type == OBJECT_MOBILEii || type == OBJECT_MOBILEfs || type == OBJECT_MOBILEts || type == OBJECT_MOBILEws || type == OBJECT_MOBILEis || type == OBJECT_MOBILErt || type == OBJECT_MOBILErc || type == OBJECT_MOBILErr || type == OBJECT_MOBILErs || type == OBJECT_MOBILEsa || type == OBJECT_MOBILEft || type == OBJECT_MOBILEtt || type == OBJECT_MOBILEwt || type == OBJECT_MOBILEit || type == OBJECT_MOBILEdr || // robot? type == OBJECT_METAL || type == OBJECT_POWER || type == OBJECT_ATOMIC || // cargo? type == OBJECT_DERRICK || type == OBJECT_STATION || type == OBJECT_FACTORY || type == OBJECT_REPAIR || type == OBJECT_DESTROYER|| type == OBJECT_CONVERT || type == OBJECT_TOWER || type == OBJECT_RESEARCH || type == OBJECT_RADAR || type == OBJECT_INFO || type == OBJECT_ENERGY || type == OBJECT_LABO || type == OBJECT_NUCLEAR || type == OBJECT_PARA ); // building? } //! Check if an object is a destroyable enemy bool IsAlien(ObjectType type) { return ( type == OBJECT_ANT || type == OBJECT_SPIDER || type == OBJECT_BEE || type == OBJECT_WORM || type == OBJECT_MOTHER || type == OBJECT_NEST || type == OBJECT_BULLET || type == OBJECT_EGG || type == OBJECT_MOBILEtg || type == OBJECT_TEEN28 || type == OBJECT_TEEN31 ); } //! Returns the damping factor for friendly fire float GetDecay(ObjectType type) { if (IsSoft(type)) return 0.2f; return 1.0f; } CParticle::CParticle(CEngine* engine) { m_device = nullptr; m_engine = engine; m_main = nullptr; m_terrain = nullptr; m_water = nullptr; m_sound = nullptr; m_uniqueStamp = 0; m_exploGunCounter = 0; m_lastTimeGunDel = 0.0f; m_absTime = 0.0f; FlushParticle(); } CParticle::~CParticle() { } void CParticle::SetDevice(CDevice* device) { m_device = device; } void CParticle::FlushParticle() { for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) m_particle[i].used = false; for (int i = 0; i < MAXPARTITYPE; i++) { for (int j = 0; j < SH_MAX; j++) { m_totalInterface[i][j] = 0; } } for (int i = 0; i < MAXTRACK; i++) m_track[i].used = false; m_wheelTraceTotal = 0; m_wheelTraceIndex = 0; for (int i = 0; i < SH_MAX; i++) m_frameUpdate[i] = true; m_fogTotal = 0; m_exploGunCounter = 0; } void CParticle::FlushParticle(int sheet) { for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) { if (!m_particle[i].used) continue; if (m_particle[i].sheet != sheet) continue; m_particle[i].used = false; } for (int i = 0; i < MAXPARTITYPE; i++) m_totalInterface[i][sheet] = 0; for (int i = 0; i < MAXTRACK; i++) m_track[i].used = false; if (sheet == SH_WORLD) { m_wheelTraceTotal = 0; m_wheelTraceIndex = 0; } } //! Returns file name of the effect effectNN.png, with NN = number void NameParticle(std::string &name, int num) { if (num == 1) name = "effect00.png"; else if (num == 2) name = "effect01.png"; else if (num == 3) name = "effect02.png"; else if (num == 4) name = "interface/text.png"; else name = ""; } /** Returns the channel of the particle created or -1 on error. */ int CParticle::CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration, float mass, float windSensitivity, int sheet) { if (m_main == nullptr) m_main = CRobotMain::GetInstancePointer(); int t = -1; if ( type == PARTIEXPLOT || type == PARTIEXPLOO || type == PARTIMOTOR || type == PARTIBLITZ || type == PARTICRASH || type == PARTIVAPOR || type == PARTIGAS || type == PARTIBASE || type == PARTIFIRE || type == PARTIFIREZ || type == PARTIBLUE || type == PARTIROOT || type == PARTIRECOVER || type == PARTIEJECT || type == PARTISCRAPS || type == PARTIGUN2 || type == PARTIGUN3 || type == PARTIGUN4 || type == PARTIQUEUE || type == PARTIORGANIC1 || type == PARTIORGANIC2 || type == PARTIFLAME || type == PARTIBUBBLE || type == PARTIERROR || type == PARTIWARNING || type == PARTIINFO || type == PARTISPHERE1 || type == PARTISPHERE2 || type == PARTISPHERE4 || type == PARTISPHERE5 || type == PARTISPHERE6 || type == PARTIPLOUF0 || type == PARTITRACK1 || type == PARTITRACK2 || type == PARTITRACK3 || type == PARTITRACK4 || type == PARTITRACK5 || type == PARTITRACK6 || type == PARTITRACK7 || type == PARTITRACK8 || type == PARTITRACK9 || type == PARTITRACK10 || type == PARTITRACK11 || type == PARTITRACK12 || type == PARTILENS1 || type == PARTILENS2 || type == PARTILENS3 || type == PARTILENS4 || type == PARTIGFLAT || type == PARTIDROP || type == PARTIWATER || type == PARTILIMIT1 || type == PARTILIMIT2 || type == PARTILIMIT3 || type == PARTILIMIT4 || type == PARTIEXPLOG1 || type == PARTIEXPLOG2 ) { t = 1; // effect00 } if ( type == PARTIGLINT || type == PARTIGLINTb || type == PARTIGLINTr || type == PARTITOTO || type == PARTISELY || type == PARTISELR || type == PARTIQUARTZ || type == PARTIGUNDEL || type == PARTICONTROL || type == PARTISHOW || type == PARTICHOC || type == PARTIFOG4 || type == PARTIFOG5 || type == PARTIFOG6 || type == PARTIFOG7 ) { t = 2; // effect01 } if ( type == PARTIGUN1 || type == PARTIFLIC || type == PARTISPHERE0 || type == PARTISPHERE3 || type == PARTIFOG0 || type == PARTIFOG1 || type == PARTIFOG2 || type == PARTIFOG3 ) { t = 3; // effect02 } if ( type == PARTISMOKE1 || type == PARTISMOKE2 || type == PARTISMOKE3 || type == PARTIBLOOD || type == PARTIBLOODM || type == PARTIVIRUS1 || type == PARTIVIRUS2 || type == PARTIVIRUS3 || type == PARTIVIRUS4 || type == PARTIVIRUS5 || type == PARTIVIRUS6 || type == PARTIVIRUS7 || type == PARTIVIRUS8 || type == PARTIVIRUS9 || type == PARTIVIRUS10 ) { t = 4; // text (D3DSTATETTw) } if (t >= MAXPARTITYPE) return -1; if (t == -1) return -1; for (int j = 0; j < MAXPARTICULE; j++) { int i = MAXPARTICULE*t+j; if (! m_particle[i].used) { memset(&m_particle[i], 0, sizeof(Particle)); m_particle[i].used = true; m_particle[i].ray = false; m_particle[i].uniqueStamp = m_uniqueStamp++; m_particle[i].sheet = sheet; m_particle[i].mass = mass; m_particle[i].duration = duration; m_particle[i].pos = pos; m_particle[i].goal = pos; m_particle[i].speed = speed; m_particle[i].windSensitivity = windSensitivity; m_particle[i].dim = dim; m_particle[i].zoom = 1.0f; m_particle[i].angle = 0.0f; m_particle[i].intensity = 1.0f; m_particle[i].type = type; m_particle[i].phase = PARPHSTART; m_particle[i].texSup.x = 0.0f; m_particle[i].texSup.y = 0.0f; m_particle[i].texInf.x = 0.0f; m_particle[i].texInf.y = 0.0f; m_particle[i].time = 0.0f; m_particle[i].phaseTime = 0.0f; m_particle[i].testTime = 0.0f; m_particle[i].objLink = 0; m_particle[i].objFather = 0; m_particle[i].trackRank = -1; m_totalInterface[t][sheet] ++; if ( type == PARTIEXPLOT || type == PARTIEXPLOO ) { m_particle[i].angle = Math::Rand()*Math::PI*2.0f; } if ( type == PARTIGUN1 || type == PARTIGUN4 ) { m_particle[i].testTime = 1.0f; // impact immediately } if ( type >= PARTIFOG0 && type <= PARTIFOG9 ) { if (m_fogTotal < MAXPARTIFOG) m_fog[m_fogTotal++] = i; } return i | ((m_particle[i].uniqueStamp&0xffff)<<16); } } return -1; } /** Returns the channel of the particle created or -1 on error */ int CParticle::CreateFrag(Math::Vector pos, Math::Vector speed, EngineTriangle *triangle, ParticleType type, float duration, float mass, float windSensitivity, int sheet) { int t = 0; for (int j = 0; j < MAXPARTICULE; j++) { int i = MAXPARTICULE*t+j; if (!m_particle[i].used) { memset(&m_particle[i], 0, sizeof(Particle)); m_particle[i].used = true; m_particle[i].ray = false; m_particle[i].uniqueStamp = m_uniqueStamp++; m_particle[i].sheet = sheet; m_particle[i].mass = mass; m_particle[i].duration = duration; m_particle[i].pos = pos; m_particle[i].goal = pos; m_particle[i].speed = speed; m_particle[i].windSensitivity = windSensitivity; m_particle[i].zoom = 1.0f; m_particle[i].angle = 0.0f; m_particle[i].intensity = 1.0f; m_particle[i].type = type; m_particle[i].phase = PARPHSTART; m_particle[i].texSup.x = 0.0f; m_particle[i].texSup.y = 0.0f; m_particle[i].texInf.x = 0.0f; m_particle[i].texInf.y = 0.0f; m_particle[i].time = 0.0f; m_particle[i].phaseTime = 0.0f; m_particle[i].testTime = 0.0f; m_particle[i].objLink = 0; m_particle[i].objFather = 0; m_particle[i].trackRank = -1; m_triangle[i] = *triangle; m_totalInterface[t][sheet] ++; Math::Vector p1; p1.x = m_triangle[i].triangle[0].coord.x; p1.y = m_triangle[i].triangle[0].coord.y; p1.z = m_triangle[i].triangle[0].coord.z; Math::Vector p2; p2.x = m_triangle[i].triangle[1].coord.x; p2.y = m_triangle[i].triangle[1].coord.y; p2.z = m_triangle[i].triangle[1].coord.z; Math::Vector p3; p3.x = m_triangle[i].triangle[2].coord.x; p3.y = m_triangle[i].triangle[2].coord.y; p3.z = m_triangle[i].triangle[2].coord.z; float l1 = Math::Distance(p1, p2); float l2 = Math::Distance(p2, p3); float l3 = Math::Distance(p3, p1); float dx = fabs(Math::Min(l1, l2, l3))*0.5f; float dy = fabs(Math::Max(l1, l2, l3))*0.5f; p1 = Math::Vector(-dx, dy, 0.0f); p2 = Math::Vector( dx, dy, 0.0f); p3 = Math::Vector(-dx, -dy, 0.0f); m_triangle[i].triangle[0].coord.x = p1.x; m_triangle[i].triangle[0].coord.y = p1.y; m_triangle[i].triangle[0].coord.z = p1.z; m_triangle[i].triangle[1].coord.x = p2.x; m_triangle[i].triangle[1].coord.y = p2.y; m_triangle[i].triangle[1].coord.z = p2.z; m_triangle[i].triangle[2].coord.x = p3.x; m_triangle[i].triangle[2].coord.y = p3.y; m_triangle[i].triangle[2].coord.z = p3.z; Math::Vector n(0.0f, 0.0f, -1.0f); m_triangle[i].triangle[0].normal.x = n.x; m_triangle[i].triangle[0].normal.y = n.y; m_triangle[i].triangle[0].normal.z = n.z; m_triangle[i].triangle[1].normal.x = n.x; m_triangle[i].triangle[1].normal.y = n.y; m_triangle[i].triangle[1].normal.z = n.z; m_triangle[i].triangle[2].normal.x = n.x; m_triangle[i].triangle[2].normal.y = n.y; m_triangle[i].triangle[2].normal.z = n.z; if (type == PARTIFRAG) m_particle[i].angle = Math::Rand()*Math::PI*2.0f; return i | ((m_particle[i].uniqueStamp&0xffff)<<16); } } return -1; } /** Returns the channel of the particle created or -1 on error */ int CParticle::CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, float duration, float mass, float weight, float windSensitivity, int sheet) { int t = 0; for (int j = 0; j < MAXPARTICULE; j++) { int i = MAXPARTICULE*t+j; if (!m_particle[i].used) { memset(&m_particle[i], 0, sizeof(Particle)); m_particle[i].used = true; m_particle[i].ray = false; m_particle[i].uniqueStamp = m_uniqueStamp++; m_particle[i].sheet = sheet; m_particle[i].mass = mass; m_particle[i].weight = weight; m_particle[i].duration = duration; m_particle[i].pos = pos; m_particle[i].goal = pos; m_particle[i].speed = speed; m_particle[i].windSensitivity = windSensitivity; m_particle[i].zoom = 1.0f; m_particle[i].angle = 0.0f; m_particle[i].intensity = 1.0f; m_particle[i].type = type; m_particle[i].phase = PARPHSTART; m_particle[i].texSup.x = 0.0f; m_particle[i].texSup.y = 0.0f; m_particle[i].texInf.x = 0.0f; m_particle[i].texInf.y = 0.0f; m_particle[i].time = 0.0f; m_particle[i].phaseTime = 0.0f; m_particle[i].testTime = 0.0f; m_particle[i].trackRank = -1; m_totalInterface[t][sheet] ++; return i | ((m_particle[i].uniqueStamp&0xffff)<<16); } } return -1; } /** Returns the channel of the particle created or -1 on error */ int CParticle::CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, float duration, int sheet) { int t = -1; if ( type == PARTIRAY1 || type == PARTIRAY2 || type == PARTIRAY3 || type == PARTIRAY4 ) { t = 3; // effect02 } if (t >= MAXPARTITYPE) return -1; if (t == -1) return -1; for (int j = 0; j < MAXPARTICULE; j++) { int i = MAXPARTICULE*t+j; if (!m_particle[i].used) { memset(&m_particle[i], 0, sizeof(Particle)); m_particle[i].used = true; m_particle[i].ray = true; m_particle[i].uniqueStamp = m_uniqueStamp++; m_particle[i].sheet = sheet; m_particle[i].mass = 0.0f; m_particle[i].duration = duration; m_particle[i].pos = pos; m_particle[i].goal = goal; m_particle[i].speed = Math::Vector(0.0f, 0.0f, 0.0f); m_particle[i].windSensitivity = 0.0f; m_particle[i].dim = dim; m_particle[i].zoom = 1.0f; m_particle[i].angle = 0.0f; m_particle[i].intensity = 1.0f; m_particle[i].type = type; m_particle[i].phase = PARPHSTART; m_particle[i].texSup.x = 0.0f; m_particle[i].texSup.y = 0.0f; m_particle[i].texInf.x = 0.0f; m_particle[i].texInf.y = 0.0f; m_particle[i].time = 0.0f; m_particle[i].phaseTime = 0.0f; m_particle[i].testTime = 0.0f; m_particle[i].objLink = 0; m_particle[i].objFather = 0; m_particle[i].trackRank = -1; m_totalInterface[t][sheet] ++; return i | ((m_particle[i].uniqueStamp&0xffff)<<16); } } return -1; } /** "length" is the length of the tail of drag (in seconds)! */ int CParticle::CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration, float mass, float length, float width) { // Creates the normal particle. int channel = CreateParticle(pos, speed, dim, type, duration, mass, 0.0f, 0); if (channel == -1) return -1; // Seeks a streak free. for (int i = 0; i < MAXTRACK; i++) { if (!m_track[i].used) // free? { int rank = channel; if (!CheckChannel(rank)) return -1; m_particle[rank].trackRank = i; m_track[i].used = true; m_track[i].step = (length/duration) / MAXTRACKLEN; m_track[i].last = 0.0f; m_track[i].intensity = 1.0f; m_track[i].width = width; m_track[i].posUsed = 1; m_track[i].head = 0; m_track[i].pos[0] = pos; break; } } return channel; } void CParticle::CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticleType type) { int max = MAXWHEELTRACE; int i = m_wheelTraceIndex++; if (m_wheelTraceIndex > max) m_wheelTraceIndex = 0; m_wheelTrace[i].type = type; m_wheelTrace[i].pos[0] = p1; // ul m_wheelTrace[i].pos[1] = p2; // dl m_wheelTrace[i].pos[2] = p3; // ur m_wheelTrace[i].pos[3] = p4; // dr m_wheelTrace[i].startTime = m_absTime; if (m_terrain == nullptr) m_terrain = m_main->GetTerrain(); m_terrain->AdjustToFloor(m_wheelTrace[i].pos[0]); m_wheelTrace[i].pos[0].y += 0.2f; // just above the ground m_terrain->AdjustToFloor(m_wheelTrace[i].pos[1]); m_wheelTrace[i].pos[1].y += 0.2f; // just above the ground m_terrain->AdjustToFloor(m_wheelTrace[i].pos[2]); m_wheelTrace[i].pos[2].y += 0.2f; // just above the ground m_terrain->AdjustToFloor(m_wheelTrace[i].pos[3]); m_wheelTrace[i].pos[3].y += 0.2f; // just above the ground if (m_wheelTraceTotal < max) m_wheelTraceTotal++; else m_wheelTraceTotal = max; } /** Adapts the channel so it can be used as an offset in m_particle */ bool CParticle::CheckChannel(int &channel) { int uniqueStamp = (channel>>16)&0xffff; channel &= 0xffff; if (channel < 0) return false; if (channel >= MAXPARTICULE*MAXPARTITYPE) return false; if (!m_particle[channel].used) { GetLogger()->Error("CheckChannel used=false !\n"); return false; } if (m_particle[channel].uniqueStamp != uniqueStamp) { GetLogger()->Error("CheckChannel uniqueStamp !\n"); return false; } return true; } void CParticle::DeleteRank(int rank) { if (m_totalInterface[rank/MAXPARTICULE][m_particle[rank].sheet] > 0) m_totalInterface[rank/MAXPARTICULE][m_particle[rank].sheet]--; int i = m_particle[rank].trackRank; if (i != -1) // drag associated? m_track[i].used = false; // frees the drag m_particle[rank].used = false; } void CParticle::DeleteParticle(ParticleType type) { for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) { if (!m_particle[i].used) continue; if (m_particle[i].type != type) continue; DeleteRank(i); } } void CParticle::DeleteParticle(int channel) { if (!CheckChannel(channel)) return; if (m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet] > 0 ) m_totalInterface[channel/MAXPARTICULE][m_particle[channel].sheet]--; int i = m_particle[channel].trackRank; if (i != -1) // drag associated? m_track[i].used = false; // frees the drag m_particle[channel].used = false; } void CParticle::SetObjectLink(int channel, CObject *object) { if (!CheckChannel(channel)) return; m_particle[channel].objLink = object; } void CParticle::SetObjectFather(int channel, CObject *object) { if (!CheckChannel(channel)) return; m_particle[channel].objFather = object; } void CParticle::SetPosition(int channel, Math::Vector pos) { if (!CheckChannel(channel)) return; m_particle[channel].pos = pos; } void CParticle::SetDimension(int channel, Math::Point dim) { if (!CheckChannel(channel)) return; m_particle[channel].dim = dim; } void CParticle::SetZoom(int channel, float zoom) { if (!CheckChannel(channel)) return; m_particle[channel].zoom = zoom; } void CParticle::SetAngle(int channel, float angle) { if (!CheckChannel(channel)) return; m_particle[channel].angle = angle; } void CParticle::SetIntensity(int channel, float intensity) { if (!CheckChannel(channel)) return; m_particle[channel].intensity = intensity; } void CParticle::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity) { if (!CheckChannel(channel)) return; m_particle[channel].pos = pos; m_particle[channel].dim = dim; m_particle[channel].zoom = zoom; m_particle[channel].angle = angle; m_particle[channel].intensity = intensity; } void CParticle::SetPhase(int channel, ParticlePhase phase, float duration) { if (!CheckChannel(channel)) return; m_particle[channel].phase = phase; m_particle[channel].duration = duration; m_particle[channel].phaseTime = m_particle[channel].time; } bool CParticle::GetPosition(int channel, Math::Vector &pos) { if (!CheckChannel(channel)) return false; pos = m_particle[channel].pos; return true; } void CParticle::SetFrameUpdate(int sheet, bool update) { m_frameUpdate[sheet] = update; } void CParticle::FrameParticle(float rTime) { if (m_main == nullptr) m_main = CRobotMain::GetInstancePointer(); bool pause = (m_engine->GetPause() && !m_main->GetInfoLock()); if (m_terrain == nullptr) m_terrain = m_main->GetTerrain(); if (m_water == nullptr) m_water = m_engine->GetWater(); if (!pause) { m_lastTimeGunDel += rTime; m_absTime += rTime; } Math::Vector wind = m_terrain->GetWind(); Math::Vector eye = m_engine->GetEyePt(); Math::Point ts, ti; Math::Vector pos; for (int i = 0; i < MAXPARTICULE*MAXPARTITYPE; i++) { if (!m_particle[i].used) continue; if (!m_frameUpdate[m_particle[i].sheet]) continue; if (m_particle[i].type != PARTISHOW) { if (pause && m_particle[i].sheet != SH_INTERFACE) continue; } if (m_particle[i].type != PARTIQUARTZ) m_particle[i].pos += m_particle[i].speed*rTime; if (m_particle[i].sheet == SH_WORLD) { float h = rTime*m_particle[i].windSensitivity*Math::Rand()*2.0f; m_particle[i].pos += wind*h; } float progress = (m_particle[i].time-m_particle[i].phaseTime)/m_particle[i].duration; // Manages the particles with mass that bounce. if ( m_particle[i].mass != 0.0f && m_particle[i].type != PARTIQUARTZ ) { m_particle[i].speed.y -= m_particle[i].mass*rTime; float h; if (m_particle[i].sheet == SH_INTERFACE) h = 0.0f; else h = m_terrain->GetFloorLevel(m_particle[i].pos, true); h += m_particle[i].dim.y*0.75f; if (m_particle[i].pos.y < h) // impact with the ground? { if ( m_particle[i].type == PARTIPART && m_particle[i].weight > 3.0f && // heavy enough? m_particle[i].bounce < 3 ) { float amplitude = m_particle[i].weight*0.1f; amplitude *= 1.0f-0.3f*m_particle[i].bounce; if (amplitude > 1.0f) amplitude = 1.0f; if (amplitude > 0.0f) { Play(SOUND_BOUM, m_particle[i].pos, amplitude); } } if (m_particle[i].bounce < 3) { m_particle[i].pos.y = h; m_particle[i].speed.y *= -0.4f; m_particle[i].speed.x *= 0.4f; m_particle[i].speed.z *= 0.4f; m_particle[i].bounce ++; // more impact } else // disappears after 3 bounces? { if ( m_particle[i].pos.y < h-10.0f || m_particle[i].time >= 20.0f ) { DeleteRank(i); continue; } } } } // Manages drag associated. int r = m_particle[i].trackRank; if (r != -1) // drag exists? { if (TrackMove(r, m_particle[i].pos, progress)) { DeleteRank(i); continue; } m_track[r].drawParticle = (progress < 1.0f); } if (m_particle[i].type == PARTITRACK1) // explosion technique? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.375f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK2) // spray blue? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.500f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK3) // spider? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.500f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK4) // insect explosion? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.625f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK5) // derrick? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.750f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK6) // reset in/out? { ts.x = 0.0f; ts.y = 0.0f; ti.x = 0.0f; ti.y = 0.0f; } if ( m_particle[i].type == PARTITRACK7 || // win-1 ? m_particle[i].type == PARTITRACK8 || // win-2 ? m_particle[i].type == PARTITRACK9 || // win-3 ? m_particle[i].type == PARTITRACK10 ) // win-4 ? { m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.25f*(m_particle[i].type-PARTITRACK7); ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTITRACK11) // phazer shot? { CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { if (object->GetType() == OBJECT_MOTHER) object->ExploObject(EXPLO_BOUM, 0.1f); else object->ExploObject(EXPLO_BOUM, 0.0f, GetDecay(object->GetType())); } m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.375f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTITRACK12) // drag reactor? { m_particle[i].zoom = 1.0f; ts.x = 0.375f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIMOTOR) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; m_particle[i].intensity = 1.0f-progress; ts.x = 0.000f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIBLITZ) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; m_particle[i].angle = Math::Rand()*Math::PI*2.0f; ts.x = 0.125f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTICRASH) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.25f) m_particle[i].zoom = progress/0.25f; else m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; ts.x = 0.000f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIVAPOR) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; m_particle[i].zoom = 1.0f+progress*3.0f; ts.x = 0.000f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIGAS) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; ts.x = 0.375f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIBASE) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f+progress*7.0f; m_particle[i].intensity = powf(1.0f-progress, 3.0f); ts.x = 0.375f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if ( m_particle[i].type == PARTIFIRE || m_particle[i].type == PARTIFIREZ ) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].type == PARTIFIRE) m_particle[i].zoom = 1.0f-progress; else m_particle[i].zoom = progress; ts.x = 0.500f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIGUN1) // fireball shot? { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].testTime >= 0.1f) { m_particle[i].testTime = 0.0f; if (m_terrain->GetHeightToFloor(m_particle[i].pos, true) < -2.0f) { m_exploGunCounter++; if (m_exploGunCounter % 2 == 0) { pos = m_particle[i].goal; m_terrain->AdjustToFloor(pos, true); Math::Vector speed; speed.x = 0.0f; speed.z = 0.0f; speed.y = 0.0f; Math::Point dim; dim.x = Math::Rand()*6.0f+6.0f; dim.y = dim.x; float duration = Math::Rand()*1.0f+1.0f; float mass = 0.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); pos.y += 1.0f; int total = static_cast(2.0f*m_engine->GetParticleDensity()); for (int j = 0; j < total; j++) { speed.x = (Math::Rand()-0.5f)*20.0f; speed.z = (Math::Rand()-0.5f)*20.0f; speed.y = Math::Rand()*20.0f; dim.x = 1.0f; dim.y = dim.x; duration = Math::Rand()*1.0f+1.0f; mass = Math::Rand()*10.0f+15.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); } } if (m_exploGunCounter % 4 == 0) Play(SOUND_EXPLOg1, pos, 0.5f); DeleteRank(i); continue; } CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { object->ExploObject(EXPLO_BURN, 0.0f, GetDecay(object->GetType())); m_exploGunCounter++; if (m_exploGunCounter % 2 == 0) { pos = m_particle[i].pos; Math::Vector speed; speed.x = 0.0f; speed.z = 0.0f; speed.y = 0.0f; Math::Point dim; dim.x = Math::Rand()*6.0f+6.0f; dim.y = dim.x; float duration = Math::Rand()*1.0f+1.0f; float mass = 0.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); pos.y += 1.0f; int total = static_cast(2.0f*m_engine->GetParticleDensity()); for (int j = 0; j < total; j++) { speed.x = (Math::Rand()-0.5f)*20.0f; speed.z = (Math::Rand()-0.5f)*20.0f; speed.y = Math::Rand()*20.0f; dim.x = 1.0f; dim.y = dim.x; duration = Math::Rand()*1.0f+1.0f; mass = Math::Rand()*10.0f+15.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); } } if (m_exploGunCounter % 4 == 0) Play(SOUND_EXPLOg1, pos, 0.5f); DeleteRank(i); continue; } } m_particle[i].angle -= rTime*Math::PI*8.0f; m_particle[i].zoom = 1.0f-progress; ts.x = 0.00f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIGUN2) // ant shot? { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].testTime >= 0.2f) { m_particle[i].testTime = 0.0f; CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { if (object->GetShieldRadius() > 0.0f) // protected by shield? { CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); if (m_lastTimeGunDel > 0.2f) { m_lastTimeGunDel = 0.0f; Play(SOUND_GUNDEL, m_particle[i].pos, 1.0f); } DeleteRank(i); continue; } else { if (object->GetType() != OBJECT_HUMAN) Play(SOUND_TOUCH, m_particle[i].pos, 1.0f); object->ExploObject(EXPLO_BOUM, 0.0f); // starts explosion } } } m_particle[i].angle = Math::Rand()*Math::PI*2.0f; m_particle[i].zoom = 1.0f-progress; ts.x = 0.125f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIGUN3) // spider suicides? { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].testTime >= 0.2f) { m_particle[i].testTime = 0.0f; CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { if (object->GetShieldRadius() > 0.0f) { CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); if (m_lastTimeGunDel > 0.2f) { m_lastTimeGunDel = 0.0f; Play(SOUND_GUNDEL, m_particle[i].pos, 1.0f); } DeleteRank(i); continue; } else { object->ExploObject(EXPLO_BURN, 1.0f); // starts explosion } } } ts.x = 0.500f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIGUN4) // orgaball shot? { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].testTime >= 0.1f) { m_particle[i].testTime = 0.0f; if (m_terrain->GetHeightToFloor(m_particle[i].pos, true) < -2.0f) { m_exploGunCounter ++; if (m_exploGunCounter % 2 == 0) { pos = m_particle[i].goal; m_terrain->AdjustToFloor(pos, true); Math::Vector speed; speed.x = 0.0f; speed.z = 0.0f; speed.y = 0.0f; Math::Point dim; dim.x = Math::Rand()*4.0f+2.0f; dim.y = dim.x; float duration = Math::Rand()*0.7f+0.7f; float mass = 0.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); } if (m_exploGunCounter % 4 == 0) { Play(SOUND_EXPLOg2, pos, 0.5f); } DeleteRank(i); continue; } CObject* object = SearchObjectGun(m_particle[i].goal, m_particle[i].pos, m_particle[i].type, m_particle[i].objFather); m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { object->ExploObject(EXPLO_BOUM, 0.0f, GetDecay(object->GetType())); m_exploGunCounter ++; if (m_exploGunCounter % 2 == 0) { pos = m_particle[i].pos; Math::Vector speed; speed.x = 0.0f; speed.z = 0.0f; speed.y = 0.0f; Math::Point dim; dim.x = Math::Rand()*4.0f+2.0f; dim.y = dim.x; float duration = Math::Rand()*0.7f+0.7f; float mass = 0.0f; CreateParticle(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); } if (m_exploGunCounter % 4 == 0) Play(SOUND_EXPLOg2, pos, 0.5f); DeleteRank(i); continue; } } m_particle[i].angle = Math::Rand()*Math::PI*2.0f; m_particle[i].zoom = 1.0f-progress; ts.x = 0.125f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIFLIC) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 0.1f+progress; m_particle[i].intensity = 1.0f-progress; ts.x = 0.00f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISHOW) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.5f) m_particle[i].intensity = progress/0.5f; else m_particle[i].intensity = 2.0f-progress/0.5f; m_particle[i].zoom = 1.0f-progress*0.8f; m_particle[i].angle -= rTime*Math::PI*0.5f; ts.x = 0.50f; ts.y = 0.00f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTICHOC) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 0.1f+progress; m_particle[i].intensity = 1.0f-progress; ts.x = 0.50f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIGFLAT) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 0.1f+progress; m_particle[i].intensity = 1.0f-progress; m_particle[i].angle -= rTime*Math::PI*2.0f; ts.x = 0.00f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTILIMIT1) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f; m_particle[i].intensity = 1.0f; ts.x = 0.000f; ts.y = 0.125f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTILIMIT2) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f; m_particle[i].intensity = 1.0f; ts.x = 0.375f; ts.y = 0.125f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTILIMIT3) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f; m_particle[i].intensity = 1.0f; ts.x = 0.500f; ts.y = 0.125f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIFOG0) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.3f+sinf(progress)*0.15f; m_particle[i].angle += rTime*0.05f; ts.x = 0.25f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG1) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.3f+sinf(progress)*0.15f; m_particle[i].angle -= rTime*0.07f; ts.x = 0.25f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG2) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.6f+sinf(progress)*0.15f; m_particle[i].angle += rTime*0.05f; ts.x = 0.75f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG3) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.6f+sinf(progress)*0.15f; m_particle[i].angle -= rTime*0.07f; ts.x = 0.75f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG4) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; m_particle[i].angle += rTime*0.05f; ts.x = 0.00f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG5) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; m_particle[i].angle -= rTime*0.07f; ts.x = 0.00f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG6) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; m_particle[i].angle += rTime*0.05f; ts.x = 0.50f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIFOG7) { m_particle[i].zoom = progress; m_particle[i].intensity = 0.5f+sinf(progress)*0.2f; m_particle[i].angle -= rTime*0.07f; ts.x = 0.50f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } // Decreases the intensity if the camera // is almost at the same height (fog was eye level). if ( m_particle[i].type >= PARTIFOG0 && m_particle[i].type <= PARTIFOG9 ) { float h = 10.0f; if ( m_particle[i].pos.y >= eye.y && m_particle[i].pos.y < eye.y+h ) { m_particle[i].intensity *= (m_particle[i].pos.y-eye.y)/h; } if ( m_particle[i].pos.y > eye.y-h && m_particle[i].pos.y < eye.y ) { m_particle[i].intensity *= (eye.y-m_particle[i].pos.y)/h; } } if ( m_particle[i].type == PARTIEXPLOT || m_particle[i].type == PARTIEXPLOO ) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress/2.0f; m_particle[i].intensity = 1.0f-progress; if (m_particle[i].type == PARTIEXPLOT) ts.x = 0.750f; else ts.x = 0.875f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIEXPLOG1) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; ts.x = 0.375f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIEXPLOG2) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; ts.x = 0.625f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIFLAME) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress/2.0f; if (progress < 0.5f) { m_particle[i].intensity = progress/0.5f; } else { m_particle[i].intensity = 2.0f-progress/0.5f; } ts.x = 0.750f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIBUBBLE) { if ( progress >= 1.0f || m_particle[i].pos.y >= m_water->GetLevel() ) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress/2.0f; m_particle[i].intensity = 1.0f-progress; ts.x = 0.250f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if ( m_particle[i].type == PARTISMOKE1 || m_particle[i].type == PARTISMOKE2 || m_particle[i].type == PARTISMOKE3 ) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.25f) { m_particle[i].zoom = progress/0.25f; } else { m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; } ts.x = 0.500f+0.125f*(m_particle[i].type-PARTISMOKE1); ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIBLOOD) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; ts.x = 0.750f+(rand()%2)*0.125f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIBLOODM) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; ts.x = 0.875f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if ( m_particle[i].type == PARTIVIRUS1 || m_particle[i].type == PARTIVIRUS2 || m_particle[i].type == PARTIVIRUS3 || m_particle[i].type == PARTIVIRUS4 || m_particle[i].type == PARTIVIRUS5 || m_particle[i].type == PARTIVIRUS6 || m_particle[i].type == PARTIVIRUS7 || m_particle[i].type == PARTIVIRUS8 || m_particle[i].type == PARTIVIRUS9 || m_particle[i].type == PARTIVIRUS10 ) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.25f) m_particle[i].zoom = progress/0.25f; else m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; m_particle[i].angle += rTime*Math::PI*1.0f; if (m_particle[i].type == PARTIVIRUS1) // A ? { ts.x = 0.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 10.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS2) // C ? { ts.x = 19.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 28.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS3) // E ? { ts.x = 36.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 45.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS4) // N ? { ts.x = 110.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 120.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS5) // R ? { ts.x = 148.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 158.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS6) // T ? { ts.x = 166.0f/256.0f; ts.y = 19.0f/256.0f; ti.x = 175.0f/256.0f; ti.y = 30.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS7) // 0 ? { ts.x = 90.0f/256.0f; ts.y = 2.0f/256.0f; ti.x = 98.0f/256.0f; ti.y = 13.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS8) // 2 ? { ts.x = 103.0f/256.0f; ts.y = 2.0f/256.0f; ti.x = 111.0f/256.0f; ti.y = 13.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS9) // 5 ? { ts.x = 125.0f/256.0f; ts.y = 2.0f/256.0f; ti.x = 132.0f/256.0f; ti.y = 13.0f/256.0f; } if (m_particle[i].type == PARTIVIRUS10) // 9 ? { ts.x = 153.0f/256.0f; ts.y = 2.0f/256.0f; ti.x = 161.0f/256.0f; ti.y = 13.0f/256.0f; } } if (m_particle[i].type == PARTIBLUE) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; ts.x = 0.625f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIROOT) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.25f) { m_particle[i].zoom = progress/0.25f; } else { m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; } ts.x = 0.000f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIRECOVER) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.25f) { m_particle[i].zoom = progress/0.25f; } else { m_particle[i].intensity = 1.0f-(progress-0.25f)/0.75f; } ts.x = 0.875f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIEJECT) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f+powf(progress, 2.0f)*5.0f; m_particle[i].intensity = 1.0f-progress; ts.x = 0.625f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTISCRAPS) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; ts.x = 0.625f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIFRAG) { m_particle[i].angle += rTime*Math::PI*0.5f; ts.x = 0.0f; ts.y = 0.0f; ti.x = 0.0f; ti.y = 0.0f; } if (m_particle[i].type == PARTIPART) { ts.x = 0.0f; ts.y = 0.0f; ti.x = 0.0f; ti.y = 0.0f; } if (m_particle[i].type == PARTIQUEUE) { if (m_particle[i].testTime >= 0.05f) { m_particle[i].testTime = 0.0f; pos = m_particle[i].pos; Math::Vector speed = Math::Vector(0.0f, 0.0f, 0.0f); Math::Point dim; dim.x = 1.0f*(Math::Rand()*0.8f+0.6f); dim.y = dim.x; CreateParticle(pos, speed, dim, PARTIGAS, 0.5f); } ts.x = 0.375f; ts.y = 0.750f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIORGANIC1) { if (progress >= 1.0f) { DeleteRank(i); pos = m_particle[i].pos; Math::Point dim; dim.x = m_particle[i].dim.x/4.0f; dim.y = dim.x; float duration = m_particle[i].duration; float mass = m_particle[i].mass; int total = static_cast((10.0f*m_engine->GetParticleDensity())); for (int j = 0; j < total; j++) { Math::Vector speed; speed.x = (Math::Rand()-0.5f)*20.0f; speed.y = (Math::Rand()-0.5f)*20.0f; speed.z = (Math::Rand()-0.5f)*20.0f; CreateParticle(pos, speed, dim, PARTIORGANIC2, duration, mass); } total = static_cast((5.0f*m_engine->GetParticleDensity())); for (int j = 0; j < total; j++) { Math::Vector speed; speed.x = (Math::Rand()-0.5f)*20.0f; speed.y = (Math::Rand()-0.5f)*20.0f; speed.z = (Math::Rand()-0.5f)*20.0f; duration *= Math::Rand()+0.8f; CreateTrack(pos, speed, dim, PARTITRACK4, duration, mass, duration*0.2f, dim.x*2.0f); } continue; } m_particle[i].zoom = (m_particle[i].time-m_particle[i].duration); ts.x = 0.125f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIORGANIC2) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); ts.x = 0.125f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIGLINT) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress > 0.5f) m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; m_particle[i].angle = m_particle[i].time*Math::PI; ts.x = 0.75f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIGLINTb) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress > 0.5f) m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; m_particle[i].angle = m_particle[i].time*Math::PI; ts.x = 0.75f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIGLINTr) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress > 0.5f) m_particle[i].zoom = 1.0f-(progress-0.5f)*2.0f; m_particle[i].angle = m_particle[i].time*Math::PI; ts.x = 0.75f; ts.y = 0.00f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if ( m_particle[i].type >= PARTILENS1 && m_particle[i].type <= PARTILENS4 ) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.5f) m_particle[i].zoom = progress*2.0f; else m_particle[i].intensity = 1.0f-(progress-0.5f)*2.0f; ts.x = 0.25f*(m_particle[i].type-PARTILENS1); ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTICONTROL) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.3f) { m_particle[i].zoom = progress/0.3f; } else { m_particle[i].zoom = 1.0f; m_particle[i].intensity = 1.0f-(progress-0.3f)/0.7f; } ts.x = 0.00f; ts.y = 0.00f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIGUNDEL) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress > 0.5f) m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration/2.0f); m_particle[i].angle = m_particle[i].time*Math::PI; ts.x = 0.75f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIQUARTZ) { if (progress >= 1.0f) { m_particle[i].time = 0.0f; m_particle[i].duration = 0.5f+Math::Rand()*2.0f; m_particle[i].pos.x = m_particle[i].speed.x + (Math::Rand()-0.5f)*m_particle[i].mass; m_particle[i].pos.y = m_particle[i].speed.y + (Math::Rand()-0.5f)*m_particle[i].mass; m_particle[i].pos.z = m_particle[i].speed.z + (Math::Rand()-0.5f)*m_particle[i].mass; m_particle[i].dim.x = 0.5f+Math::Rand()*1.5f; m_particle[i].dim.y = m_particle[i].dim.x; progress = 0.0f; } if (progress < 0.2f) { m_particle[i].zoom = progress/0.2f; m_particle[i].intensity = 1.0f; } else { m_particle[i].zoom = 1.0f; m_particle[i].intensity = 1.0f-(progress-0.2f)/0.8f; } ts.x = 0.25f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTITOTO) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; if (progress < 0.15f) m_particle[i].intensity = progress/0.15f; else m_particle[i].intensity = 1.0f-(progress-0.15f)/0.85f; m_particle[i].intensity *= 0.5f; ts.x = 0.25f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIERROR) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress*1.0f; m_particle[i].intensity = 1.0f-progress; ts.x = 0.500f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIWARNING) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress*1.0f; m_particle[i].intensity = 1.0f-progress; ts.x = 0.875f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIINFO) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress*1.0f; m_particle[i].intensity = 1.0f-progress; ts.x = 0.750f; ts.y = 0.875f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTISELY) { ts.x = 0.75f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISELR) { ts.x = 0.75f; ts.y = 0.00f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISPHERE0) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress*m_particle[i].dim.x; if (progress < 0.65f) m_particle[i].intensity = progress/0.65f; else m_particle[i].intensity = 1.0f-(progress-0.65f)/0.35f; m_particle[i].intensity *= 0.5f; ts.x = 0.50f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISPHERE1) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.30f) m_particle[i].intensity = progress/0.30f; else m_particle[i].intensity = 1.0f-(progress-0.30f)/0.70f; m_particle[i].zoom = progress*m_particle[i].dim.x; m_particle[i].angle = m_particle[i].time*Math::PI*2.0f; ts.x = 0.000f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTISPHERE2) { if (progress >= 1.0f) { DeleteRank(i); continue; } if (progress < 0.20f) m_particle[i].intensity = 1.0f; else m_particle[i].intensity = 1.0f-(progress-0.20f)/0.80f; m_particle[i].zoom = progress*m_particle[i].dim.x; m_particle[i].angle = m_particle[i].time*Math::PI*2.0f; ts.x = 0.125f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTISPHERE3) { if (m_particle[i].phase == PARPHEND && progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].phase == PARPHSTART) { m_particle[i].intensity = progress; if (m_particle[i].intensity > 1.0f) m_particle[i].intensity = 1.0f; } if (m_particle[i].phase == PARPHEND) m_particle[i].intensity = 1.0f-progress; m_particle[i].zoom = m_particle[i].dim.x; m_particle[i].angle = m_particle[i].time*Math::PI*0.2f; ts.x = 0.25f; ts.y = 0.75f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISPHERE4) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress*m_particle[i].dim.x; if (progress < 0.65 ) m_particle[i].intensity = progress/0.65f; else m_particle[i].intensity = 1.0f-(progress-0.65f)/0.35f; m_particle[i].intensity *= 0.5f; ts.x = 0.125f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTISPHERE5) { m_particle[i].intensity = 0.7f+sinf(progress)*0.3f; m_particle[i].zoom = m_particle[i].dim.x*(1.0f+sinf(progress*0.7f)*0.01f); m_particle[i].angle = m_particle[i].time*Math::PI*0.2f; ts.x = 0.25f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTISPHERE6) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = (1.0f-progress)*m_particle[i].dim.x; m_particle[i].intensity = progress*0.5f; ts.x = 0.125f; ts.y = 0.000f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIPLOUF0) { if (progress >= 1.0f) { DeleteRank(i); continue; } m_particle[i].zoom = progress; m_particle[i].intensity = 1.0f-progress; ts.x = 0.50f; ts.y = 0.50f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIDROP) { if (progress >= 1.0f || m_particle[i].pos.y < m_water->GetLevel()) { DeleteRank(i); continue; } m_particle[i].zoom = 1.0f-progress; m_particle[i].intensity = 1.0f-progress; ts.x = 0.750f; ts.y = 0.500f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIWATER) { if (progress >= 1.0f || m_particle[i].pos.y < m_water->GetLevel()) { DeleteRank(i); continue; } m_particle[i].intensity = 1.0f-progress; ts.x = 0.125f; ts.y = 0.125f; ti.x = ts.x+0.125f; ti.y = ts.y+0.125f; } if (m_particle[i].type == PARTIRAY1) // rayon tour ? { if (progress >= 1.0f) { DeleteRank(i); continue; } if (m_particle[i].testTime >= 0.2f) { m_particle[i].testTime = 0.0f; CObject* object = SearchObjectRay(m_particle[i].pos, m_particle[i].goal, m_particle[i].type, m_particle[i].objFather); if (object != nullptr) object->ExploObject(EXPLO_BOUM, 0.0f); } ts.x = 0.00f; ts.y = 0.00f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } if (m_particle[i].type == PARTIRAY2 || m_particle[i].type == PARTIRAY3) { if (progress >= 1.0f) { DeleteRank(i); continue; } ts.x = 0.00f; ts.y = 0.25f; ti.x = ts.x+0.25f; ti.y = ts.y+0.25f; } float dp = (1.0f/256.0f)/2.0f; m_particle[i].texSup.x = ts.x+dp; m_particle[i].texSup.y = ts.y+dp; m_particle[i].texInf.x = ti.x-dp; m_particle[i].texInf.y = ti.y-dp; m_particle[i].time += rTime; m_particle[i].testTime += rTime; } } bool CParticle::TrackMove(int i, Math::Vector pos, float progress) { if (i < 0 || i >= MAXTRACK) return true; if (! m_track[i].used) return true; if (progress < 1.0f) // particle exists? { int h = m_track[i].head; Math::Vector last; if ( m_track[i].posUsed == 1 || m_track[i].last+m_track[i].step <= progress ) { m_track[i].last = progress; last = m_track[i].pos[h]; h ++; if (h == MAXTRACKLEN) h = 0; if (m_track[i].posUsed < MAXTRACKLEN) m_track[i].posUsed++; } else { int hh = h-1; if (hh < 0) hh = MAXTRACKLEN-1; last = m_track[i].pos[hh]; } m_track[i].pos[h] = pos; m_track[i].len[h] = Math::Distance(pos, last); m_track[i].head = h; m_track[i].intensity = 1.0f-progress; } else // slow death of the track ? { m_track[i].intensity = 0.0f; } return (m_track[i].intensity <= 0.0f); } void CParticle::TrackDraw(int i, ParticleType type) { // Calculates the total length memorized. float lTotal = 0.0f; int h = m_track[i].head; for (int counter = 0; counter < m_track[i].posUsed-1; counter++) { lTotal += m_track[i].len[h]; h--; if (h < 0) h = MAXTRACKLEN-1; } Math::Matrix mat; mat.LoadIdentity(); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Point texInf, texSup; if (type == PARTITRACK1) // explosion technique? { texInf.x = 64.5f/256.0f; texInf.y = 21.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 22.0f/256.0f; // orange } if (type == PARTITRACK2) // blue spray? { texInf.x = 64.5f/256.0f; texInf.y = 13.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 14.0f/256.0f; // blue } if (type == PARTITRACK3) // spider? { texInf.x = 64.5f/256.0f; texInf.y = 5.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 6.0f/256.0f; // brown } if (type == PARTITRACK4) // insect explosion? { texInf.x = 64.5f/256.0f; texInf.y = 9.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 10.0f/256.0f; // dark green } if (type == PARTITRACK5) // derrick? { texInf.x = 64.5f/256.0f; texInf.y = 29.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 30.0f/256.0f; // dark brown } if (type == PARTITRACK6) // reset in/out? { texInf.x = 64.5f/256.0f; texInf.y = 17.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 18.0f/256.0f; // cyan } if (type == PARTITRACK7) // win-1? { texInf.x = 64.5f/256.0f; texInf.y = 41.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 42.0f/256.0f; // orange } if (type == PARTITRACK8) // win-2? { texInf.x = 64.5f/256.0f; texInf.y = 45.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 46.0f/256.0f; // yellow } if (type == PARTITRACK9) // win-3? { texInf.x = 64.5f/256.0f; texInf.y = 49.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 50.0f/256.0f; // red } if (type == PARTITRACK10) // win-4? { texInf.x = 64.5f/256.0f; texInf.y = 53.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 54.0f/256.0f; // violet } if (type == PARTITRACK11) // phazer shot? { texInf.x = 64.5f/256.0f; texInf.y = 21.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 22.0f/256.0f; // orange } if (type == PARTITRACK12) // drag reactor? { texInf.x = 64.5f/256.0f; texInf.y = 21.0f/256.0f; texSup.x = 95.5f/256.0f; texSup.y = 22.0f/256.0f; // orange } h = m_track[i].head; Math::Vector p1 = m_track[i].pos[h]; float f1 = m_track[i].intensity; Math::Vector eye = m_engine->GetEyePt(); float a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); Vertex vertex[4]; Math::Vector corner[4]; for (int counter = 0; counter < m_track[i].posUsed-1; counter++) { float f2 = f1-(m_track[i].len[h]/lTotal); if (f2 < 0.0f) f2 = 0.0f; h --; if (h < 0) h = MAXTRACKLEN-1; Math::Vector p2 = m_track[i].pos[h]; Math::Vector n = Normalize(p1-eye); Math::Vector p; Math::Point rot; p = p1; p.x += f1*m_track[i].width; rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); corner[0].x = rot.x; corner[0].y = p1.y; corner[0].z = rot.y; rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); corner[1].x = rot.x; corner[1].y = p1.y; corner[1].z = rot.y; p = p2; p.x += f2*m_track[i].width; rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a+Math::PI/2.0f, Math::Point(p.x, p.z)); corner[2].x = rot.x; corner[2].y = p2.y; corner[2].z = rot.y; rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a-Math::PI/2.0f, Math::Point(p.x, p.z)); corner[3].x = rot.x; corner[3].y = p2.y; corner[3].z = rot.y; if (p2.y < p1.y) { vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y)); } else { vertex[0] = Vertex(corner[0], n, Math::Point(texSup.x, texSup.y)); vertex[1] = Vertex(corner[1], n, Math::Point(texInf.x, texSup.y)); vertex[2] = Vertex(corner[2], n, Math::Point(texSup.x, texInf.y)); vertex[3] = Vertex(corner[3], n, Math::Point(texInf.x, texInf.y)); } m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); if (f2 < 0.0f) break; f1 = f2; p1 = p2; } } void CParticle::DrawParticleTriangle(int i) { if (m_particle[i].zoom == 0.0f) return; Math::Vector eye = m_engine->GetEyePt(); Math::Vector pos = m_particle[i].pos; CObject* object = m_particle[i].objLink; if (object != nullptr) pos += object->GetPosition(0); Math::Vector angle; angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); angle.z = m_particle[i].angle; Math::Matrix mat; Math::LoadRotationXZYMatrix(mat, angle); mat.Set(1, 4, pos.x); mat.Set(2, 4, pos.y); mat.Set(3, 4, pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, m_triangle[i].triangle, 3); m_engine->AddStatisticTriangle(1); } void CParticle::DrawParticleNorm(int i) { float zoom = m_particle[i].zoom; if (zoom == 0.0f) return; if (m_particle[i].intensity == 0.0f) return; Math::Vector corner[4]; Vertex vertex[4]; if (m_particle[i].sheet == SH_INTERFACE) { Math::Vector pos = m_particle[i].pos; Math::Vector n(0.0f, 0.0f, -1.0f); Math::Point dim; dim.x = m_particle[i].dim.x * zoom; dim.y = m_particle[i].dim.y * zoom; corner[0].x = pos.x+dim.x; corner[0].y = pos.y+dim.y; corner[0].z = 0.0f; corner[1].x = pos.x-dim.x; corner[1].y = pos.y+dim.y; corner[1].z = 0.0f; corner[2].x = pos.x+dim.x; corner[2].y = pos.y-dim.y; corner[2].z = 0.0f; corner[3].x = pos.x-dim.x; corner[3].y = pos.y-dim.y; corner[3].z = 0.0f; vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } else { Math::Vector eye = m_engine->GetEyePt(); Math::Vector pos = m_particle[i].pos; CObject* object = m_particle[i].objLink; if (object != nullptr) pos += object->GetPosition(0); Math::Vector angle; angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); angle.z = m_particle[i].angle; Math::Matrix mat; Math::LoadRotationXZYMatrix(mat, angle); mat.Set(1, 4, pos.x); mat.Set(2, 4, pos.y); mat.Set(3, 4, pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Vector n(0.0f, 0.0f, -1.0f); Math::Point dim; dim.x = m_particle[i].dim.x * zoom; dim.y = m_particle[i].dim.y * zoom; corner[0].x = dim.x; corner[0].y = dim.y; corner[0].z = 0.0f; corner[1].x = -dim.x; corner[1].y = dim.y; corner[1].z = 0.0f; corner[2].x = dim.x; corner[2].y = -dim.y; corner[2].z = 0.0f; corner[3].x = -dim.x; corner[3].y = -dim.y; corner[3].z = 0.0f; vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } } void CParticle::DrawParticleFlat(int i) { if (m_particle[i].zoom == 0.0f) return; if (m_particle[i].intensity == 0.0f) return; Math::Vector pos = m_particle[i].pos; CObject* object = m_particle[i].objLink; if (object != nullptr) pos += object->GetPosition(0); Math::Vector angle; angle.x = Math::PI/2.0f; angle.y = 0.0f; angle.z = m_particle[i].angle; if (m_engine->GetRankView() == 1) // underwater? pos.y -= 1.0f; Math::Vector eye = m_engine->GetEyePt(); if (pos.y > eye.y) // seen from below? angle.x = -Math::PI/2.0f; Math::Matrix mat; Math::LoadRotationXZYMatrix(mat, angle); mat.Set(1, 4, pos.x); mat.Set(2, 4, pos.y); mat.Set(3, 4, pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Vector n(0.0f, 0.0f, -1.0f); Math::Point dim; dim.x = m_particle[i].dim.x * m_particle[i].zoom; dim.y = m_particle[i].dim.y * m_particle[i].zoom; Math::Vector corner[4]; corner[0].x = dim.x; corner[0].y = dim.y; corner[0].z = 0.0f; corner[1].x = -dim.x; corner[1].y = dim.y; corner[1].z = 0.0f; corner[2].x = dim.x; corner[2].y = -dim.y; corner[2].z = 0.0f; corner[3].x = -dim.x; corner[3].y = -dim.y; corner[3].z = 0.0f; Vertex vertex[4]; vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } void CParticle::DrawParticleFog(int i) { if (!m_engine->GetFog()) return; if (m_particle[i].intensity == 0.0f) return; Math::Vector pos = m_particle[i].pos; Math::Point dim; dim.x = m_particle[i].dim.x; dim.y = m_particle[i].dim.y; Math::Point zoom; if ( m_particle[i].type == PARTIFOG0 || m_particle[i].type == PARTIFOG2 || m_particle[i].type == PARTIFOG4 || m_particle[i].type == PARTIFOG6 ) { zoom.x = 1.0f+sinf(m_particle[i].zoom*2.0f)/6.0f; zoom.y = 1.0f+cosf(m_particle[i].zoom*2.7f)/6.0f; } if ( m_particle[i].type == PARTIFOG1 || m_particle[i].type == PARTIFOG3 || m_particle[i].type == PARTIFOG5 || m_particle[i].type == PARTIFOG7 ) { zoom.x = 1.0f+sinf(m_particle[i].zoom*3.0f)/6.0f; zoom.y = 1.0f+cosf(m_particle[i].zoom*3.7f)/6.0f; } dim.x *= zoom.x; dim.y *= zoom.y; CObject* object = m_particle[i].objLink; if (object != nullptr) pos += object->GetPosition(0); Math::Vector angle; angle.x = Math::PI/2.0f; angle.y = 0.0f; angle.z = m_particle[i].angle; if (m_engine->GetRankView() == 1) // underwater? pos.y -= 1.0f; Math::Vector eye = m_engine->GetEyePt(); if (pos.y > eye.y) // seen from below? angle.x = -Math::PI/2.0f; Math::Matrix mat; Math::LoadRotationXZYMatrix(mat, angle); mat.Set(1, 4, pos.x); mat.Set(2, 4, pos.y); mat.Set(3, 4, pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Vector n(0.0f, 0.0f, -1.0f); Math::Vector corner[4]; corner[0].x = dim.x; corner[0].y = dim.y; corner[0].z = 0.0f; corner[1].x = -dim.x; corner[1].y = dim.y; corner[1].z = 0.0f; corner[2].x = dim.x; corner[2].y = -dim.y; corner[2].z = 0.0f; corner[3].x = -dim.x; corner[3].y = -dim.y; corner[3].z = 0.0f; Vertex vertex[4]; vertex[0] = Vertex(corner[1], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(m_particle[i].texSup.x, m_particle[i].texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(m_particle[i].texInf.x, m_particle[i].texInf.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } void CParticle::DrawParticleRay(int i) { if (m_particle[i].zoom == 0.0f) return; if (m_particle[i].intensity == 0.0f) return; Math::Vector eye = m_engine->GetEyePt(); Math::Vector pos = m_particle[i].pos; Math::Vector goal = m_particle[i].goal; CObject* object = m_particle[i].objLink; if (object != nullptr) pos += object->GetPosition(0); float a = Math::RotateAngle(Math::Point(pos.x,pos.z), Math::Point(goal.x,goal.z), Math::Point(eye.x,eye.z)); bool left = (a < Math::PI); Math::Vector proj = Math::Projection(pos, goal, eye); Math::Vector angle; angle.x = -Math::RotateAngle(Math::DistanceProjected(proj, eye), proj.y-eye.y); angle.y = Math::RotateAngle(pos.z-goal.z, pos.x-goal.x)+Math::PI/2.0f; angle.z = -Math::RotateAngle(Math::DistanceProjected(pos, goal), pos.y-goal.y); if (left) angle.x = -angle.x; Math::Matrix mat; Math::LoadRotationZXYMatrix(mat, angle); mat.Set(1, 4, pos.x); mat.Set(2, 4, pos.y); mat.Set(3, 4, pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Vector n(0.0f, 0.0f, left ? 1.0f : -1.0f); Math::Point dim; dim.x = m_particle[i].dim.x * m_particle[i].zoom; dim.y = m_particle[i].dim.y * m_particle[i].zoom; if (left) dim.y = -dim.y; float len = Math::Distance(pos, goal); float adv = 0.0f; int step = static_cast((len/(dim.x*2.0f))+1); float vario1, vario2; if (step == 1) { vario1 = 1.0f; vario2 = 1.0f; } else { vario1 = 0.0f; vario2 = 2.0f; } int first, last; if (m_particle[i].type == PARTIRAY2) { first = 0; last = step; vario1 = 0.0f; vario2 = 0.0f; } else if (m_particle[i].type == PARTIRAY3) { if (m_particle[i].time < m_particle[i].duration*0.40f) { float prop = m_particle[i].time / (m_particle[i].duration*0.40f); first = 0; last = static_cast(prop*step); } else if (m_particle[i].time < m_particle[i].duration*0.60f) { first = 0; last = step; } else { float prop = (m_particle[i].time-m_particle[i].duration*0.60f) / (m_particle[i].duration*0.40f); first = static_cast(prop*step); last = step; } } else { if (m_particle[i].time < m_particle[i].duration*0.50f) { float prop = m_particle[i].time / (m_particle[i].duration*0.50f); first = 0; last = static_cast(prop*step); } else if (m_particle[i].time < m_particle[i].duration*0.75f) { first = 0; last = step; } else { float prop = (m_particle[i].time-m_particle[i].duration*0.75f) / (m_particle[i].duration*0.25f); first = static_cast(prop*step); last = step; } } Math::Vector corner[4]; corner[0].x = adv; corner[2].x = adv; corner[0].y = dim.y; corner[2].y = -dim.y; corner[0].z = (Math::Rand()-0.5f)*vario1; corner[1].z = (Math::Rand()-0.5f)*vario1; corner[2].z = (Math::Rand()-0.5f)*vario1; corner[3].z = (Math::Rand()-0.5f)*vario1; Vertex vertex[4]; for (int rank = 0; rank < step; rank++) { corner[1].x = corner[0].x; corner[3].x = corner[2].x; corner[0].x = adv+dim.x*2.0f+(Math::Rand()-0.5f)*vario2; corner[2].x = adv+dim.x*2.0f+(Math::Rand()-0.5f)*vario2; corner[1].y = corner[0].y; corner[3].y = corner[2].y; corner[0].y = dim.y+(Math::Rand()-0.5f)*vario2; corner[2].y = -dim.y+(Math::Rand()-0.5f)*vario2; if (rank >= first && rank <= last) { Math::Point texInf = m_particle[i].texInf; Math::Point texSup = m_particle[i].texSup; int r = rand() % 16; texInf.x += 0.25f*(r/4); texSup.x += 0.25f*(r/4); if (r % 2 < 1 && adv > 0.0f && m_particle[i].type != PARTIRAY1) Math::Swap(texInf.x, texSup.x); if (r % 4 < 2) Math::Swap(texInf.y, texSup.y); vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y)); vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y)); vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y)); vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } adv += dim.x*2.0f; } } void CParticle::DrawParticleSphere(int i) { float zoom = m_particle[i].zoom; if (zoom == 0.0f) return; m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK | ENG_RSTATE_2FACE | ENG_RSTATE_WRAP, IntensityToColor(m_particle[i].intensity)); Math::Matrix mat; mat.LoadIdentity(); mat.Set(1, 1, zoom); mat.Set(2, 2, zoom); mat.Set(3, 3, zoom); mat.Set(1, 4, m_particle[i].pos.x); mat.Set(2, 4, m_particle[i].pos.y); mat.Set(3, 4, m_particle[i].pos.z); if (m_particle[i].angle != 0.0f) { Math::Vector angle; angle.x = m_particle[i].angle*0.4f; angle.y = m_particle[i].angle*1.0f; angle.z = m_particle[i].angle*0.7f; Math::Matrix rot; Math::LoadRotationZXYMatrix(rot, angle); mat = Math::MultiplyMatrices(mat, rot); } m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Point ts, ti; ts.x = m_particle[i].texSup.x; ts.y = m_particle[i].texSup.y; ti.x = m_particle[i].texInf.x; ti.y = m_particle[i].texInf.y; int numRings, numSegments; // Choose a tesselation level. if ( m_particle[i].type == PARTISPHERE3 || m_particle[i].type == PARTISPHERE5 ) { numRings = 16; numSegments = 16; } else { numRings = 8; numSegments = 10; } // Establish constants used in sphere generation. float deltaRingAngle = Math::PI/numRings; float deltaSegAngle = 2.0f*Math::PI/numSegments; Vertex vertex[2*16*(16+1)]; // Generate the group of rings for the sphere. int j = 0; for (int ring = 0; ring < numRings; ring++) { float r0 = sinf((ring+0)*deltaRingAngle); float r1 = sinf((ring+1)*deltaRingAngle); Math::Vector v0, v1; v0.y = cosf((ring+0)*deltaRingAngle); v1.y = cosf((ring+1)*deltaRingAngle); float tv0 = (ring+0)/static_cast(numRings); float tv1 = (ring+1)/static_cast(numRings); tv0 = ts.y+(ti.y-ts.y)*tv0; tv1 = ts.y+(ti.y-ts.y)*tv1; // Generate the group of segments for the current ring. for (int seg = 0; seg < numSegments+1; seg++) { v0.x = r0*sinf(seg*deltaSegAngle); v0.z = r0*cosf(seg*deltaSegAngle); v1.x = r1*sinf(seg*deltaSegAngle); v1.z = r1*cosf(seg*deltaSegAngle); // Add two vertices to the strip which makes up the sphere. float tu0 = (static_cast(seg))/numSegments; tu0 = ts.x+(ti.x-ts.x)*tu0; float tu1 = tu0; vertex[j++] = Vertex(v0, v0, Math::Point(tu0, tv0)); vertex[j++] = Vertex(v1, v1, Math::Point(tu1, tv1)); } } m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, j); m_engine->AddStatisticTriangle(j); m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK, IntensityToColor(m_particle[i].intensity)); } //! Returns the height depending on the progress float ProgressCylinder(float progress) { if (progress < 0.5f) return 1.0f - (powf(1.0f-progress*2.0f, 2.0f)); else return 1.0f - (powf(progress*2.0f-1.0f, 2.0f)); } void CParticle::DrawParticleCylinder(int i) { float progress = m_particle[i].zoom; float zoom = m_particle[i].dim.x; float diam = m_particle[i].dim.y; if (progress >= 1.0f || zoom == 0.0f) return; m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK | ENG_RSTATE_2FACE | ENG_RSTATE_WRAP, IntensityToColor(m_particle[i].intensity)); Math::Matrix mat; mat.LoadIdentity(); mat.Set(1, 1, zoom); mat.Set(2, 2, zoom); mat.Set(3, 3, zoom); mat.Set(1, 4, m_particle[i].pos.x); mat.Set(2, 4, m_particle[i].pos.y); mat.Set(3, 4, m_particle[i].pos.z); m_device->SetTransform(TRANSFORM_WORLD, mat); Math::Point ts, ti; ts.x = m_particle[i].texSup.x; ts.y = m_particle[i].texSup.y; ti.x = m_particle[i].texInf.x; ti.y = m_particle[i].texInf.y; int numRings = 5; int numSegments = 10; float deltaSegAngle = 2.0f*Math::PI/numSegments; float h[6] = { 0.0f }; float d[6] = { 0.0f }; if (m_particle[i].type == PARTIPLOUF0) { float p1 = progress; // front float p2 = powf(progress, 5.0f); // back for (int ring = 0; ring <= numRings; ring++) { float pp = p2+(p1-p2)*(static_cast(ring)/numRings); d[ring] = diam/zoom+pp*2.0f; h[ring] = ProgressCylinder(pp); } } Vertex vertex[2*5*(10+1)]; int j = 0; for (int ring = 0; ring < numRings; ring++) { Math::Vector v0, v1; float r0 = 1.0f*d[ring+0]; // radius at the base float r1 = 1.0f*d[ring+1]; // radius at the top v0.y = 1.0f*h[ring+0]; // bottom v1.y = 1.0f*h[ring+1]; // top float tv0 = 1.0f-(ring+0)*(1.0f/numRings); float tv1 = 1.0f-(ring+1)*(1.0f/numRings); tv0 = ts.y+(ti.y-ts.y)*tv0; tv1 = ts.y+(ti.y-ts.y)*tv1; for (int seg = 0; seg < numSegments+1; seg++) { v0.x = r0*sinf(seg*deltaSegAngle); v0.z = r0*cosf(seg*deltaSegAngle); v1.x = r1*sinf(seg*deltaSegAngle); v1.z = r1*cosf(seg*deltaSegAngle); float tu0 = (seg % 2) ? 0.0f : 1.0f; tu0 = ts.x+(ti.x-ts.x)*tu0; float tu1 = tu0; vertex[j++] = Vertex(v0, v0, Math::Point(tu0, tv0)); vertex[j++] = Vertex(v1, v1, Math::Point(tu1, tv1)); } } m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, j); m_engine->AddStatisticTriangle(j); m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK, IntensityToColor(m_particle[i].intensity)); } void CParticle::DrawParticleWheel(int i) { float dist = Math::DistanceProjected(m_engine->GetEyePt(), m_wheelTrace[i].pos[0]); if (dist > 300.0f) return; Math::Vector pos[4]; pos[0] = m_wheelTrace[i].pos[0]; pos[1] = m_wheelTrace[i].pos[1]; pos[2] = m_wheelTrace[i].pos[2]; pos[3] = m_wheelTrace[i].pos[3]; Math::Point ts; if (m_wheelTrace[i].type == PARTITRACE0) // white ground track? { ts.x = 8.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE1) // black ground track? { ts.x = 0.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE2) // gray ground track? { ts.x = 0.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE3) // light gray ground track? { ts.x = 8.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE4) // red ground track? { ts.x = 32.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE5) // pink ground track? { ts.x = 40.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE6) // violet ground track? { ts.x = 32.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE7) // orange ground track? { ts.x = 40.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE8) // yellow ground track? { ts.x = 16.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE9) // beige ground track? { ts.x = 24.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE10) // brown ground track? { ts.x = 16.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE11) // skin ground track? { ts.x = 24.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE12) // green ground track? { ts.x = 48.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE13) // light green ground track? { ts.x = 56.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE14) // blue ground track? { ts.x = 48.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE15) // light blue ground track? { ts.x = 56.0f/256.0f; ts.y = 232.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE16) // black arrow ground track? { ts.x = 160.0f/256.0f; ts.y = 224.0f/256.0f; } else if (m_wheelTrace[i].type == PARTITRACE17) // red arrow ground track? { ts.x = 176.0f/256.0f; ts.y = 224.0f/256.0f; } else { return; } Math::Point ti; if ( m_wheelTrace[i].type == PARTITRACE16 || m_wheelTrace[i].type == PARTITRACE17 ) { ti.x = ts.x+16.0f/256.0f; ti.y = ts.y+16.0f/256.0f; } else { ti.x = ts.x+8.0f/256.0f; ti.y = ts.y+8.0f/256.0f; } float dp = (1.0f/256.0f)/2.0f; ts.x = ts.x+dp; ts.y = ts.y+dp; ti.x = ti.x-dp; ti.y = ti.y-dp; Math::Vector n(0.0f, 1.0f, 0.0f); Vertex vertex[4]; vertex[0] = Vertex(pos[0], n, Math::Point(ts.x, ts.y)); vertex[1] = Vertex(pos[1], n, Math::Point(ti.x, ts.y)); vertex[2] = Vertex(pos[2], n, Math::Point(ts.x, ti.y)); vertex[3] = Vertex(pos[3], n, Math::Point(ti.x, ti.y)); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); m_engine->AddStatisticTriangle(2); } void CParticle::DrawParticle(int sheet) { // Draw the basic particles of triangles. if (m_totalInterface[0][sheet] > 0) { for (int i = 0; i < MAXPARTICULE; i++) { if (!m_particle[i].used) continue; if (m_particle[i].sheet != sheet) continue; if (m_particle[i].type == PARTIPART) continue; m_engine->SetTexture("textures/"+m_triangle[i].tex1Name); m_engine->SetMaterial(m_triangle[i].material); m_engine->SetState(m_triangle[i].state); DrawParticleTriangle(i); } } Material mat; mat.diffuse.r = 1.0f; mat.diffuse.g = 1.0f; mat.diffuse.b = 1.0f; // white mat.ambient.r = 0.5f; mat.ambient.g = 0.5f; mat.ambient.b = 0.5f; m_engine->SetMaterial(mat); // Draw tire marks. if (m_wheelTraceTotal > 0 && sheet == SH_WORLD) { m_engine->SetTexture("textures/interface/text.png"); m_engine->SetState(ENG_RSTATE_TTEXTURE_WHITE); Math::Matrix matrix; matrix.LoadIdentity(); m_device->SetTransform(TRANSFORM_WORLD, matrix); for (int i = 0; i < m_wheelTraceTotal; i++) DrawParticleWheel(i); } for (int t = MAXPARTITYPE-1; t >= 1; t--) // black behind! { if (m_totalInterface[t][sheet] == 0) continue; bool loadTexture = false; int state; if (t == 4) state = ENG_RSTATE_TTEXTURE_WHITE; // text.png else state = ENG_RSTATE_TTEXTURE_BLACK; // effect[00..02].png m_engine->SetState(state); for (int j = 0; j < MAXPARTICULE; j++) { int i = MAXPARTICULE*t+j; if (!m_particle[i].used) continue; if (m_particle[i].sheet != sheet) continue; if (!loadTexture) { std::string name; NameParticle(name, t); m_engine->SetTexture("textures/"+name); loadTexture = true; } int r = m_particle[i].trackRank; if (r != -1) { m_engine->SetState(state); TrackDraw(r, m_particle[i].type); // draws the drag if (!m_track[r].drawParticle) continue; } m_engine->SetState(state, IntensityToColor(m_particle[i].intensity)); if (m_particle[i].ray) // ray? { DrawParticleRay(i); } else if ( m_particle[i].type == PARTIFLIC || // circle in the water? m_particle[i].type == PARTISHOW || m_particle[i].type == PARTICHOC || m_particle[i].type == PARTIGFLAT ) { DrawParticleFlat(i); } else if ( m_particle[i].type >= PARTIFOG0 && m_particle[i].type <= PARTIFOG9 ) { DrawParticleFog(i); } else if ( m_particle[i].type >= PARTISPHERE0 && m_particle[i].type <= PARTISPHERE9 ) // sphere? { DrawParticleSphere(i); } else if ( m_particle[i].type >= PARTIPLOUF0 && m_particle[i].type <= PARTIPLOUF4 ) // cylinder? { DrawParticleCylinder(i); } else // normal? { DrawParticleNorm(i); } } } } CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father) { if (m_main->GetMovieLock()) return nullptr; // current movie? bool himself = m_main->GetHimselfDamage(); float min = 5.0f; if (type == PARTIGUN2) min = 2.0f; // shooting insect? if (type == PARTIGUN3) min = 3.0f; // suiciding spider? Math::Vector box1 = old; Math::Vector box2 = pos; if (box1.x > box2.x) Math::Swap(box1.x, box2.x); // box1 < box2 if (box1.y > box2.y) Math::Swap(box1.y, box2.y); if (box1.z > box2.z) Math::Swap(box1.z, box2.z); box1.x -= min; box1.y -= min; box1.z -= min; box2.x += min; box2.y += min; box2.z += min; CInstanceManager* iMan = CInstanceManager::GetInstancePointer(); CObject* best = 0; bool shield = false; for (int i = 0; i < 1000000; i++) { CObject* obj = static_cast(iMan->SearchInstance(CLASS_OBJECT, i)); if (obj == 0) break; if (!obj->GetActif()) continue; // inactive? if (obj == father) continue; ObjectType oType = obj->GetType(); if (oType == OBJECT_TOTO) continue; if (type == PARTIGUN1) // fireball shooting? { if (oType == OBJECT_MOTHER) continue; if (himself) // damage is oneself? { if ( !IsAlien(oType) && !IsSoft(oType) ) continue; } else // damage only to enemies? { if (!IsAlien(oType)) continue; } } else if (type == PARTIGUN2) // shooting insect? { if (!IsSoft(oType)) continue; } else if (type == PARTIGUN3) // suiciding spider? { if (!IsSoft(oType)) continue; } else if (type == PARTIGUN4) // orgaball shooting? { if (oType == OBJECT_MOTHER) continue; if (himself) // damage is oneself? { if ( !IsAlien(oType) && !IsSoft(oType) ) continue; } else // damage only to enemies? { if (!IsAlien(oType)) continue; } } else if (type == PARTITRACK11) // phazer shooting? { if (himself) // damage is oneself? { if ( !IsAlien(oType) && !IsSoft(oType) ) continue; } else // damage only to enemies? { if (!IsAlien(oType)) continue; } } else { continue; } Math::Vector oPos = obj->GetPosition(0); if ( type == PARTIGUN2 || // shooting insect? type == PARTIGUN3 ) // suiciding spider? { // Test if the ball is entered into the sphere of a shield. float shieldRadius = obj->GetShieldRadius(); if (shieldRadius > 0.0f) { float dist = Math::Distance(oPos, pos); if (dist <= shieldRadius) { best = obj; shield = true; } } } if (shield) continue; // Test the center of the object, which is necessary for objects // that have no sphere in the center (station). float dist = Math::Distance(oPos, pos)-4.0f; if (dist < min) best = obj; // Test with all spheres of the object. int j = 0; float oRadius; while (obj->GetCrashSphere(j++, oPos, oRadius)) { if ( oPos.x+oRadius < box1.x || oPos.x-oRadius > box2.x || // outside the box? oPos.y+oRadius < box1.y || oPos.y-oRadius > box2.y || oPos.z+oRadius < box1.z || oPos.z-oRadius > box2.z ) continue; Math::Vector p = Math::Projection(old, pos, oPos); float ddist = Math::Distance(p, oPos)-oRadius; if (ddist < min) best = obj; } } return best; } CObject* CParticle::SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father) { if (m_main->GetMovieLock()) return nullptr; // current movie? float min = 10.0f; Math::Vector box1 = pos; Math::Vector box2 = goal; if (box1.x > box2.x) Math::Swap(box1.x, box2.x); // box1 < box2 if (box1.y > box2.y) Math::Swap(box1.y, box2.y); if (box1.z > box2.z) Math::Swap(box1.z, box2.z); box1.x -= min; box1.y -= min; box1.z -= min; box2.x += min; box2.y += min; box2.z += min; CInstanceManager* iMan = CInstanceManager::GetInstancePointer(); for (int i = 0; i < 1000000; i++) { CObject* obj = static_cast( iMan->SearchInstance(CLASS_OBJECT, i) ); if (obj == nullptr) break; if (!obj->GetActif()) continue; // inactive? if (obj == father) continue; ObjectType oType = obj->GetType(); if (oType == OBJECT_TOTO) continue; if ( type == PARTIRAY1 && oType != OBJECT_MOBILEtg && oType != OBJECT_TEEN28 && oType != OBJECT_TEEN31 && oType != OBJECT_ANT && oType != OBJECT_SPIDER && oType != OBJECT_BEE && oType != OBJECT_WORM && oType != OBJECT_MOTHER && oType != OBJECT_NEST ) continue; Math::Vector oPos = obj->GetPosition(0); if ( oPos.x < box1.x || oPos.x > box2.x || // outside the box? oPos.y < box1.y || oPos.y > box2.y || oPos.z < box1.z || oPos.z > box2.z ) continue; Math::Vector p = Math::Projection(pos, goal, oPos); float dist = Math::Distance(p, oPos); if (dist < min) return obj; } return nullptr; } void CParticle::Play(Sound sound, Math::Vector pos, float amplitude) { if (m_sound == nullptr) m_sound = CApplication::GetInstancePointer()->GetSound(); m_sound->Play(sound, pos, amplitude); } Color CParticle::GetFogColor(Math::Vector pos) { Color result; result.r = 0.0f; result.g = 0.0f; result.b = 0.0f; result.a = 0.0f; for (int fog = 0; fog < m_fogTotal; fog++) { int i = m_fog[fog]; // i = rank of the particle if (pos.y >= m_particle[i].pos.y+FOG_HSUP) continue; if (pos.y <= m_particle[i].pos.y-FOG_HINF) continue; float dist = Math::DistanceProjected(pos, m_particle[i].pos); if (dist >= m_particle[i].dim.x*1.5f) continue; // Calculates the horizontal distance. float factor = 1.0f-powf(dist/(m_particle[i].dim.x*1.5f), 4.0f); // Calculates the vertical distance. if (pos.y > m_particle[i].pos.y) factor *= 1.0f-(pos.y-m_particle[i].pos.y)/FOG_HSUP; else factor *= 1.0f-(m_particle[i].pos.y-pos.y)/FOG_HINF; factor *= 0.3f; Color color; if ( m_particle[i].type == PARTIFOG0 || m_particle[i].type == PARTIFOG1 ) // blue? { color.r = 0.0f; color.g = 0.5f; color.b = 1.0f; } else if ( m_particle[i].type == PARTIFOG2 || m_particle[i].type == PARTIFOG3 ) // red? { color.r = 2.0f; color.g = 1.0f; color.b = 0.0f; } else if ( m_particle[i].type == PARTIFOG4 || m_particle[i].type == PARTIFOG5 ) // white? { color.r = 1.0f; color.g = 1.0f; color.b = 1.0f; } else if ( m_particle[i].type == PARTIFOG6 || m_particle[i].type == PARTIFOG7 ) // yellow? { color.r = 0.8f; color.g = 1.0f; color.b = 0.4f; } else { color.r = 0.0f; color.g = 0.0f; color.b = 0.0f; } result.r += color.r*factor; result.g += color.g*factor; result.b += color.b*factor; } if (result.r > 0.6f) result.r = 0.6f; if (result.g > 0.6f) result.g = 0.6f; if (result.b > 0.6f) result.b = 0.6f; return result; } bool CParticle::WriteWheelTrace(const char *filename, int width, int height, Math::Vector dl, Math::Vector ur) { // TODO: stub! GetLogger()->Trace("CParticle::WriteWheelTrace(): stub!\n"); return true; } } // namespace Gfx