- Added Dave McAllister's particle system code (not licensed, but so old and not found online so I think it's OK)

This commit is contained in:
Flayra 2014-01-14 11:26:14 -08:00
parent 9ededaf0b5
commit b16ad0f3f3
18 changed files with 6671 additions and 0 deletions

View file

@ -0,0 +1,248 @@
// This file implements the API calls that draw particle groups in Half-life
#include "general.h"
#ifdef WIN32
// This is for something in gl.h.
#include <windows.h>
#endif
//#include <GL/gl.h>
#include "common/triangleapi.h"
#include "cl_dll/wrect.h"
#include "cl_dll/cl_dll.h"
#include "common/renderingconst.h"
#include "particles/papi.h"
// XXX #include <iostream.h>
// Draw as a splat texture on a quad.
void DrawGroupTriSplat(const pVector &view, const pVector &up,
float size_scale, bool draw_tex,
bool const_size, bool const_color)
{
int cnt = pGetGroupCount();
if(cnt < 1)
return;
pVector *ppos = new pVector[cnt];
float *color = const_color ? NULL : new float[cnt * 4];
pVector *size = const_size ? NULL : new pVector[cnt];
pGetParticles(0, cnt, (float *)ppos, color, NULL, (float *)size);
// Compute the vectors from the particle to the corners of its tri.
// 2
// |\ The particle is at the center of the x.
// |-\ V0, V1, and V2 go from there to the vertices.
// |x|\ The texcoords are (0,0), (2,0), and (0,2) respectively.
// 0-+-1 We clamp the texture so the rest is transparent.
pVector right = view ^ up;
right.normalize();
pVector nup = right ^ view;
right *= size_scale;
nup *= size_scale;
pVector V0 = -(right + nup);
pVector V1 = V0 + right * 4;
pVector V2 = V0 + nup*4 + right*2;
//cerr << "x " << view.x << " " << view.y << " " << view.z << endl;
//cerr << "x " << nup.x << " " << nup.y << " " << nup.z << endl;
//cerr << "x " << right.x << " " << right.y << " " << right.z << endl;
//cerr << "x " << V0.x << " " << V0.y << " " << V0.z << endl;
//glBegin(GL_TRIANGLES);
gEngfuncs.pTriAPI->Begin( TRI_TRIANGLES );
//gEngfuncs.pTriAPI->RenderMode( kRenderTransAlpha );
for(int i = 0; i < cnt; i++)
{
pVector &p = ppos[i];
float* theCurrentColor = &color[i*4];
if(!const_color)
{
//glColor4fv((GLfloat *)&color[i*4]);
gEngfuncs.pTriAPI->Color4f(theCurrentColor[0], theCurrentColor[1], theCurrentColor[2], theCurrentColor[3]);
}
//else
//{
// gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, .5f);
//}
pVector sV0 = V0;
pVector sV1 = V1;
pVector sV2 = V2;
if(!const_size)
{
sV0 *= size[i].x;
sV1 *= size[i].x;
sV2 *= size[i].x;
}
//if(draw_tex) glTexCoord2f(0,0);
if(draw_tex) gEngfuncs.pTriAPI->TexCoord2f(0,0);
pVector ver = p + sV0;
//glVertex3fv((GLfloat *)&ver);
gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//if(draw_tex) glTexCoord2f(2,0);
if(draw_tex) gEngfuncs.pTriAPI->TexCoord2f(1,0);
ver = p + sV1;
//glVertex3fv((GLfloat *)&ver);
gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//if(draw_tex) glTexCoord2f(0,2);
if(draw_tex) gEngfuncs.pTriAPI->TexCoord2f(.5,1);
ver = p + sV2;
//glVertex3fv((GLfloat *)&ver);
gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
}
//glEnd();
gEngfuncs.pTriAPI->End();
delete [] ppos;
if(color) delete [] color;
if(size) delete [] size;
}
// Emit OpenGL calls to draw the particles. These are drawn with
// whatever primitive type the user specified(GL_POINTS, for
// example). The color and radius are set per primitive, by default.
// For GL_LINES, the other vertex of the line is the velocity vector.
// XXX const_size is ignored.
//PARTICLEDLL_API void pDrawGroupp(int primitive, bool const_size, bool const_color)
//{
// _ParticleState &_ps = _GetPState();
//
// // Get a pointer to the particles in gp memory
// ParticleGroup *pg = _ps.pgrp;
//
// if(pg == NULL)
// return; // ERROR
//
// if(pg->p_count < 1)
// return;
//
// if(primitive == GL_POINTS)
// {
// glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
// glEnableClientState(GL_VERTEX_ARRAY);
// if(!const_color)
// {
// glEnableClientState(GL_COLOR_ARRAY);
// glColorPointer(4, GL_FLOAT, sizeof(Particle), &pg->list[0].color);
// }
//
// glVertexPointer(3, GL_FLOAT, sizeof(Particle), &pg->list[0].pos);
// glDrawArrays((GLenum)primitive, 0, pg->p_count);
// glPopClientAttrib();
// // XXX For E&S
// glDisableClientState(GL_COLOR_ARRAY);
// }
// else
// {
// // Assume GL_LINES
// glBegin((GLenum)primitive);
//
// if(!const_color)
// {
// for(int i = 0; i < pg->p_count; i++)
// {
// Particle &m = pg->list[i];
//
// // Warning: this depends on alpha following color in the Particle struct.
// glColor4fv((GLfloat *)&m.color);
// glVertex3fv((GLfloat *)&m.pos);
//
// // For lines, make a tail with the velocity vector's direction and
// // a length of radius.
// pVector tail = m.pos - m.vel;
// glVertex3fv((GLfloat *)&tail);
// }
// }
// else
// {
// for(int i = 0; i < pg->p_count; i++)
// {
// Particle &m = pg->list[i];
// glVertex3fv((GLfloat *)&m.pos);
//
// // For lines, make a tail with the velocity vector's direction and
// // a length of radius.
// pVector tail = m.pos - m.vel;
// glVertex3fv((GLfloat *)&tail);
// }
// }
// glEnd();
// }
//}
//
//PARTICLEDLL_API void pDrawGroupl(int dlist, bool const_size, bool const_color, bool const_rotation)
//{
// _ParticleState &_ps = _GetPState();
//
// // Get a pointer to the particles in gp memory
// ParticleGroup *pg = _ps.pgrp;
// if(pg == NULL)
// return; // ERROR
//
// if(pg->p_count < 1)
// return;
//
// //if(const_color)
// // glColor4fv((GLfloat *)&pg->list[0].color);
//
// for(int i = 0; i < pg->p_count; i++)
// {
// Particle &m = pg->list[i];
//
// glPushMatrix();
// glTranslatef(m.pos.x, m.pos.y, m.pos.z);
//
// if(!const_size)
// glScalef(m.size.x, m.size.y, m.size.z);
// else
// glScalef(pg->list[i].size.x, pg->list[i].size.y, pg->list[i].size.z);
//
// // Expensive! A sqrt, cross prod and acos. Yow.
// if(!const_rotation)
// {
// pVector vN(m.vel);
// vN.normalize();
// pVector voN(m.velB);
// voN.normalize();
//
// pVector biN;
// if(voN.x == vN.x && voN.y == vN.y && voN.z == vN.z)
// biN = pVector(0, 1, 0);
// else
// biN = vN ^ voN;
// biN.normalize();
//
// pVector N(vN ^ biN);
//
// double M[16];
// M[0] = vN.x; M[4] = biN.x; M[8] = N.x; M[12] = 0;
// M[1] = vN.y; M[5] = biN.y; M[9] = N.y; M[13] = 0;
// M[2] = vN.z; M[6] = biN.z; M[10] = N.z; M[14] = 0;
// M[3] = 0; M[7] = 0; M[11] = 0; M[15] = 1;
// glMultMatrixd(M);
// }
//
// // Warning: this depends on alpha following color in the Particle struct.
// if(!const_color)
// glColor4fv((GLfloat *)&m.color);
//
// glCallList(dlist);
//
// glPopMatrix();
// }
//}

View file

