mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00

This implementation should just let the game run without crashing, the renderer doesn't show anything yet
1662 lines
34 KiB
C++
1662 lines
34 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2023-2024 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// tr_ghost.cpp
|
|
|
|
#include "tr_local.h"
|
|
#include "tr_ghost.h"
|
|
|
|
GhostManager ghostManager;
|
|
|
|
int frameTime;
|
|
int lastTime;
|
|
|
|
/*
|
|
====================
|
|
RandomizeRange
|
|
|
|
====================
|
|
*/
|
|
float RandomizeRange(float min, float max)
|
|
{
|
|
return min + (max - min) * (rand() / (float)RAND_MAX);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Particle::Particle
|
|
|
|
Initializes the particle with the specified parameters
|
|
====================
|
|
*/
|
|
Particle::Particle(
|
|
Vector pos,
|
|
Vector vel,
|
|
Vector acc,
|
|
int srcColor,
|
|
int dstColor,
|
|
float colorRate,
|
|
qboolean wavy,
|
|
float wavyDist,
|
|
float currentTime,
|
|
float dieTime,
|
|
float maxspeed,
|
|
Vector parentOrg,
|
|
qboolean swarm,
|
|
int freq,
|
|
int delta
|
|
)
|
|
{
|
|
m_position = pos;
|
|
m_realposition = pos;
|
|
m_velocity = vel;
|
|
m_acceleration = acc;
|
|
|
|
m_srcColor = srcColor;
|
|
m_dstColor = dstColor;
|
|
m_color = srcColor;
|
|
m_colorRate = colorRate;
|
|
|
|
m_wavy = wavy;
|
|
m_wavyDist = wavyDist;
|
|
m_wavyOffset = RandomizeRange(-wavyDist, wavyDist);
|
|
|
|
m_swarm = swarm;
|
|
m_swarmfrequency = freq;
|
|
m_swarmdelta = delta;
|
|
|
|
m_startTime = currentTime;
|
|
m_dieTime = dieTime;
|
|
m_life = dieTime - currentTime;
|
|
|
|
m_maxspeed = maxspeed;
|
|
m_parentOrigin = parentOrg;
|
|
|
|
Vector tempvec = m_velocity;
|
|
VectorNormalize(tempvec);
|
|
|
|
m_perp.x = tempvec.x * cos(M_PI / 2) - tempvec.y * sin(M_PI / 2);
|
|
m_perp.y = tempvec.x * sin(M_PI / 2) + tempvec.y * cos(M_PI / 2);
|
|
|
|
m_srcR = (m_srcColor & 0xff);
|
|
m_srcG = (m_srcColor & 0xff00) >> 8;
|
|
m_srcB = (m_srcColor & 0xff0000) >> 16;
|
|
|
|
m_dstR = (m_dstColor & 0xff);
|
|
m_dstG = (m_dstColor & 0xff00) >> 8;
|
|
m_dstB = (m_dstColor & 0xff0000) >> 16;
|
|
|
|
m_deltaR = m_dstR - m_srcR;
|
|
m_deltaG = m_dstG - m_srcG;
|
|
m_deltaB = m_dstB - m_srcB;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Particle::Update
|
|
|
|
Updates the particle based on the current time
|
|
====================
|
|
*/
|
|
void Particle::Update(float currentTime)
|
|
{
|
|
int r, g, b;
|
|
float ftime;
|
|
float time2;
|
|
float factor;
|
|
Vector offset;
|
|
|
|
ftime = frameTime / 1000.0;
|
|
time2 = Square(ftime) * 0.5;
|
|
|
|
if (m_swarm) {
|
|
if (!(rand() % m_swarmfrequency)) {
|
|
m_velocity[0] = crandom() * m_maxspeed;
|
|
m_velocity[1] = crandom() * m_maxspeed;
|
|
m_velocity[2] = crandom() * m_maxspeed;
|
|
}
|
|
|
|
if (m_parentOrigin[0] > m_position[0]) {
|
|
m_velocity[0] += m_swarmdelta;
|
|
} else {
|
|
m_velocity[0] -= m_swarmdelta;
|
|
}
|
|
if (m_parentOrigin[1] > m_position[1]) {
|
|
m_velocity[1] += m_swarmdelta;
|
|
} else {
|
|
m_velocity[1] -= m_swarmdelta;
|
|
}
|
|
if (m_parentOrigin[2] > m_position[2]) {
|
|
m_velocity[2] += m_swarmdelta;
|
|
} else {
|
|
m_velocity[2] -= m_swarmdelta;
|
|
}
|
|
}
|
|
|
|
m_position = m_realposition;
|
|
|
|
m_position += m_velocity * ftime + m_acceleration * time2;
|
|
m_velocity += m_acceleration * ftime;
|
|
m_realposition = m_position;
|
|
|
|
if (m_wavy) {
|
|
offset = m_perp * sin(currentTime + m_wavyOffset) * (m_wavyOffset + m_wavyDist);
|
|
m_position += offset;
|
|
}
|
|
|
|
factor = 1.0 - (m_dieTime - currentTime) / m_life;
|
|
r = m_deltaR * factor;
|
|
g = m_deltaG * factor;
|
|
b = m_deltaB * factor;
|
|
|
|
m_color = (r) | (g << 8) | (b << 8);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Particle::GetDieTime
|
|
|
|
Returns the time at which the particle stops
|
|
====================
|
|
*/
|
|
float Particle::GetDieTime()
|
|
{
|
|
return m_dieTime;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::ParticleEmitter
|
|
|
|
Initializes the particle emitter with specified parameters
|
|
====================
|
|
*/
|
|
ParticleEmitter::ParticleEmitter(
|
|
Vector position,
|
|
float minSpeed,
|
|
float maxSpeed,
|
|
float angle,
|
|
float angleVar,
|
|
float minAccSpeed,
|
|
float maxAccSpeed,
|
|
float accAngle,
|
|
float accAngleVar,
|
|
float minRate,
|
|
float maxRate,
|
|
int srcColor,
|
|
int dstColor,
|
|
float minColorRate,
|
|
float maxColorRate,
|
|
qboolean wavy,
|
|
float minWavyDist,
|
|
float maxWavyDist,
|
|
float minLife,
|
|
float maxLife,
|
|
qboolean particles,
|
|
qboolean gravityWell,
|
|
float gravityWellStrength,
|
|
qboolean ballLightning,
|
|
int minBallLightningRadius,
|
|
int maxBallLightningRadius,
|
|
float lightningVar,
|
|
int lightningSubdivisions,
|
|
qboolean swarm,
|
|
int swarmfreq,
|
|
int swarmdelta
|
|
)
|
|
{
|
|
m_position = position;
|
|
|
|
m_minSpeed = minSpeed;
|
|
m_maxSpeed = maxSpeed;
|
|
|
|
m_angle = angle;
|
|
m_angleVar = angleVar;
|
|
m_minAccSpeed = minAccSpeed;
|
|
m_maxAccSpeed = maxAccSpeed;
|
|
m_accAngle = accAngle;
|
|
m_accAngleVar = accAngleVar;
|
|
|
|
m_maxRate = 1.0 / maxRate;
|
|
m_minRate = 1.0 / minRate;
|
|
|
|
m_srcColor = srcColor;
|
|
m_dstColor = dstColor;
|
|
m_minColorRate = minColorRate;
|
|
m_maxColorRate = maxColorRate;
|
|
|
|
m_minWavyDist = minWavyDist;
|
|
m_maxWavyDist = maxWavyDist;
|
|
m_minLife = minLife;
|
|
m_maxLife = maxLife;
|
|
|
|
m_wavy = wavy;
|
|
|
|
m_particles = particles;
|
|
|
|
m_gravityWellStrength = gravityWellStrength;
|
|
m_gravityWell = gravityWell;
|
|
|
|
m_ballLightning = ballLightning;
|
|
m_minBallLightningRadius = minBallLightningRadius;
|
|
m_lightningVar = lightningVar;
|
|
m_maxBallLightningRadius = maxBallLightningRadius;
|
|
m_lightningSubdivisions = lightningSubdivisions;
|
|
|
|
m_swarm = swarm;
|
|
m_swarmfrequency = swarmfreq;
|
|
m_swarmdelta = swarmdelta;
|
|
|
|
m_time = tr.refdef.time;
|
|
m_lasttime = m_time;
|
|
|
|
m_gravityEffectVector = vec_zero;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::ParticleEmitter
|
|
====================
|
|
*/
|
|
ParticleEmitter::ParticleEmitter()
|
|
{
|
|
m_lasttime = tr.refdef.time / 1000.0;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::~ParticleEmitter
|
|
====================
|
|
*/
|
|
ParticleEmitter::~ParticleEmitter() {}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::Emit
|
|
|
|
Creates new particles based on the current time
|
|
====================
|
|
*/
|
|
void ParticleEmitter::Emit(float currentTime)
|
|
{
|
|
Particle *p;
|
|
float rate;
|
|
float delta;
|
|
|
|
rate = GetRate();
|
|
delta = currentTime = m_lasttime;
|
|
|
|
if (!rate) {
|
|
m_lasttime = currentTime;
|
|
return;
|
|
}
|
|
|
|
for (; delta > rate; delta -= rate) {
|
|
p = new Particle(
|
|
m_position,
|
|
GetVelocity(),
|
|
GetAcceleration(),
|
|
GetSrcColor(),
|
|
GetDstColor(),
|
|
GetColorRate(),
|
|
IsWavy(),
|
|
GetWavyDistance(),
|
|
currentTime,
|
|
GetDieTime(currentTime),
|
|
m_maxSpeed,
|
|
GetPosition(),
|
|
IsSwarm(),
|
|
m_swarmfrequency,
|
|
m_swarmdelta
|
|
);
|
|
|
|
particleList.AddObject(p);
|
|
|
|
m_lasttime = currentTime;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::UpdateValues
|
|
|
|
Updates all particles with the last renderer time
|
|
====================
|
|
*/
|
|
void ParticleEmitter::UpdateValues()
|
|
{
|
|
int i;
|
|
int numParticles;
|
|
|
|
numParticles = particleList.NumObjects();
|
|
for (i = 1; i <= numParticles; i++) {
|
|
Particle *p = particleList.ObjectAt(i);
|
|
|
|
p->Update(m_lasttime);
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetPosition
|
|
|
|
Returns the current particle position
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetPosition()
|
|
{
|
|
return m_position;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetVelocity
|
|
|
|
Returns the random velocity based on random angle, and random speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetVelocity()
|
|
{
|
|
float var;
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_angle, m_angleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
//
|
|
// Calculate the velocity from random speed
|
|
//
|
|
var = RandomizeRange(m_minSpeed, m_maxSpeed);
|
|
v *= var;
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetVelocityDirection
|
|
|
|
Returns the direction of the random velocity
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetVelocityDirection()
|
|
{
|
|
float var;
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_angle, m_angleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
//
|
|
// Calculate the velocity from random speed
|
|
//
|
|
var = RandomizeRange(m_minSpeed, m_maxSpeed);
|
|
v *= var;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetVelocityDirectionMin
|
|
|
|
Returns the random velocity direction based on random angle, and minimum speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetVelocityDirectionMin()
|
|
{
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_angle, m_angleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
// Use the minimum speed
|
|
v *= m_minSpeed;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetVelocityDirectionMax
|
|
|
|
Returns the random velocity direction based on random angle, and maximum speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetVelocityDirectionMax()
|
|
{
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_angle, m_angleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
// Use the minimum speed
|
|
v *= m_maxSpeed;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetAcceleration
|
|
|
|
Returns the random acceleration based on random angle, and random speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetAcceleration()
|
|
{
|
|
float var;
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_accAngle, m_accAngleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
//
|
|
// Calculate the velocity from random speed
|
|
//
|
|
var = RandomizeRange(m_minSpeed, m_maxSpeed);
|
|
v += m_gravityEffectVector * var;
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetAccelerationDirection
|
|
|
|
Returns the direction of the random acceleration
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetAccelerationDirection()
|
|
{
|
|
float var;
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_accAngle, m_accAngleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
//
|
|
// Calculate the velocity from random speed
|
|
//
|
|
var = RandomizeRange(m_minSpeed, m_maxSpeed);
|
|
v += m_gravityEffectVector * var;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetAccelerationDirectionMin
|
|
|
|
Returns the random acceleration direction based on random angle, and minimum speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetAccelerationDirectionMin()
|
|
{
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_accAngle, m_accAngleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
// Use the minimum speed
|
|
v += m_gravityEffectVector * m_minSpeed;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetAccelerationDirectionMax
|
|
|
|
Returns the random acceleration direction based on random angle, and maximum speed
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::GetAccelerationDirectionMax()
|
|
{
|
|
float angle;
|
|
Vector v;
|
|
|
|
//
|
|
// Calculate the direction from random angle
|
|
//
|
|
angle = RandomizeAngle(m_accAngle, m_accAngleVar);
|
|
v = CalculateDirection(angle);
|
|
|
|
// Use the maximum speed
|
|
v += m_gravityEffectVector * m_minSpeed;
|
|
|
|
v.normalize();
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetSrcColor
|
|
|
|
Returns the source color
|
|
====================
|
|
*/
|
|
int ParticleEmitter::GetSrcColor()
|
|
{
|
|
return m_srcColor;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetDstColor
|
|
|
|
Returns the destination color
|
|
====================
|
|
*/
|
|
int ParticleEmitter::GetDstColor()
|
|
{
|
|
return m_dstColor;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetGravityWellStrength
|
|
|
|
Returns the strength of the gravity
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetGravityWellStrength()
|
|
{
|
|
return m_gravityWellStrength;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetRate
|
|
|
|
Returns a random rate between minimum and maximum
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetRate()
|
|
{
|
|
return RandomizeRange(m_minRate, m_maxRate);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetColorRate
|
|
|
|
Returns a random color between minimum and maximum
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetColorRate()
|
|
{
|
|
return RandomizeRange(m_minColorRate, m_maxColorRate);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetWavyDistance
|
|
|
|
Returns a random wavy distance between minimum and maximum
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetWavyDistance()
|
|
{
|
|
return RandomizeRange(m_minWavyDist, m_maxWavyDist);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetDieTime
|
|
|
|
Returns a random time at which the particle will stop, between minimum and maximum
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetDieTime(float currentTime)
|
|
{
|
|
return currentTime + RandomizeRange(m_minLife, m_maxLife);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetBallLightningRadius
|
|
|
|
Returns a random lightning radius between minimum and maximum
|
|
====================
|
|
*/
|
|
int ParticleEmitter::GetBallLightningRadius()
|
|
{
|
|
return RandomizeRange(m_minBallLightningRadius, m_maxBallLightningRadius);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetLightningVar
|
|
|
|
Returns the maximum lightning value
|
|
====================
|
|
*/
|
|
float ParticleEmitter::GetLightningVar()
|
|
{
|
|
return m_lightningVar;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::GetLightningSubdivisions
|
|
|
|
Returns the number of lightning subdivisions
|
|
====================
|
|
*/
|
|
int ParticleEmitter::GetLightningSubdivisions()
|
|
{
|
|
return m_lightningSubdivisions;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::IsWavy
|
|
|
|
Returns whether or not this is a wavy particle
|
|
====================
|
|
*/
|
|
qboolean ParticleEmitter::IsWavy()
|
|
{
|
|
return m_wavy;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::IsGravityWell
|
|
|
|
Returns whether or not this particle has gravity
|
|
====================
|
|
*/
|
|
qboolean ParticleEmitter::IsGravityWell()
|
|
{
|
|
return m_gravityWell;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::IsParticles
|
|
|
|
Returns whether or not this contains particles
|
|
====================
|
|
*/
|
|
qboolean ParticleEmitter::IsParticles()
|
|
{
|
|
return m_particles;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::IsBallLightning
|
|
|
|
Returns whether or not ball lightning can be applied
|
|
====================
|
|
*/
|
|
qboolean ParticleEmitter::IsBallLightning()
|
|
{
|
|
return m_ballLightning;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::IsSwarm
|
|
|
|
Returns whether or not this is a swarm of particles
|
|
====================
|
|
*/
|
|
qboolean ParticleEmitter::IsSwarm()
|
|
{
|
|
return m_swarm;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinSpeed
|
|
|
|
Sets the minimum speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinSpeed(float value)
|
|
{
|
|
m_minSpeed = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxSpeed
|
|
|
|
Sets the maximum speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxSpeed(float value)
|
|
{
|
|
m_maxSpeed = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetAngle
|
|
|
|
Sets the angle/minimum angle
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetAngle(float value)
|
|
{
|
|
m_angle = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetAngleVar
|
|
|
|
Sets the maximum speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetAngleVar(float value)
|
|
{
|
|
m_angleVar = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinAccSpeed
|
|
|
|
Sets the minimum acceleration speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinAccSpeed(float value)
|
|
{
|
|
m_minAccSpeed = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxAccSpeed
|
|
|
|
Sets the maximum acceleration speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxAccSpeed(float value)
|
|
{
|
|
m_maxAccSpeed = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetAccAngle
|
|
|
|
Sets the acceleration angle / minimum acceleration angle
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetAccAngle(float value)
|
|
{
|
|
m_accAngle = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetAccAngleVar
|
|
|
|
Sets the maximum acceleration speed
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetAccAngleVar(float value)
|
|
{
|
|
m_accAngleVar = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinRate
|
|
|
|
Sets the minimum rate
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinRate(float value)
|
|
{
|
|
m_minRate = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxRate
|
|
|
|
Sets the maximum rate
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxRate(float value)
|
|
{
|
|
m_maxRate = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetSrcColor
|
|
|
|
Sets the source color
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetSrcColor(int value)
|
|
{
|
|
m_srcColor = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetDstColor
|
|
|
|
Sets the destination color
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetDstColor(int value)
|
|
{
|
|
m_dstColor = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinColorRate
|
|
|
|
Sets the minimum color rate
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinColorRate(float value)
|
|
{
|
|
m_minColorRate = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxColorRate
|
|
|
|
Sets the maximum color rate
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxColorRate(float value)
|
|
{
|
|
m_maxColorRate = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetWavy
|
|
|
|
Sets whether or not this is a wavy particle
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetWavy(int value)
|
|
{
|
|
m_wavy = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetParticles
|
|
|
|
Sets whether or not this contains particles
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetParticles(int value)
|
|
{
|
|
m_particles = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetGravityWell
|
|
|
|
Sets whether or not this has gravity
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetGravityWell(int value)
|
|
{
|
|
m_gravityWell = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinWavyDist
|
|
|
|
Sets the minimum wavy distance
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinWavyDist(float value)
|
|
{
|
|
m_minWavyDist = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxWavyDist
|
|
|
|
Sets the maximum wavy distance
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxWavyDist(float value)
|
|
{
|
|
m_maxWavyDist = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinLife
|
|
|
|
Sets the minimum life
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinLife(float value)
|
|
{
|
|
m_minLife = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxLife
|
|
|
|
Sets the maximum life
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxLife(float value)
|
|
{
|
|
m_maxLife = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetGravityWellStrength
|
|
|
|
Sets the strength of the gravity
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetGravityWellStrength(float value)
|
|
{
|
|
m_gravityWellStrength = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetGravityEffectVector
|
|
|
|
Sets the direction at which gravity is applied
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetGravityEffectVector(Vector value)
|
|
{
|
|
m_gravityEffectVector = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetBallLightning
|
|
|
|
Sets whether or not it has ball lightning
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetBallLightning(int value)
|
|
{
|
|
m_ballLightning = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMinBallLightningRadius
|
|
|
|
Sets the minimum ball lightning radius
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMinBallLightningRadius(int value)
|
|
{
|
|
m_minBallLightningRadius = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetMaxBallLightningRadius
|
|
|
|
Sets the maximum ball lightning radius
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetMaxBallLightningRadius(int value)
|
|
{
|
|
m_maxBallLightningRadius = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetLightningVar
|
|
|
|
Sets the maximum lightning value
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetLightningVar(float value)
|
|
{
|
|
m_lightningVar = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::SetLightningSubdivisions
|
|
|
|
Sets the number of subdivisions for the lightning
|
|
====================
|
|
*/
|
|
void ParticleEmitter::SetLightningSubdivisions(int value)
|
|
{
|
|
m_lightningSubdivisions = value;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::RandomizeRange
|
|
|
|
Returns a random value between the range [min, max]
|
|
====================
|
|
*/
|
|
float ParticleEmitter::RandomizeRange(float min, float max)
|
|
{
|
|
return min + (max - min) * (rand() / (float)RAND_MAX);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::RandomizeAngle
|
|
|
|
Returns a random angle between the range [min, max]
|
|
====================
|
|
*/
|
|
float ParticleEmitter::RandomizeAngle(float min, float max)
|
|
{
|
|
return min + ((rand() - (RAND_MAX / 2)) / (float)RAND_MAX) * max;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::CalculateDirection
|
|
|
|
Returns a random Vector direction based on the angle value
|
|
====================
|
|
*/
|
|
Vector ParticleEmitter::CalculateDirection(float value)
|
|
{
|
|
float deg = DEG2RAD(value);
|
|
|
|
return Vector(cos(deg), -sin(deg), 0);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
ParticleEmitter::Load
|
|
|
|
Loads the specified particle emitter from the string buffer
|
|
====================
|
|
*/
|
|
void ParticleEmitter::Load(char **buf_p)
|
|
{
|
|
m_position[0] = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_position[1] = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_position[2] = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_srcColor = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_dstColor = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_minColorRate = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_maxColorRate = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_minRate = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_maxRate = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_minLife = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_maxLife = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_angle = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_angleVar = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_accAngle = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_accAngleVar = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_minSpeed = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_maxSpeed = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_minAccSpeed = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_maxAccSpeed = atof(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_minWavyDist = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_maxWavyDist = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_wavy = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_particles = atoi(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_gravityWell = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_gravityWellStrength = atof(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_ballLightning = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_minBallLightningRadius = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_maxBallLightningRadius = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_lightningVar = atof(COM_ParseExt(buf_p, qtrue));
|
|
m_lightningSubdivisions = atof(COM_ParseExt(buf_p, qtrue));
|
|
|
|
m_swarm = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_swarmfrequency = atoi(COM_ParseExt(buf_p, qtrue));
|
|
m_swarmdelta = atoi(COM_ParseExt(buf_p, qtrue));
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::GhostTexture
|
|
====================
|
|
*/
|
|
GhostTexture::GhostTexture()
|
|
{
|
|
m_image = NULL;
|
|
m_texture = NULL;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::SetTexel
|
|
|
|
Sets color at the specified xy texel location
|
|
====================
|
|
*/
|
|
void GhostTexture::SetTexel(int x, int y, unsigned int color)
|
|
{
|
|
m_texture[x + m_width * y] = color;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::Burn
|
|
|
|
Applies fade/burn effect to the ghost texture
|
|
====================
|
|
*/
|
|
void GhostTexture::Burn()
|
|
{
|
|
int x, y;
|
|
int r, g, b;
|
|
GLint pixel;
|
|
GLuint *line;
|
|
|
|
if (m_isfade) {
|
|
for (y = 1; y < m_height - 1; y++) {
|
|
line = &m_texture[m_width * y];
|
|
|
|
for (x = 1; x < m_width - 1; x++) {
|
|
r = (line[x] & 0xff) - m_faderate;
|
|
g = ((line[x] & 0xff00) >> 8) - m_faderate;
|
|
b = ((line[x] & 0xff0000) >> 16) - m_faderate;
|
|
|
|
if (r < 0) {
|
|
r = 0;
|
|
}
|
|
if (g < 0) {
|
|
g = 0;
|
|
}
|
|
if (b < 0) {
|
|
b = 0;
|
|
}
|
|
|
|
line[x] = (r) | (g << 8) | (b << 16);
|
|
}
|
|
}
|
|
} else if (m_isburn) {
|
|
for (y = 1; y < m_height - 1; y++) {
|
|
line = &m_texture[m_width * y];
|
|
|
|
for (x = 1; x < m_width - 1; x++) {
|
|
r = (((line[m_width + x] & 0xff) + (line[x + 1] & 0xff) + (line[x - 1] & 0xff) + (line[x] & 0xff)) >> 2)
|
|
- m_burnrate;
|
|
g = ((((line[m_width + x] & 0xFF00) >> 8) + ((line[x + 1] & 0xFF00) >> 8)
|
|
+ ((line[x - 1] & 0xFF00) >> 8) + ((line[x] & 0xFF00) >> 8))
|
|
>> 2)
|
|
- m_burnrate;
|
|
b = ((((line[m_width + x] & 0xFF0000) >> 16) + ((line[x + 1] & 0xFF0000) >> 16)
|
|
+ ((line[x - 1] & 0xFF0000) >> 16) + ((line[x] & 0xFF0000) >> 16))
|
|
>> 2)
|
|
- m_burnrate;
|
|
|
|
if (r < 0) {
|
|
r = 0;
|
|
}
|
|
if (g < 0) {
|
|
g = 0;
|
|
}
|
|
if (b < 0) {
|
|
b = 0;
|
|
}
|
|
|
|
pixel = (r) | (g << 8) | (b << 16);
|
|
if (pixel > 0) {
|
|
line[x] = pixel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
line = m_texture;
|
|
|
|
for (x = 0; x < m_width; x++) {
|
|
line[x] = 0;
|
|
}
|
|
|
|
for (y = 0; y < m_height; ++y) {
|
|
line[m_width * y] = 0;
|
|
line[m_width - 1 + m_width * y] = 0;
|
|
}
|
|
|
|
line = &m_texture[m_width * (m_height - 1)];
|
|
|
|
for (x = 0; x < m_width; x++) {
|
|
line[x] = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::ComputeOutCode
|
|
|
|
Returns a flag value indicating if x/y variable reached xmin/xmax
|
|
====================
|
|
*/
|
|
outcode GhostTexture::ComputeOutCode(int x, int y, int xmin, int xmax, int ymin, int ymax)
|
|
{
|
|
outcode code = 0;
|
|
|
|
if (y > ymax) {
|
|
code = 1;
|
|
} else if (y < ymin) {
|
|
code = 2;
|
|
}
|
|
|
|
if (x > xmax) {
|
|
code |= 4;
|
|
} else if (x < xmin) {
|
|
code |= 8;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::ClipAndDrawLine
|
|
|
|
Draws a line from p0 to p1 with clipping
|
|
====================
|
|
*/
|
|
void GhostTexture::ClipAndDrawLine(Vector p0, Vector p1, int color)
|
|
{
|
|
int x0, x1;
|
|
int y0, y1;
|
|
int d;
|
|
int x, y;
|
|
int ax, ay;
|
|
int sx, sy;
|
|
int dx, dy;
|
|
int xmax, ymax;
|
|
bool accept;
|
|
outcode outcode0;
|
|
outcode outcode1;
|
|
|
|
x0 = p0.x;
|
|
y0 = p0.y;
|
|
x1 = p1.x;
|
|
y1 = p1.y;
|
|
xmax = m_width - 1;
|
|
ymax = m_height - 1;
|
|
|
|
accept = false;
|
|
|
|
outcode0 = ComputeOutCode(x0, y0, 0, xmax, 0, ymax);
|
|
outcode1 = ComputeOutCode(x1, y1, 0, xmax, 0, ymax);
|
|
|
|
while (outcode1 | outcode0) {
|
|
outcode outCodeOut;
|
|
if (outcode0 & outcode1) {
|
|
break;
|
|
}
|
|
|
|
outCodeOut = outcode0 ? outcode0 : outcode1;
|
|
|
|
if (outCodeOut & 1) {
|
|
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
|
|
y = ymax;
|
|
} else if (outCodeOut & 2) {
|
|
x = x0 - y0 * (x1 - x0) / (y1 - y0);
|
|
y = 0;
|
|
} else if (outCodeOut & 4) {
|
|
x = xmax;
|
|
y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
|
|
} else if (outCodeOut * 8) {
|
|
x = 0;
|
|
y = y0 - x0 * (y1 - y0) / (x1 - x0);
|
|
} else {
|
|
x = x0;
|
|
y = y0;
|
|
}
|
|
if (outCodeOut == outcode0) {
|
|
y0 = y;
|
|
x0 = x;
|
|
outcode0 = ComputeOutCode(x, y, 0, xmax, 0, ymax);
|
|
} else {
|
|
x1 = x;
|
|
y1 = y;
|
|
outcode1 = ComputeOutCode(x, y, 0, xmax, 0, ymax);
|
|
}
|
|
}
|
|
|
|
accept = true;
|
|
if (!accept) {
|
|
return;
|
|
}
|
|
|
|
dx = x1 - x0;
|
|
if (dx < 0) {
|
|
dx = x0 - x1;
|
|
}
|
|
ax = dx * 2;
|
|
sx = dx >= 0 ? 1 : -1;
|
|
|
|
dy = y1 - y0;
|
|
if (dy < 0) {
|
|
dy = y0 - y1;
|
|
}
|
|
ay = dy * 2;
|
|
sy = dy >= 0 ? 1 : -1;
|
|
|
|
x = x0;
|
|
y = y0;
|
|
|
|
if (ax > ay) {
|
|
for (d = ay - (ax >> 1);; d += ay, x += sx) {
|
|
SetTexel(x, y, color);
|
|
if (x == x1) {
|
|
break;
|
|
}
|
|
|
|
if (d >= 0) {
|
|
y += sy;
|
|
d -= ax;
|
|
}
|
|
}
|
|
} else {
|
|
for (d = ax - (ay >> 1);; d += ax, y += sy) {
|
|
SetTexel(x, y, color);
|
|
if (y == y1) {
|
|
break;
|
|
}
|
|
|
|
if (d >= 0) {
|
|
x += sx;
|
|
d -= ay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::RotateVector
|
|
|
|
Rotates the vector from angle
|
|
====================
|
|
*/
|
|
Vector GhostTexture::RotateVector(Vector v, float angle)
|
|
{
|
|
Vector vec;
|
|
float rad;
|
|
|
|
rad = DEG2RAD(angle);
|
|
vec.x = cos(rad) * v.x - sin(rad) * v.y;
|
|
vec.y = cos(rad) * v.y + sin(rad) * v.x;
|
|
vec.z = 0;
|
|
|
|
return vec;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::GenerateLightning
|
|
|
|
Generates a lightning effect
|
|
====================
|
|
*/
|
|
void GhostTexture::GenerateLightning(
|
|
Vector p1, Vector p2, int color, float angleVar, int numSubdivisions, int maxSubdivisions
|
|
)
|
|
{
|
|
Vector mid;
|
|
Vector delta;
|
|
float length;
|
|
|
|
if (numSubdivisions == maxSubdivisions) {
|
|
p1[0] += 0.5;
|
|
p1[1] += 0.5;
|
|
p2[0] += 0.5;
|
|
p2[1] += 0.5;
|
|
ClipAndDrawLine(p1, p2, color);
|
|
|
|
return;
|
|
}
|
|
|
|
delta = p2 - p1;
|
|
length = delta.length() * 0.5;
|
|
delta.normalize();
|
|
|
|
mid = RotateVector(delta, RandomizeRange(-angleVar, angleVar));
|
|
mid = p1 + mid * length;
|
|
|
|
GenerateLightning(p1, mid, color, angleVar, numSubdivisions + 1, maxSubdivisions);
|
|
GenerateLightning(mid, p2, color, angleVar, numSubdivisions + 1, maxSubdivisions);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GhostTexture::Update
|
|
|
|
Updates the ghost texture
|
|
====================
|
|
*/
|
|
void GhostTexture::Update()
|
|
{
|
|
Vector pos;
|
|
int i, j;
|
|
int numEmitters;
|
|
float currentTime;
|
|
|
|
currentTime = tr.refdef.time / 1000.0;
|
|
|
|
numEmitters = m_emitterList.NumObjects();
|
|
|
|
for (i = 1; i <= numEmitters; i++) {
|
|
ParticleEmitter *pe = m_emitterList.ObjectAt(i);
|
|
|
|
if (pe->IsGravityWell()) {
|
|
break;
|
|
}
|
|
|
|
if (pe->IsBallLightning()) {
|
|
Vector p1, p2;
|
|
|
|
if (pe->GetBallLightningRadius()) {
|
|
p1 = pe->GetPosition();
|
|
p2 = pe->GetVelocityDirection();
|
|
|
|
p2 = p1 + p2 * pe->GetBallLightningRadius();
|
|
GenerateLightning(p1, p2, pe->GetSrcColor(), pe->GetLightningVar(), 0, pe->GetLightningSubdivisions());
|
|
}
|
|
} else if (pe->IsParticles()) {
|
|
pe->Emit(currentTime);
|
|
} else {
|
|
Vector p = pe->GetPosition();
|
|
|
|
SetTexel(p.x, p.y, pe->GetSrcColor());
|
|
}
|
|
|
|
for (j = pe->particleList.NumObjects(); j > 0; j--) {
|
|
Particle *p = pe->particleList.ObjectAt(j);
|
|
|
|
p->Update(currentTime);
|
|
if (p->m_position.x < m_width && p->m_position.x >= 0 && p->m_position.y < m_height && p->m_position.y >= 0
|
|
&& currentTime <= p->GetDieTime()) {
|
|
SetTexel(p->m_position.x, p->m_position.y, p->m_color);
|
|
} else {
|
|
delete p;
|
|
pe->particleList.RemoveObjectAt(j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
R_UpdateGhostTextures
|
|
|
|
Updates all ghost textures
|
|
====================
|
|
*/
|
|
void R_UpdateGhostTextures()
|
|
{
|
|
int i;
|
|
int numTextures;
|
|
|
|
frameTime = tr.refdef.time - lastTime;
|
|
lastTime = tr.refdef.time;
|
|
|
|
numTextures = ghostManager.m_textureList.NumObjects();
|
|
for (i = 1; i <= numTextures; i++) {
|
|
GhostTexture *gt = ghostManager.m_textureList.ObjectAt(i);
|
|
|
|
gt->Update();
|
|
gt->Burn();
|
|
|
|
GL_BindToTMU(gt->m_image, 0);
|
|
qglTexImage2D(GL_TEXTURE_2D, 0, 3, gt->m_width, gt->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, gt->m_texture);
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
R_SetGhostImage
|
|
|
|
Applies an image to the specified named ghost texture
|
|
====================
|
|
*/
|
|
void R_SetGhostImage(const char *name, image_t *image)
|
|
{
|
|
int i;
|
|
int numTextures;
|
|
|
|
numTextures = ghostManager.m_textureList.NumObjects();
|
|
for (i = 1; i <= numTextures; i++) {
|
|
GhostTexture *gt = ghostManager.m_textureList.ObjectAt(i);
|
|
|
|
if (gt->m_name == name) {
|
|
gt->m_image = image;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
LoadGHOST
|
|
|
|
Loads a GHOST image file
|
|
====================
|
|
*/
|
|
void LoadGHOST(const char *name, byte **pic, int *width, int *height)
|
|
{
|
|
char *buf_p;
|
|
char *buffer;
|
|
int numPixels;
|
|
int numParticles;
|
|
int i;
|
|
GhostTexture *gt;
|
|
|
|
if (ri.FS_ReadFile(name, (void **)&buffer) == -1) {
|
|
return;
|
|
}
|
|
|
|
buf_p = buffer;
|
|
COM_ParseExt(&buf_p, qtrue);
|
|
|
|
*width = atoi(COM_ParseExt(&buf_p, qtrue));
|
|
*height = atoi(COM_ParseExt(&buf_p, qtrue));
|
|
|
|
numParticles = atoi(COM_ParseExt(&buf_p, qtrue));
|
|
numPixels = *height * *width;
|
|
*pic = new byte[numPixels * 4];
|
|
|
|
gt = new GhostTexture();
|
|
gt->m_width = *width;
|
|
gt->m_height = *height;
|
|
gt->m_texture = new unsigned int[numPixels];
|
|
|
|
gt->m_isburn = atoi(COM_ParseExt(&buf_p, qtrue));
|
|
gt->m_burnrate = atof(COM_ParseExt(&buf_p, qtrue));
|
|
|
|
gt->m_isfade = atoi(COM_ParseExt(&buf_p, qtrue));
|
|
gt->m_faderate = atof(COM_ParseExt(&buf_p, qtrue));
|
|
|
|
ghostManager.m_textureList.AddObject(gt);
|
|
|
|
for (i = 0; i < numParticles; i++) {
|
|
ParticleEmitter *pe = new ParticleEmitter();
|
|
gt->m_emitterList.AddObject(pe);
|
|
pe->Load(&buf_p);
|
|
}
|
|
}
|