mirror of
https://github.com/unknownworlds/NS.git
synced 2024-12-11 05:10:56 +00:00
b5590dd5d9
git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@144 67975925-1194-0748-b3d5-c16f83f1a3a1
908 lines
19 KiB
C++
908 lines
19 KiB
C++
// 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.h>
|
|
// 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(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(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;
|
|
}
|