colobot/src/graphics/engine/particle.cpp

3923 lines
114 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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 <cstring>
// 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 = "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<int>(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<int>(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<int>((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<int>((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<int>((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<int>(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<int>(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<int>(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<int>(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<float>(numRings);
float tv1 = (ring+1)/static_cast<float>(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<float>(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<float>(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(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("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(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<CObject*>(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<CObject*>( 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