@ -0,0 +1,29 @@
Particle system goals
---------------------
Versatility
Not dependent on Half-life, OpenGL or any particular output device or API
Collision detection with arbitrary areas
This would be nice but isn't necessarily needed
Arbitrary updating of particle source
Ability to hook into Worldcraft or be dynamically generated
As an entity
Ability to have multiple particle systems at once, all with different parameters
Allow static and near-static systems
Volumetric light, haze
Allow custom behavior on collision (less important)
Including altering particle lifetime, draw mode or creation of new particles inheriting characteristics with some randomly alteration
Allows rain that spatters on hit, waterfall that mists
Suggests handle/manager based system
Suggests extendable classes for drawing, updating and iterating through systems
Allow creating of templates which can be named and then later created

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
For SGI we make a version of the library that's made for
multiprocessing in this directory and a version that's made for single
processing in the SP directory. Typing make in this directory will make both.

View file

@ -0,0 +1,391 @@
// action_api.cpp
//
// Copyright 1997-1998 by David K. McAllister
//
// This file implements the action API calls by creating
// action class instances, which are either executed or
// added to an action list.
#include "general.h"
#include "particles/papi.h"
extern void _pAddActionToList(ParticleAction *S, int size);
extern void _pCallActionList(ParticleAction *pa, int num_actions,
ParticleGroup *pg);
// Do not call this function.
void _pSendAction(ParticleAction *S, PActionEnum type, int size)
{
_ParticleState &_ps = _GetPState();
S->type = type;
if(_ps.in_new_list)
{
_pAddActionToList(S, size);
}
else
{
// Immediate mode. Execute it.
// This is a hack to give them local access to dt.
S->dt = _ps.dt;
_pCallActionList(S, 1, _ps.pgrp);
}
}
PARTICLEDLL_API void pAvoid(float magnitude, float epsilon, float look_ahead,
PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PAAvoid S;
S.position = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
S.magnitude = magnitude;
S.epsilon = epsilon;
S.look_ahead = look_ahead;
_pSendAction(&S, PAAvoidID, sizeof(PAAvoid));
}
PARTICLEDLL_API void pBounce(float friction, float resilience, float cutoff,
PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PABounce S;
S.position = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
S.oneMinusFriction = 1.0f - friction;
S.resilience = resilience;
S.cutoffSqr = fsqr(cutoff);
_pSendAction(&S, PABounceID, sizeof(PABounce));
}
PARTICLEDLL_API void pCopyVertexB(bool copy_pos, bool copy_vel)
{
PACopyVertexB S;
S.copy_pos = copy_pos;
S.copy_vel = copy_vel;
_pSendAction(&S, PACopyVertexBID, sizeof(PACopyVertexB));
}
PARTICLEDLL_API void pDamping(float damping_x, float damping_y, float damping_z,
float vlow, float vhigh)
{
PADamping S;
S.damping = pVector(damping_x, damping_y, damping_z);
S.vlowSqr = fsqr(vlow);
S.vhighSqr = fsqr(vhigh);
_pSendAction(&S, PADampingID, sizeof(PADamping));
}
PARTICLEDLL_API void pExplosion(float center_x, float center_y, float center_z, float velocity,
float magnitude, float stdev, float epsilon, float age)
{
PAExplosion S;
S.center = pVector(center_x, center_y, center_z);
S.velocity = velocity;
S.magnitude = magnitude;
S.stdev = stdev;
S.epsilon = epsilon;
S.age = age;
if(S.epsilon < 0.0f)
S.epsilon = P_EPS;
_pSendAction(&S, PAExplosionID, sizeof(PAExplosion));
}
PARTICLEDLL_API void pFollow(float magnitude, float epsilon, float max_radius)
{
PAFollow S;
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAFollowID, sizeof(PAFollow));
}
PARTICLEDLL_API void pGravitate(float magnitude, float epsilon, float max_radius)
{
PAGravitate S;
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAGravitateID, sizeof(PAGravitate));
}
PARTICLEDLL_API void pGravity(float dir_x, float dir_y, float dir_z)
{
PAGravity S;
S.direction = pVector(dir_x, dir_y, dir_z);
_pSendAction(&S, PAGravityID, sizeof(PAGravity));
}
PARTICLEDLL_API void pJet(float center_x, float center_y, float center_z,
float magnitude, float epsilon, float max_radius)
{
_ParticleState &_ps = _GetPState();
PAJet S;
S.center = pVector(center_x, center_y, center_z);
S.acc = _ps.Vel;
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAJetID, sizeof(PAJet));
}
PARTICLEDLL_API void pKillOld(float age_limit, bool kill_less_than)
{
PAKillOld S;
S.age_limit = age_limit;
S.kill_less_than = kill_less_than;
_pSendAction(&S, PAKillOldID, sizeof(PAKillOld));
}
PARTICLEDLL_API void pMatchVelocity(float magnitude, float epsilon, float max_radius)
{
PAMatchVelocity S;
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAMatchVelocityID, sizeof(PAMatchVelocity));
}
PARTICLEDLL_API void pMove()
{
PAMove S;
_pSendAction(&S, PAMoveID, sizeof(PAMove));
}
PARTICLEDLL_API void pOrbitLine(float p_x, float p_y, float p_z,
float axis_x, float axis_y, float axis_z,
float magnitude, float epsilon, float max_radius)
{
PAOrbitLine S;
S.p = pVector(p_x, p_y, p_z);
S.axis = pVector(axis_x, axis_y, axis_z);
S.axis.normalize();
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAOrbitLineID, sizeof(PAOrbitLine));
}
PARTICLEDLL_API void pOrbitPoint(float center_x, float center_y, float center_z,
float magnitude, float epsilon, float max_radius)
{
PAOrbitPoint S;
S.center = pVector(center_x, center_y, center_z);
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAOrbitPointID, sizeof(PAOrbitPoint));
}
PARTICLEDLL_API void pRandomAccel(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PARandomAccel S;
S.gen_acc = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
_pSendAction(&S, PARandomAccelID, sizeof(PARandomAccel));
}
PARTICLEDLL_API void pRandomDisplace(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PARandomDisplace S;
S.gen_disp = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
_pSendAction(&S, PARandomDisplaceID, sizeof(PARandomDisplace));
}
PARTICLEDLL_API void pRandomVelocity(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PARandomVelocity S;
S.gen_vel = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
_pSendAction(&S, PARandomVelocityID, sizeof(PARandomVelocity));
}
PARTICLEDLL_API void pRestore(float time_left)
{
PARestore S;
S.time_left = time_left;
_pSendAction(&S, PARestoreID, sizeof(PARestore));
}
PARTICLEDLL_API void pSink(bool kill_inside, PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PASink S;
S.kill_inside = kill_inside;
S.position = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
_pSendAction(&S, PASinkID, sizeof(PASink));
}
PARTICLEDLL_API void pSinkVelocity(bool kill_inside, PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
PASinkVelocity S;
S.kill_inside = kill_inside;
S.velocity = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
_pSendAction(&S, PASinkVelocityID, sizeof(PASinkVelocity));
}
PARTICLEDLL_API void pSource(float particle_rate, PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
_ParticleState &_ps = _GetPState();
PASource S;
S.particle_rate = particle_rate;
S.position = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
S.positionB = _ps.VertexB;
S.size = _ps.Size;
S.velocity = _ps.Vel;
S.color = _ps.Color;
S.alpha = _ps.Alpha;
S.age = _ps.Age;
S.age_sigma = _ps.AgeSigma;
S.vertexB_tracks = _ps.vertexB_tracks;
_pSendAction(&S, PASourceID, sizeof(PASource));
}
PARTICLEDLL_API void pSpeedLimit(float min_speed, float max_speed)
{
PASpeedLimit S;
S.min_speed = min_speed;
S.max_speed = max_speed;
_pSendAction(&S, PASpeedLimitID, sizeof(PASpeedLimit));
}
PARTICLEDLL_API void pTargetColor(float color_x, float color_y, float color_z,
float alpha, float scale)
{
PATargetColor S;
S.color = pVector(color_x, color_y, color_z);
S.alpha = alpha;
S.scale = scale;
_pSendAction(&S, PATargetColorID, sizeof(PATargetColor));
}
PARTICLEDLL_API void pTargetSize(float size_x, float size_y, float size_z,
float scale_x, float scale_y, float scale_z)
{
PATargetSize S;
S.size = pVector(size_x, size_y, size_z);
S.scale = pVector(scale_x, scale_y, scale_z);
_pSendAction(&S, PATargetSizeID, sizeof(PATargetSize));
}
PARTICLEDLL_API void pTargetVelocity(float vel_x, float vel_y, float vel_z, float scale)
{
PATargetVelocity S;
S.velocity = pVector(vel_x, vel_y, vel_z);
S.scale = scale;
_pSendAction(&S, PATargetVelocityID, sizeof(PATargetVelocity));
}
// If in immediate mode, quickly add a vertex.
// If building an action list, call pSource.
PARTICLEDLL_API void pVertex(float x, float y, float z)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
{
pSource(1, PDPoint, x, y, z);
return;
}
// Immediate mode. Quickly add the vertex.
if(_ps.pgrp == NULL)
return;
pVector pos(x, y, z);
pVector siz, vel, col, posB;
if(_ps.vertexB_tracks)
posB = pos;
else
_ps.VertexB.Generate(posB);
_ps.Size.Generate(siz);
_ps.Vel.Generate(vel);
_ps.Color.Generate(col);
_ps.pgrp->Add(pos, posB, siz, vel, col, _ps.Alpha, _ps.Age);
}
PARTICLEDLL_API void pVortex(float center_x, float center_y, float center_z,
float axis_x, float axis_y, float axis_z,
float magnitude, float epsilon, float max_radius)
{
PAVortex S;
S.center = pVector(center_x, center_y, center_z);
S.axis = pVector(axis_x, axis_y, axis_z);
S.axis.normalize();
S.magnitude = magnitude;
S.epsilon = epsilon;
S.max_radius = max_radius;
_pSendAction(&S, PAVortexID, sizeof(PAVortex));
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,404 @@
// general.h
//
// Copyright 1998 by David K. McAllister.
//
// This file implements the API calls that are not particle actions.
#ifndef general_h
#define general_h
//#include "papi.h"
#include "p_vector.h"
#include "particledefs.h"
#ifdef _WIN32
#pragma warning (disable:4244)
#endif
struct pDomain
{
PDomainEnum type; // PABoxDomain, PASphereDomain, PAConeDomain...
pVector p1, p2; // Box vertices, Sphere center, Cylinder/Cone ends
pVector u, v; // Orthonormal basis vectors for Cylinder/Cone
float radius1; // Outer radius
float radius2; // Inner radius
float radius1Sqr; // Used for fast Within test of spheres,
float radius2Sqr; // and for mag. of u and v vectors for plane.
bool Within(const pVector &) const;
void Generate(pVector &) const;
// This constructor is used when default constructing a
// ParticleAction that has a pDomain.
inline pDomain()
{
}
// Construct a domain in the standard way.
pDomain(PDomainEnum dtype,
float a0=0.0f, float a1=0.0f, float a2=0.0f,
float a3=0.0f, float a4=0.0f, float a5=0.0f,
float a6=0.0f, float a7=0.0f, float a8=0.0f);
};
//////////////////////////////////////////////////////////////////////
// Type codes for all actions
enum PActionEnum
{
PAHeaderID, // The first action in each list.
PAAvoidID, // Avoid entering the domain of space.
PABounceID, // Bounce particles off a domain of space.
PACallActionListID, //
PACopyVertexBID, // Set the secondary position from current position.
PADampingID, // Dampen particle velocities.
PAExplosionID, // An Explosion.
PAFollowID, // Accelerate toward the previous particle in the group.
PAGravitateID, // Accelerate each particle toward each other particle.
PAGravityID, // Acceleration in the given direction.
PAJetID, //
PAKillOldID, //
PAMatchVelocityID, //
PAMoveID, //
PAOrbitLineID, //
PAOrbitPointID, //
PARandomAccelID, //
PARandomDisplaceID, //
PARandomVelocityID, //
PARestoreID, //
PASinkID, //
PASinkVelocityID, //
PASourceID, //
PASpeedLimitID, //
PATargetColorID, //
PATargetSizeID, //
PATargetVelocityID, //
PAVortexID //
};
// This method actually does the particle's action.
#define ExecMethod void Execute(ParticleGroup *pg);
struct ParticleAction
{
static float dt; // This is copied to here from global state.
PActionEnum type; // Type field
};
///////////////////////////////////////////////////////////////////////////
// Data types derived from Action.
struct PAHeader : public ParticleAction
{
int actions_allocated;
int count; // Total actions in the list.
float padding[96]; // This must be the largest action.
ExecMethod
};
struct PAAvoid : public ParticleAction
{
pDomain position; // Avoid region
float look_ahead; // how many time units ahead to look
float magnitude; // what percent of the way to go each time
float epsilon; // add to r^2 for softening
ExecMethod
};
struct PABounce : public ParticleAction
{
pDomain position; // Bounce region
float oneMinusFriction; // Friction tangent to surface
float resilience; // Resilence perpendicular to surface
float cutoffSqr; // cutoff velocity; friction applies iff v > cutoff
ExecMethod
};
struct PACallActionList : public ParticleAction
{
int action_list_num; // The action list number to call
ExecMethod
};
struct PACopyVertexB : public ParticleAction
{
bool copy_pos; // True to copy pos to posB.
bool copy_vel; // True to copy vel to velB.
ExecMethod
};
struct PADamping : public ParticleAction
{
pVector damping; // Damping constant applied to velocity
float vlowSqr; // Low and high cutoff velocities
float vhighSqr;
ExecMethod
};
struct PAExplosion : public ParticleAction
{
pVector center; // The center of the explosion
float velocity; // Of shock wave
float magnitude; // At unit radius
float stdev; // Sharpness or width of shock wave
float age; // How long it's been going on
float epsilon; // Softening parameter
ExecMethod
};
struct PAFollow : public ParticleAction
{
float magnitude; // The grav of each particle
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PAGravitate : public ParticleAction
{
float magnitude; // The grav of each particle
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PAGravity : public ParticleAction
{
pVector direction; // Amount to increment velocity
ExecMethod
};
struct PAJet : public ParticleAction
{
pVector center; // Center of the fan
pDomain acc; // Acceleration vector domain
float magnitude; // Scales acceleration
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PAKillOld : public ParticleAction
{
float age_limit; // Exact age at which to kill particles.
bool kill_less_than; // True to kill particles less than limit.
ExecMethod
};
struct PAMatchVelocity : public ParticleAction
{
float magnitude; // The grav of each particle
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PAMove : public ParticleAction
{
ExecMethod
};
struct PAOrbitLine : public ParticleAction
{
pVector p, axis; // Endpoints of line to which particles are attracted
float magnitude; // Scales acceleration
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PAOrbitPoint : public ParticleAction
{
pVector center; // Point to which particles are attracted
float magnitude; // Scales acceleration
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
struct PARandomAccel : public ParticleAction
{
pDomain gen_acc; // The domain of random accelerations.
ExecMethod
};
struct PARandomDisplace : public ParticleAction
{
pDomain gen_disp; // The domain of random displacements.
ExecMethod
};
struct PARandomVelocity : public ParticleAction
{
pDomain gen_vel; // The domain of random velocities.
ExecMethod
};
struct PARestore : public ParticleAction
{
float time_left; // Time remaining until they should be in position.
ExecMethod
};
struct PASink : public ParticleAction
{
bool kill_inside; // True to dispose of particles *inside* domain
pDomain position; // Disposal region
ExecMethod
};
struct PASinkVelocity : public ParticleAction
{
bool kill_inside; // True to dispose of particles with vel *inside* domain
pDomain velocity; // Disposal region
ExecMethod
};
struct PASpeedLimit : public ParticleAction
{
float min_speed; // Clamp speed to this minimum.
float max_speed; // Clamp speed to this maximum.
ExecMethod
};
struct PASource : public ParticleAction
{
pDomain position; // Choose a position in this domain.
pDomain positionB; // Choose a positionB in this domain.
pDomain size; // Choose a size in this domain.
pDomain velocity; // Choose a velocity in this domain.
pDomain color; // Choose a color in this domain.
float alpha; // Alpha of all generated particles
float particle_rate; // Particles to generate per unit time
float age; // Initial age of the particles
float age_sigma; // St. dev. of initial age of the particles
bool vertexB_tracks; // True to get positionB from position.
ExecMethod
};
struct PATargetColor : public ParticleAction
{
pVector color; // Color to shift towards
float alpha; // Alpha value to shift towards
float scale; // Amount to shift by (1 == all the way)
ExecMethod
};
struct PATargetSize : public ParticleAction
{
pVector size; // Size to shift towards
pVector scale; // Amount to shift by per frame (1 == all the way)
ExecMethod
};
struct PATargetVelocity : public ParticleAction
{
pVector velocity; // Velocity to shift towards
float scale; // Amount to shift by (1 == all the way)
ExecMethod
};
struct PAVortex : public ParticleAction
{
pVector center; // Center of vortex
pVector axis; // Axis around which vortex is applied
float magnitude; // Scale for rotation around axis
float epsilon; // Softening parameter
float max_radius; // Only influence particles within max_radius
ExecMethod
};
// Global state vector
struct _ParticleState
{
float dt;
bool in_call_list;
bool in_new_list;
bool vertexB_tracks;
int group_id;
int list_id;
ParticleGroup *pgrp;
PAHeader *pact;
int tid; // Only used in the MP case, but always define it.
// These are static because all threads access the same groups.
// All accesses to these should be locked.
static ParticleGroup **group_list;
static PAHeader **alist_list;
static int group_count;
static int alist_count;
pDomain Size;
pDomain Vel;
pDomain VertexB;
pDomain Color;
float Alpha;
float Age;
float AgeSigma;
_ParticleState();
// Return an index into the list of particle groups where
// p_group_count groups can be added.
int GenerateGroups(int p_group_count);
int GenerateLists(int alist_count);
ParticleGroup *GetGroupPtr(int p_group_num);
PAHeader *GetListPtr(int action_list_num);
};
#ifdef PARTICLE_MP
// All entry points call this to get their particle state.
inline _ParticleState &_GetPState()
{
// Returns a reference to the appropriate particle state.
extern _ParticleState &_GetPStateWithTID();
return _GetPStateWithTID();
}
#else
// All entry points call this to get their particle state.
// For the non-MP case this is practically a no-op.
inline _ParticleState &_GetPState()
{
// This is the global state.
extern _ParticleState __ps;
return __ps;
}
#endif
// Just a silly little function.
static inline float fsqr(float f) { return f * f; }
#endif

View file

@ -0,0 +1,149 @@
// opengl.cpp
//
// Copyright 1998 by David K. McAllister
//
// This file implements the API calls that draw particle groups in OpenGL.
#include "general.h"
#ifdef WIN32
// This is for something in gl.h.
#include <windows.h>
#endif
#include <GL/gl.h>
// XXX #include <iostream.h>
// Emit OpenGL calls to draw the particles. These are drawn with
// whatever primitive type the user specified(GL_POINTS, for
// example). The color and radius are set per primitive, by default.
// For GL_LINES, the other vertex of the line is the velocity vector.
// XXX const_size is ignored.
PARTICLEDLL_API void pDrawGroupp(int primitive, bool const_size, bool const_color)
{
_ParticleState &_ps = _GetPState();
// Get a pointer to the particles in gp memory
ParticleGroup *pg = _ps.pgrp;
if(pg == NULL)
return; // ERROR
if(pg->p_count < 1)
return;
if(primitive == GL_POINTS)
{
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
if(!const_color)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(Particle), &pg->list[0].color);
}
glVertexPointer(3, GL_FLOAT, sizeof(Particle), &pg->list[0].pos);
glDrawArrays((GLenum)primitive, 0, pg->p_count);
glPopClientAttrib();
// XXX For E&S
glDisableClientState(GL_COLOR_ARRAY);
}
else
{
// Assume GL_LINES
glBegin((GLenum)primitive);
if(!const_color)
{
for(int i = 0; i < pg->p_count; i++)
{
Particle &m = pg->list[i];
// Warning: this depends on alpha following color in the Particle struct.
glColor4fv((GLfloat *)&m.color);
glVertex3fv((GLfloat *)&m.pos);
// For lines, make a tail with the velocity vector's direction and
// a length of radius.
pVector tail = m.pos - m.vel;
glVertex3fv((GLfloat *)&tail);
}
}
else
{
for(int i = 0; i < pg->p_count; i++)
{
Particle &m = pg->list[i];
glVertex3fv((GLfloat *)&m.pos);
// For lines, make a tail with the velocity vector's direction and
// a length of radius.
pVector tail = m.pos - m.vel;
glVertex3fv((GLfloat *)&tail);
}
}
glEnd();
}
}
PARTICLEDLL_API void pDrawGroupl(int dlist, bool const_size, bool const_color, bool const_rotation)
{
_ParticleState &_ps = _GetPState();
// Get a pointer to the particles in gp memory
ParticleGroup *pg = _ps.pgrp;
if(pg == NULL)
return; // ERROR
if(pg->p_count < 1)
return;
//if(const_color)
// glColor4fv((GLfloat *)&pg->list[0].color);
for(int i = 0; i < pg->p_count; i++)
{
Particle &m = pg->list[i];
glPushMatrix();
glTranslatef(m.pos.x, m.pos.y, m.pos.z);
if(!const_size)
glScalef(m.size.x, m.size.y, m.size.z);
else
glScalef(pg->list[i].size.x, pg->list[i].size.y, pg->list[i].size.z);
// Expensive! A sqrt, cross prod and acos. Yow.
if(!const_rotation)
{
pVector vN(m.vel);
vN.normalize();
pVector voN(m.velB);
voN.normalize();
pVector biN;
if(voN.x == vN.x && voN.y == vN.y && voN.z == vN.z)
biN = pVector(0, 1, 0);
else
biN = vN ^ voN;
biN.normalize();
pVector N(vN ^ biN);
double M[16];
M[0] = vN.x; M[4] = biN.x; M[8] = N.x; M[12] = 0;
M[1] = vN.y; M[5] = biN.y; M[9] = N.y; M[13] = 0;
M[2] = vN.z; M[6] = biN.z; M[10] = N.z; M[14] = 0;
M[3] = 0; M[7] = 0; M[11] = 0; M[15] = 1;
glMultMatrixd(M);
}
// Warning: this depends on alpha following color in the Particle struct.
if(!const_color)
glColor4fv((GLfloat *)&m.color);
glCallList(dlist);
glPopMatrix();
}
}

View file

@ -0,0 +1,141 @@
// p_vector.h - yet another vector class.
//
// Copyright 1997 by Jonathan P. Leech
// Modifications Copyright 1997-1999 by David K. McAllister
//
// A simple 3D float vector class for internal use by the particle systems.
#ifndef particle_vector_h
#define particle_vector_h
#include <math.h>
#ifndef M_PI
#define M_PI 3.1415926535897932384626433f
#endif
#ifdef WIN32
#define drand48() (((float) rand())/((float) RAND_MAX))
#define srand48(x) srand(x)
// This is because their stupid compiler thinks it's smart.
#define inline __forceinline
#endif
class pVector
{
public:
float x, y, z;
inline pVector(float ax, float ay, float az) : x(ax), y(ay), z(az)
{
//x = ax; y = ay; z = az;
}
inline pVector() {}
inline float length() const
{
return sqrtf(x*x+y*y+z*z);
}
inline float length2() const
{
return (x*x+y*y+z*z);
}
inline float normalize()
{
float onel = 1.0f / sqrtf(x*x+y*y+z*z);
x *= onel;
y *= onel;
z *= onel;
return onel;
}
inline float operator*(const pVector &a) const
{
return x*a.x + y*a.y + z*a.z;
}
inline pVector operator*(const float s) const
{
return pVector(x*s, y*s, z*s);
}
inline pVector operator/(const float s) const
{
float invs = 1.0f / s;
return pVector(x*invs, y*invs, z*invs);
}
inline pVector operator+(const pVector& a) const
{
return pVector(x+a.x, y+a.y, z+a.z);
}
inline pVector operator-(const pVector& a) const
{
return pVector(x-a.x, y-a.y, z-a.z);
}
inline pVector operator-()
{
x = -x;
y = -y;
z = -z;
return *this;
}
inline pVector& operator+=(const pVector& a)
{
x += a.x;
y += a.y;
z += a.z;
return *this;
}
inline pVector& operator-=(const pVector& a)
{
x -= a.x;
y -= a.y;
z -= a.z;
return *this;
}
inline pVector& operator*=(const float a)
{
x *= a;
y *= a;
z *= a;
return *this;
}
inline pVector& operator/=(const float a)
{
float b = 1.0f / a;
x *= b;
y *= b;
z *= b;
return *this;
}
inline pVector& operator=(const pVector& a)
{
x = a.x;
y = a.y;
z = a.z;
return *this;
}
inline pVector operator^(const pVector& b) const
{
return pVector(
y*b.z-z*b.y,
z*b.x-x*b.z,
x*b.y-y*b.x);
}
};
#endif

View file

@ -0,0 +1,201 @@
// papi.h
//
// Copyright 1997-1998 by David K. McAllister
// http://www.cs.unc.edu/~davemc/Particle
//
// Include this file in all applications that use the Particle System API.
#ifndef _particle_api_h
#define _particle_api_h
#include <stdlib.h>
// This is the major and minor version number of this release of the API.
#define P_VERSION 120
// added <<< cgc >>>
#include <particles/p_vector.h>
#include <particles/general.h>
#include <particles/particledefs.h>
// State setting calls
PARTICLEDLL_API void pColor(float red, float green, float blue, float alpha = 1.0f);
PARTICLEDLL_API void pColorD(float alpha, PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pSize(float size_x, float size_y = 1.0f, float size_z = 1.0f);
PARTICLEDLL_API void pSizeD(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pStartingAge(float age, float sigma = 1.0f);
PARTICLEDLL_API void pTimeStep(float new_dt);
PARTICLEDLL_API void pVelocity(float x, float y, float z);
PARTICLEDLL_API void pVelocityD(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pVertexB(float x, float y, float z);
PARTICLEDLL_API void pVertexBD(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pVertexBTracks(bool track_vertex = true);
// Action List Calls
PARTICLEDLL_API void pCallActionList(int action_list_num);
PARTICLEDLL_API void pDeleteActionLists(int action_list_num, int action_list_count = 1);
PARTICLEDLL_API void pEndActionList();
PARTICLEDLL_API int pGenActionLists(int action_list_count = 1);
PARTICLEDLL_API void pNewActionList(int action_list_num);
// Particle Group Calls
PARTICLEDLL_API ParticleGroup* pGetParticleGroupRef(int p_group_num);
PARTICLEDLL_API void pCopyGroup(int p_src_group_num, int index = 0, int copy_count = P_MAXINT);
PARTICLEDLL_API void pCurrentGroup(int p_group_num);
PARTICLEDLL_API ParticleGroup* pGetCurrentGroup(void);
PARTICLEDLL_API void pDeleteParticleGroups(int p_group_num, int p_group_count = 1);
PARTICLEDLL_API void pDrawGroupl(int dlist, bool const_size = false,
bool const_color = false, bool const_rotation = false);
PARTICLEDLL_API void pDrawGroupp(int primitive, bool const_size = false,
bool const_color = false);
// Added <<< cgc >>>
PARTICLEDLL_API void DrawGroupTriSplat(const pVector &view, const pVector &up, float size_scale = 1.0f, bool draw_tex=false, bool const_size=false, bool const_color=false);
// end
PARTICLEDLL_API int pGenParticleGroups(int p_group_count = 1, int max_particles = 0);
PARTICLEDLL_API int pGetGroupCount();
PARTICLEDLL_API int pGetParticles(int index, int count, float *position = NULL, float *color = NULL,
float *vel = NULL, float *size = NULL, float *age = NULL);
PARTICLEDLL_API int pSetMaxParticles(int max_count);
// Actions
PARTICLEDLL_API void pAvoid(float magnitude, float epsilon, float look_ahead,
PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pBounce(float friction, float resilience, float cutoff,
PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pCopyVertexB(bool copy_pos = true, bool copy_vel = false);
PARTICLEDLL_API void pDamping(float damping_x, float damping_y, float damping_z,
float vlow = 0.0f, float vhigh = P_MAXFLOAT);
PARTICLEDLL_API void pExplosion(float center_x, float center_y, float center_z, float velocity,
float magnitude, float stdev, float epsilon = P_EPS, float age = 0.0f);
PARTICLEDLL_API void pFollow(float magnitude = 1.0f, float epsilon = P_EPS, float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pGravitate(float magnitude = 1.0f, float epsilon = P_EPS, float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pGravity(float dir_x, float dir_y, float dir_z);
PARTICLEDLL_API void pJet(float center_x, float center_y, float center_z, float magnitude = 1.0f,
float epsilon = P_EPS, float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pKillOld(float age_limit, bool kill_less_than = false);
PARTICLEDLL_API void pMatchVelocity(float magnitude = 1.0f, float epsilon = P_EPS,
float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pMove();
PARTICLEDLL_API void pOrbitLine(float p_x, float p_y, float p_z,
float axis_x, float axis_y, float axis_z, float magnitude = 1.0f,
float epsilon = P_EPS, float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pOrbitPoint(float center_x, float center_y, float center_z,
float magnitude = 1.0f, float epsilon = P_EPS,
float max_radius = P_MAXFLOAT);
PARTICLEDLL_API void pRandomAccel(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pRandomDisplace(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pRandomVelocity(PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pRestore(float time);
PARTICLEDLL_API void pShade(float color_x, float color_y, float color_z,
float alpha, float scale);
PARTICLEDLL_API void pSink(bool kill_inside, PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pSinkVelocity(bool kill_inside, PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pSource(float particle_rate, PDomainEnum dtype,
float a0 = 0.0f, float a1 = 0.0f, float a2 = 0.0f,
float a3 = 0.0f, float a4 = 0.0f, float a5 = 0.0f,
float a6 = 0.0f, float a7 = 0.0f, float a8 = 0.0f);
PARTICLEDLL_API void pSpeedLimit(float min_speed, float max_speed = P_MAXFLOAT);
PARTICLEDLL_API void pTargetColor(float color_x, float color_y, float color_z,
float alpha, float scale);
PARTICLEDLL_API void pTargetSize(float size_x, float size_y, float size_z,
float scale_x = 0.0f, float scale_y = 0.0f, float scale_z = 0.0f);
PARTICLEDLL_API void pTargetVelocity(float vel_x, float vel_y, float vel_z, float scale);
PARTICLEDLL_API void pVertex(float x, float y, float z);
PARTICLEDLL_API void pVortex(float center_x, float center_y, float center_z,
float axis_x, float axis_y, float axis_z,
float magnitude = 1.0f, float epsilon = P_EPS,
float max_radius = P_MAXFLOAT);
#endif

View file

@ -0,0 +1,111 @@
// general.h
//
// Copyright 1998 by David K. McAllister.
//
// This file implements the API calls that are not particle actions.
#ifndef particledefs_h
#define particledefs_h
#include "p_vector.h"
#ifdef WIN32
#include <windows.h>
// removed <<< cgc >>>
//#ifdef PARTICLEDLL_EXPORTS
//#define PARTICLEDLL_API __declspec(dllexport)
//#else
//#define PARTICLEDLL_API __declspec(dllimport)
//#endif
#define PARTICLEDLL_API extern "C"
// removed <<< cgc >>>
//#else
//#define PARTICLEDLL_API
#endif
#ifdef _WIN32
#pragma warning (disable:4244)
#endif
// Actually this must be < sqrt(MAXFLOAT) since we store this value squared.
#define P_MAXFLOAT 1.0e16f
#ifdef MAXINT
#define P_MAXINT MAXINT
#else
#define P_MAXINT 0x7fffffff
#endif
#define P_EPS 1e-3f
//////////////////////////////////////////////////////////////////////
// Type codes for domains
PARTICLEDLL_API enum PDomainEnum
{
PDPoint = 0, // Single point
PDLine = 1, // Line segment
PDTriangle = 2, // Triangle
PDPlane = 3, // Arbitrarily-oriented plane
PDBox = 4, // Axis-aligned box
PDSphere = 5, // Sphere
PDCylinder = 6, // Cylinder
PDCone = 7, // Cone
PDBlob = 8, // Gaussian blob
PDDisc = 9, // Arbitrarily-oriented disc
PDRectangle = 10 // Rhombus-shaped planar region
};
// A single particle
struct Particle
{
pVector pos;
pVector posB;
pVector size;
pVector vel;
pVector velB; // Used to compute binormal, normal, etc.
pVector color; // Color must be next to alpha so glColor4fv works.
float alpha; // This is both cunning and scary.
float age;
};
// A group of particles - Info and an array of Particles
struct ParticleGroup
{
int p_count; // Number of particles currently existing.
int max_particles; // Max particles allowed in group.
int particles_allocated; // Actual allocated size.
Particle list[1]; // Actually, num_particles in size
inline void Remove(int i)
{
list[i] = list[--p_count];
}
inline bool Add(const pVector &pos, const pVector &posB,
const pVector &size, const pVector &vel, const pVector &color,
const float alpha = 1.0f,
const float age = 0.0f)
{
if(p_count >= max_particles)
return false;
else
{
list[p_count].pos = pos;
list[p_count].posB = posB;
list[p_count].size = size;
list[p_count].vel = vel;
list[p_count].velB = vel; // XXX This should be fixed.
list[p_count].color = color;
list[p_count].alpha = alpha;
list[p_count].age = age;
p_count++;
return true;
}
}
};
#endif

Binary file not shown.

View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "particles", "particles.vcxproj", "{5AADD469-7488-4B34-A9FD-01CFAC5972FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5AADD469-7488-4B34-A9FD-01CFAC5972FD}.Debug|Win32.ActiveCfg = Debug|Win32
{5AADD469-7488-4B34-A9FD-01CFAC5972FD}.Debug|Win32.Build.0 = Debug|Win32
{5AADD469-7488-4B34-A9FD-01CFAC5972FD}.Release|Win32.ActiveCfg = Release|Win32
{5AADD469-7488-4B34-A9FD-01CFAC5972FD}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Binary file not shown.

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5AADD469-7488-4B34-A9FD-01CFAC5972FD}</ProjectGuid>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>particles</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;..;</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;..;</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<None Include="Overview.txt" />
<None Include="PS Docs.htm">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="Readme.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="general.h" />
<ClInclude Include="papi.h" />
<ClInclude Include="particledefs.h" />
<ClInclude Include="p_vector.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="actions.cpp" />
<ClCompile Include="action_api.cpp" />
<ClCompile Include="HLRender.cpp" />
<ClCompile Include="opengl.cpp" />
<ClCompile Include="system.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="PS Docs.htm" />
<None Include="Overview.txt" />
<None Include="Readme.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="general.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="p_vector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="papi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="particledefs.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="action_api.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="actions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HLRender.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="opengl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="system.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View file

@ -0,0 +1,908 @@
// system.cpp
//
// Copyright 1998 by David K. McAllister.
//
// This file implements the API calls that are not particle actions.
#include "general.h"
#include <memory.h>
// XXX
#include <iostream>
// using namespace std;
// <<< cgc >>> removed DllMain() because I'm linking statically
// For Windows DLL.
//#ifdef WIN32
//BOOL APIENTRY DllMain( HANDLE hModule,
// DWORD ul_reason_for_call,
// LPVOID lpReserved
// )
//{
// switch (ul_reason_for_call)
// {
// case DLL_PROCESS_ATTACH:
// case DLL_THREAD_ATTACH:
// case DLL_THREAD_DETACH:
// case DLL_PROCESS_DETACH:
// break;
// }
// return TRUE;
//}
//#endif
// <<< cgc >>> added this pre-declaration
extern void _pSendAction(ParticleAction *S, PActionEnum type, int size);
float ParticleAction::dt;
ParticleGroup **_ParticleState::group_list;
PAHeader **_ParticleState::alist_list;
int _ParticleState::group_count;
int _ParticleState::alist_count;
// This AutoCall struct allows for static initialization of the above shared variables.
struct AutoCall
{
AutoCall();
};
AutoCall::AutoCall()
{
// The list of groups, etc.
_ParticleState::group_list = new ParticleGroup *[16];
_ParticleState::group_count = 16;
_ParticleState::alist_list = new PAHeader *[16];
_ParticleState::alist_count = 16;
for(int i=0; i<16; i++)
{
_ParticleState::group_list[i] = NULL;
_ParticleState::alist_list[i] = NULL;
}
}
#ifdef PARTICLE_MP
// This code is defined if we are compiling the library to be used on
// multiple threads. We need to have each API call figure out which
// _ParticleState belongs to it. We hash pointers to contexts in
// _CtxHash. Whenever a TID is asked for but doesn't exist we create
// it.
#include <mpc.h>
// XXX This hard limit should get fixed.
int _CtxCount = 151;
_ParticleState **_CtxHash = NULL;
inline int _HashTID(int tid)
{
return ((tid << 13) ^ ((tid >> 11) ^ tid)) % _CtxCount;
}
// Returns a reference to the appropriate particle state.
_ParticleState &_GetPStateWithTID()
{
int tid = mp_my_threadnum();
int ind = _HashTID(tid);
// cerr << tid << "->" << ind << endl;
// Check through the hash table and find it.
for(int i=ind; i<_CtxCount; i++)
if(_CtxHash[i] && _CtxHash[i]->tid == tid)
{
//#pragma critical
//cerr << tid << " => " << i << endl;
return *_CtxHash[i];
}
for(i=0; i<ind; i++)
if(_CtxHash[i] && _CtxHash[i]->tid == tid)
return *_CtxHash[i];
// It didn't exist. It's a new context, so create it.
_ParticleState *psp = new _ParticleState();
psp->tid = tid;
// Find a place to put it.
for(i=ind; i<_CtxCount; i++)
if(_CtxHash[i] == NULL)
{
// #pragma critical
// cerr << "Stored " << tid << " at " << i << endl;
_CtxHash[i] = psp;
return *psp;
}
for(i=0; i<ind; i++)
if(_CtxHash[i] == NULL)
{
_CtxHash[i] = psp;
return *psp;
}
// We should never get here. The hash table got full.
exit(1);
// To appease warnings.
return *_CtxHash[0];
}
inline void _PLock()
{
// XXX This implementation is specific to the #pragma parallel directives.
// cerr << "Getting lock.\n";
// mp_setlock();
// cerr << "Got lock.\n";
}
inline void _PUnLock()
{
// XXX This implementation is specific to the #pragma parallel directives.
// cerr << "Giving lock.\n";
// mp_unsetlock();
// cerr << "Gave lock.\n";
}
#else
// This is the global state.
_ParticleState __ps;
inline void _PLock()
{
}
inline void _PUnLock()
{
}
#endif
_ParticleState::_ParticleState()
{
in_call_list = false;
in_new_list = false;
vertexB_tracks = true;
dt = 1.0f;
group_id = -1;
list_id = -1;
pgrp = NULL;
pact = NULL;
tid = 0; // This will be filled in above if we're MP.
Size = pDomain(PDPoint, 1.0f, 1.0f, 1.0f);
Vel = pDomain(PDPoint, 0.0f, 0.0f, 0.0f);
VertexB = pDomain(PDPoint, 0.0f, 0.0f, 0.0f);
Color = pDomain(PDPoint, 1.0f, 1.0f, 1.0f);
Alpha = 1.0f;
Age = 0.0f;
AgeSigma = 0.0f;
}
ParticleGroup *_ParticleState::GetGroupPtr(int p_group_num)
{
if(p_group_num < 0)
return NULL; // IERROR
if(p_group_num >= group_count)
return NULL; // IERROR
return group_list[p_group_num];
}
PAHeader *_ParticleState::GetListPtr(int a_list_num)
{
if(a_list_num < 0)
return NULL; // IERROR
if(a_list_num >= alist_count)
return NULL; // IERROR
return alist_list[a_list_num];
}
// Return an index into the list of particle groups where
// p_group_count groups can be added.
int _ParticleState::GenerateGroups(int p_group_count)
{
int num_empty = 0;
int first_empty = -1;
for(int i=0; i<group_count; i++)
{
if(group_list[i])
{
num_empty = 0;
first_empty = -1;
}
else
{
if(first_empty < 0)
first_empty = i;
num_empty++;
if(num_empty >= p_group_count)
return first_empty;
}
}
// Couldn't find a big enough gap. Reallocate.
int new_count = 16 + group_count + p_group_count;
ParticleGroup **glist = new ParticleGroup *[new_count];
memcpy(glist, group_list, group_count * sizeof(void*));
for(int i=group_count; i<new_count; i++)
glist[i] = NULL;
delete [] group_list;
group_list = glist;
group_count = new_count;
return GenerateGroups(p_group_count);
}
// Return an index into the list of action lists where
// list_count lists can be added.
int _ParticleState::GenerateLists(int list_count)
{
int num_empty = 0;
int first_empty = -1;
for(int i=0; i<alist_count; i++)
{
if(alist_list[i])
{
num_empty = 0;
first_empty = -1;
}
else
{
if(first_empty < 0)
first_empty = i;
num_empty++;
if(num_empty >= list_count)
return first_empty;
}
}
// Couldn't find a big enough gap. Reallocate.
int new_count = 16 + alist_count + list_count;
PAHeader **new_list = new PAHeader *[new_count];
memcpy(new_list, alist_list, alist_count * sizeof(void*));
for(int i=list_count; i<new_count; i++)
new_list[i] = NULL;
delete [] alist_list;
alist_list = new_list;
alist_count = new_count;
return GenerateLists(list_count);
}
////////////////////////////////////////////////////////
// Auxiliary calls
void _pCallActionList(ParticleAction *apa, int num_actions,
ParticleGroup *pg)
{
// All these require a particle group, so check for it.
if(pg == NULL)
return;
PAHeader *pa = (PAHeader *)apa;
// Step through all the actions in the action list.
for(int action = 0; action < num_actions; action++, pa++)
{
switch(pa->type)
{
case PAAvoidID:
((PAAvoid *)pa)->Execute(pg);
break;
case PABounceID:
((PABounce *)pa)->Execute(pg);
break;
case PACallActionListID:
((PACallActionList *)pa)->Execute(pg);
break;
case PACopyVertexBID:
((PACopyVertexB *)pa)->Execute(pg);
break;
case PADampingID:
((PADamping *)pa)->Execute(pg);
break;
case PAExplosionID:
((PAExplosion *)pa)->Execute(pg);
break;
case PAFollowID:
((PAFollow *)pa)->Execute(pg);
break;
case PAGravitateID:
((PAGravitate *)pa)->Execute(pg);
break;
case PAGravityID:
((PAGravity *)pa)->Execute(pg);
break;
case PAJetID:
((PAJet *)pa)->Execute(pg);
break;
case PAKillOldID:
((PAKillOld *)pa)->Execute(pg);
break;
case PAMatchVelocityID:
((PAMatchVelocity *)pa)->Execute(pg);
break;
case PAMoveID:
((PAMove *)pa)->Execute(pg);
break;
case PAOrbitLineID:
((PAOrbitLine *)pa)->Execute(pg);
break;
case PAOrbitPointID:
((PAOrbitPoint *)pa)->Execute(pg);
break;
case PARandomAccelID:
((PARandomAccel *)pa)->Execute(pg);
break;
case PARandomDisplaceID:
((PARandomDisplace *)pa)->Execute(pg);
break;
case PARandomVelocityID:
((PARandomVelocity *)pa)->Execute(pg);
break;
case PARestoreID:
((PARestore *)pa)->Execute(pg);
break;
case PASinkID:
((PASink *)pa)->Execute(pg);
break;
case PASinkVelocityID:
((PASinkVelocity *)pa)->Execute(pg);
break;
case PASourceID:
((PASource *)pa)->Execute(pg);
break;
case PASpeedLimitID:
((PASpeedLimit *)pa)->Execute(pg);
break;
case PATargetColorID:
((PATargetColor *)pa)->Execute(pg);
break;
case PATargetSizeID:
((PATargetSize *)pa)->Execute(pg);
break;
case PATargetVelocityID:
((PATargetVelocity *)pa)->Execute(pg);
break;
case PAVortexID:
((PAVortex *)pa)->Execute(pg);
break;
}
}
}
// Add the incoming action to the end of the current action list.
void _pAddActionToList(ParticleAction *S, int size)
{
_ParticleState &_ps = _GetPState();
if(!_ps.in_new_list)
return; // ERROR
if(_ps.pact == NULL)
return; // ERROR
if(_ps.list_id < 0)
return; // ERROR
PAHeader *alist = _ps.pact;
if(alist->actions_allocated <= alist->count)
{
// Must reallocate.
int new_alloc = 16 + alist->actions_allocated;
PAHeader *new_alist = new PAHeader[new_alloc];
memcpy(new_alist, alist, alist->count * sizeof(PAHeader));
delete [] alist;
_ps.alist_list[_ps.list_id] = _ps.pact = alist = new_alist;
alist->actions_allocated = new_alloc;
}
// Now add it in.
memcpy(&alist[alist->count], S, size);
alist->count++;
}
////////////////////////////////////////////////////////
// State setting calls
PARTICLEDLL_API void pColor(float red, float green, float blue, float alpha)
{
_ParticleState &_ps = _GetPState();
_ps.Alpha = alpha;
_ps.Color = pDomain(PDPoint, red, green, blue);
}
PARTICLEDLL_API void pColorD(float alpha, PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
_ParticleState &_ps = _GetPState();
_ps.Alpha = alpha;
_ps.Color = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
}
PARTICLEDLL_API void pVelocity(float x, float y, float z)
{
_ParticleState &_ps = _GetPState();
_ps.Vel = pDomain(PDPoint, x, y, z);
}
PARTICLEDLL_API void pVelocityD(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
_ParticleState &_ps = _GetPState();
_ps.Vel = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
}
PARTICLEDLL_API void pVertexB(float x, float y, float z)
{
_ParticleState &_ps = _GetPState();
_ps.VertexB = pDomain(PDPoint, x, y, z);
}
PARTICLEDLL_API void pVertexBD(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
_ParticleState &_ps = _GetPState();
_ps.VertexB = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
}
PARTICLEDLL_API void pVertexBTracks(bool trackVertex)
{
_ParticleState &_ps = _GetPState();
_ps.vertexB_tracks = trackVertex;
}
PARTICLEDLL_API void pSize(float size_x, float size_y, float size_z)
{
_ParticleState &_ps = _GetPState();
_ps.Size = pDomain(PDPoint, size_x, size_y, size_z);
}
PARTICLEDLL_API void pSizeD(PDomainEnum dtype,
float a0, float a1, float a2,
float a3, float a4, float a5,
float a6, float a7, float a8)
{
_ParticleState &_ps = _GetPState();
_ps.Size = pDomain(dtype, a0, a1, a2, a3, a4, a5, a6, a7, a8);
}
PARTICLEDLL_API void pStartingAge(float age, float sigma)
{
_ParticleState &_ps = _GetPState();
_ps.Age = age;
_ps.AgeSigma = sigma;
}
PARTICLEDLL_API void pTimeStep(float newDT)
{
_ParticleState &_ps = _GetPState();
_ps.dt = newDT;
}
////////////////////////////////////////////////////////
// Action List Calls
PARTICLEDLL_API int pGenActionLists(int action_list_count)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return -1; // ERROR
_PLock();
int ind = _ps.GenerateLists(action_list_count);
for(int i=ind; i<ind+action_list_count; i++)
{
_ps.alist_list[i] = new PAHeader[8];
_ps.alist_list[i]->actions_allocated = 8;
_ps.alist_list[i]->type = PAHeaderID;
_ps.alist_list[i]->count = 1;
}
_PUnLock();
return ind;
}
PARTICLEDLL_API void pNewActionList(int action_list_num)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return; // ERROR
_ps.pact = _ps.GetListPtr(action_list_num);
if(_ps.pact == NULL)
return; // ERROR
_ps.list_id = action_list_num;
_ps.in_new_list = true;
// Remove whatever used to be in the list.
_ps.pact->count = 1;
}
PARTICLEDLL_API void pEndActionList()
{
_ParticleState &_ps = _GetPState();
if(!_ps.in_new_list)
return; // ERROR
_ps.in_new_list = false;
_ps.pact = NULL;
_ps.list_id = -1;
}
PARTICLEDLL_API void pDeleteActionLists(int action_list_num, int action_list_count)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return; // ERROR
if(action_list_num < 0)
return; // ERROR
if(action_list_num + action_list_count > _ps.alist_count)
return; // ERROR
_PLock();
for(int i = action_list_num; i < action_list_num + action_list_count; i++)
{
if(_ps.alist_list[i])
{
delete [] _ps.alist_list[i];
_ps.alist_list[i] = NULL;
}
else
{
_PUnLock();
return; // ERROR
}
}
_PUnLock();
}
PARTICLEDLL_API void pCallActionList(int action_list_num)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
{
// Add this call as an action to the current list.
// <<< cgc >>> commented out predeclaration
//void _pSendAction(ParticleAction *S, PActionEnum type, int size);
PACallActionList S;
S.action_list_num = action_list_num;
_pSendAction(&S, PACallActionListID, sizeof(PACallActionList));
}
else
{
// Execute the specified action list.
PAHeader *pa = _ps.GetListPtr(action_list_num);
if(pa == NULL)
return; // ERRROR
// XXX A temporary hack.
pa->dt = _ps.dt;
_ps.in_call_list = true;
_pCallActionList(pa+1, pa->count-1, _ps.pgrp);
_ps.in_call_list = false;
}
}
////////////////////////////////////////////////////////
// Particle Group Calls
// Create particle groups, each with max_particles allocated.
PARTICLEDLL_API int pGenParticleGroups(int p_group_count, int max_particles)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return -1; // ERROR
_PLock();
// cerr << "Generating pg " << _ps.tid << " cnt= " << max_particles << endl;
int ind = _ps.GenerateGroups(p_group_count);
for(int i=ind; i<ind+p_group_count; i++)
{
_ps.group_list[i] = (ParticleGroup *)new
Particle[max_particles + 2];
_ps.group_list[i]->max_particles = max_particles;
_ps.group_list[i]->particles_allocated = max_particles;
_ps.group_list[i]->p_count = 0;
}
_PUnLock();
return ind;
}
PARTICLEDLL_API void pDeleteParticleGroups(int p_group_num, int p_group_count)
{
_ParticleState &_ps = _GetPState();
if(p_group_num < 0)
return; // ERROR
if(p_group_num + p_group_count > _ps.group_count)
return; // ERROR
_PLock();
for(int i = p_group_num; i < p_group_num + p_group_count; i++)
{
if(_ps.group_list[i])
{
delete [] _ps.group_list[i];
_ps.group_list[i] = NULL;
}
else
{
_PUnLock();
return; // ERROR
}
}
_PUnLock();
}
// Change which group is current.
PARTICLEDLL_API void pCurrentGroup(int p_group_num)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return; // ERROR
_ps.pgrp = _ps.GetGroupPtr(p_group_num);
if(_ps.pgrp)
_ps.group_id = p_group_num;
else
_ps.group_id = -1;
}
PARTICLEDLL_API ParticleGroup* pGetCurrentGroup(void)
{
_ParticleState &_ps = _GetPState();
ParticleGroup *pg = _ps.pgrp;
return pg;
}
// Change the maximum number of particles in the current group.
PARTICLEDLL_API int pSetMaxParticles(int max_count)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return 0; // ERROR
ParticleGroup *pg = _ps.pgrp;
if(pg == NULL)
return 0; // ERROR
if(max_count < 0)
return 0; // ERROR
// Reducing max.
if(pg->particles_allocated >= max_count)
{
pg->max_particles = max_count;
// May have to kill particles.
if(pg->p_count > pg->max_particles)
pg->p_count = pg->max_particles;
return max_count;
}
_PLock();
// Allocate particles.
ParticleGroup *pg2 =(ParticleGroup *)new Particle[max_count + 2];
if(pg2 == NULL)
{
// Not enough memory. Just give all we've got.
// ERROR
pg->max_particles = pg->particles_allocated;
_PUnLock();
return pg->max_particles;
}
memcpy(pg2, pg, (pg->p_count + 2) * sizeof(Particle));
delete [] pg;
_ps.group_list[_ps.group_id] = _ps.pgrp = pg2;
pg2->max_particles = max_count;
pg2->particles_allocated = max_count;
_PUnLock();
return max_count;
}
// Copy from the specified group to the current group.
PARTICLEDLL_API void pCopyGroup(int p_src_group_num, int index, int copy_count)
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return; // ERROR
ParticleGroup *srcgrp = _ps.GetGroupPtr(p_src_group_num);
if(srcgrp == NULL)
return; // ERROR
ParticleGroup *destgrp = _ps.pgrp;
if(destgrp == NULL)
return; // ERROR
// Find out exactly how many to copy.
int ccount = copy_count;
if(ccount > srcgrp->p_count - index)
ccount = srcgrp->p_count - index;
if(ccount > destgrp->max_particles - destgrp->p_count)
ccount = destgrp->max_particles - destgrp->p_count;
// #pragma critical
// cerr << p_src_group_num << ": " << ccount << " " << srcgrp->p_count << " " << index << endl;
if(ccount<0)
ccount = 0;
// Directly copy the particles to the current list.
for(int i=0; i<ccount; i++)
{
destgrp->list[destgrp->p_count+i] =
srcgrp->list[index+i];
}
destgrp->p_count += ccount;
}
PARTICLEDLL_API ParticleGroup* pGetParticleGroupRef(int p_group_num)
{
ParticleGroup* theGroup = NULL;
_ParticleState &_ps = _GetPState();
if(!_ps.in_new_list)
{
theGroup = _ps.GetGroupPtr(p_group_num);
}
return theGroup;
}
// Copy from the current group to application memory.
PARTICLEDLL_API int pGetParticles(int index, int count, float *verts,
float *color, float *vel, float *size, float *age)
{
_ParticleState &_ps = _GetPState();
// XXX I should think about whether color means color3, color4, or what.
// For now, it means color4.
if(_ps.in_new_list)
return -1; // ERROR
ParticleGroup *pg = _ps.pgrp;
if(pg == NULL)
return -2; // ERROR
if(index < 0 || count < 0)
return -3; // ERROR
if(index + count > pg->p_count)
{
count = pg->p_count - index;
if(count <= 0)
return -4; // ERROR index out of bounds.
}
int vi = 0, ci = 0, li = 0, si = 0, ai = 0;
// This could be optimized.
for(int i=0; i<count; i++)
{
Particle &m = pg->list[index + i];
if(verts)
{
verts[vi++] = m.pos.x;
verts[vi++] = m.pos.y;
verts[vi++] = m.pos.z;
}
if(color)
{
color[ci++] = m.color.x;
color[ci++] = m.color.y;
color[ci++] = m.color.z;
color[ci++] = m.alpha;
}
if(vel)
{
vel[li++] = m.vel.x;
vel[li++] = m.vel.y;
vel[li++] = m.vel.z;
}
if(size)
{
size[si++] = m.size.x;
size[si++] = m.size.y;
size[si++] = m.size.z;
}
if(age)
{
age[ai++] = m.age;
}
}
return count;
}
// Returns the number of particles currently in the group.
PARTICLEDLL_API int pGetGroupCount()
{
_ParticleState &_ps = _GetPState();
if(_ps.in_new_list)
return 0; // ERROR
if(_ps.pgrp == NULL)
return 0; // ERROR
return _ps.pgrp->p_count;
}