deargui-vpl/ref/virtools/Samples/Behaviors/ParticlesSystem/behaviors src/GeneralParticleSystem.cpp

685 lines
20 KiB
C++
Raw Blame History

/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//
// GeneralParticleSystem
//
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#include "CKAll.h"
#include "GeneralParticleSystem.h"
#define INACTIVE 0
#define ACTIVE 1
#define FREEZED 2
#ifdef USE_THR
// ACC - July 10,2002
BlockingQueue<ThreadParam> PSqueue(40);
FILE *ACCLOG;
VxMutex logguard;
#endif
#include <stdio.h>
const CKSTRING RadialParticleOffsetStr = "Radial particle offset";
CKERROR CreateGeneralParticleSystemProto(CKBehaviorPrototype **);
int GeneralParticleSystem(const CKBehaviorContext& behcontext);
CKERROR GeneralParticleSystemCallback(const CKBehaviorContext& behcontext);
void EmitterSetMesh(BOOL Set,CKGUID guid,CKBehavior* beh,ParticleEmitter *em);
CKERROR CreateGeneralParticleSystemProto(CKBehaviorPrototype **pproto)
{
CKBehaviorPrototype *proto = CreateCKBehaviorPrototype(ParticleSystemsName);
if(!proto) return CKERR_OUTOFMEMORY;
proto->DeclareInput("On");
proto->DeclareInput("Off");
proto->DeclareInput("Freeze");
proto->DeclareOutput("Exit On");
proto->DeclareOutput("Exit Off");
proto->DeclareOutput("Exit Freeze");
proto->DeclareInParameter("Emission Delay",CKPGUID_TIME,"0m 0s 200ms");
proto->DeclareInParameter("Emission Delay Variance",CKPGUID_TIME,"0m 0s 0ms");
proto->DeclareInParameter("Yaw Variance",CKPGUID_ANGLE,"0:20");
proto->DeclareInParameter("Pitch Variance",CKPGUID_ANGLE,"0:20");
proto->DeclareInParameter("Speed",CKPGUID_FLOAT,"0.005");
proto->DeclareInParameter("Speed Variance",CKPGUID_FLOAT,"0.001");
proto->DeclareInParameter("Angular Speed/Spreading",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Angular Speed Variance/Spreading Variation",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Lifespan",CKPGUID_TIME,"0m 1s 0ms");
proto->DeclareInParameter("Lifespan Variance",CKPGUID_TIME,"0m 0s 250ms");
proto->DeclareInParameter("Maximum Number",CKPGUID_INT,"100");
proto->DeclareInParameter("Emission",CKPGUID_INT,"10");
proto->DeclareInParameter("Emission Variance",CKPGUID_INT,"5");
proto->DeclareInParameter("Initial Size",CKPGUID_FLOAT,"1.0");
proto->DeclareInParameter("Initial Size Variance",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Ending Size",CKPGUID_FLOAT,"0.1");
proto->DeclareInParameter("Ending Size Variance",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Bounce",CKPGUID_FLOAT,"0.8");
proto->DeclareInParameter("Bounce Variance",CKPGUID_FLOAT,"0");
proto->DeclareInParameter("Weight",CKPGUID_FLOAT,"1.0");
proto->DeclareInParameter("Weight Variance",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Surface",CKPGUID_FLOAT,"1.0");
proto->DeclareInParameter("Surface Variance",CKPGUID_FLOAT,"0.0");
proto->DeclareInParameter("Initial Color and Alpha",CKPGUID_COLOR,"255,255,255,255");
proto->DeclareInParameter("Variance",CKPGUID_COLOR,"0,0,0,0");
proto->DeclareInParameter("Ending Color and Alpha",CKPGUID_COLOR,"0,0,0,0");
proto->DeclareInParameter("Variance",CKPGUID_COLOR,"0,0,0,0");
proto->DeclareInParameter("Texture",CKPGUID_TEXTURE);
proto->DeclareInParameter("Initial Texture Frame",CKPGUID_INT,"0");
proto->DeclareInParameter("Initial Texture Frame Variance",CKPGUID_INT,"0");
proto->DeclareInParameter("Texture Speed",CKPGUID_INT,"100");
proto->DeclareInParameter("Texture Speed Variance",CKPGUID_INT,"20");
proto->DeclareInParameter("Texture Frame Count",CKPGUID_INT,"1");
proto->DeclareInParameter("Texture Loop",CKPGUID_LOOPMODE,"No Loop");
proto->DeclareInParameter("Start Time",CKPGUID_TIME,"0m 0s 0ms");
proto->DeclareLocalParameter("Emitter",CKPGUID_VOIDBUF);
proto->DeclareLocalParameter("Activity",CKPGUID_INT);
proto->DeclareLocalParameter("EmissionTime",CKPGUID_FLOAT,"0");
// Settings
proto->DeclareSetting("Maximum Number",CKPGUID_INT,"100");
proto->DeclareSetting("Particle Rendering",CKPGUID_RENDERMODES,"3");
proto->DeclareSetting("Source Blend",CKPGUID_BLENDFACTOR,"Source Alpha");
proto->DeclareSetting("Destination Blend",CKPGUID_BLENDFACTOR,"One");
proto->DeclareSetting("Objects",CKPGUID_GROUP);
proto->DeclareSetting("Evolutions",CKPGUID_EVOLUTIONS,"Color,Size,Texture");
proto->DeclareSetting("Variances",CKPGUID_VARIANCES,"Speed,Angular Speed,Lifespan,Emission,Initial Size,Ending Size,Bounce,Weight,Surface,Initial Color,Ending Color,Initial Texture,Texture Speed");
proto->DeclareSetting("Manage Deflectors",CKPGUID_DEFLECTORS,"Plane,Infinite Plane,Cylinder,Sphere,Box,Object");
proto->DeclareSetting("Message To Deflectors",CKPGUID_MESSAGE,"NULL");
proto->DeclareSetting("Manage Interactors",CKPGUID_INTERACTORS,"Gravity,Global Wind,Local Wind,Magnet,Vortex,Disruption Box,Mutation Box,Atmosphere,Tunnel,Projector");
proto->DeclareSetting("Interactors/Deflectors Display",CKPGUID_BOOL,"TRUE");
proto->DeclareSetting("Output Particle Count",CKPGUID_BOOL,"FALSE");
proto->DeclareSetting("Trail Particle Count",CKPGUID_INT,"0");
proto->DeclareSetting("Visible In Pause",CKPGUID_BOOL,"FALSE");
proto->DeclareSetting(RadialParticleOffsetStr, CKPGUID_FLOAT, "0");
proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL);
proto->SetFunction(GeneralParticleSystem);
proto->SetBehaviorCallbackFct( GeneralParticleSystemCallback );
proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)(CKBEHAVIOR_INTERNALLYCREATEDOUTPUTPARAMS|CKBEHAVIOR_INTERNALLYCREATEDINPUTS|CKBEHAVIOR_INTERNALLYCREATEDOUTPUTS));
*pproto = proto;
return CK_OK;
}
// Helper function : test if both the script and the target behavioral object are active in the current scene
static inline bool AreScriptAndTargetActiveInScene(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
if (beh->IsParentScriptActiveInScene(behcontext.CurrentScene) && beh->IsActive())
{
if (behcontext.CurrentScene->GetObjectFlags(beh->GetTarget()) & CK_SCENEOBJECT_ACTIVE)
{
return true;
}
}
return false;
}
////
// Function to warm up the particles before the actual start of rendering
// thanx to Daniel Fournier from Microids Canada
void WarmUpParticles(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
float startTime = 0;
beh->GetInputParameterValue(STARTTIME,&startTime);
if (startTime < EPSILON) // No warmup to do
return;
CKContext* ctx = behcontext.Context;
CKGUID guid = beh->GetPrototypeGuid();
// We get the emitter
ParticleEmitter *pe = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!pe) return;
CK3dEntity* entity = (CK3dEntity*)ctx->GetObject(pe->m_Entity);
// We get the activity
// Reading Inputs
pe->ReadInputs(beh);
// shape of emitter object
if(guid == OBJECTSYSTEM_GUID) {
((ObjectEmitter*)pe)->m_Shape = entity->GetCurrentMesh();
}
// We create new particles only if we are active
float emissiondelay = 0.0f;
beh->GetInputParameterValue(EMISSIONDELAY,&emissiondelay);
float deltaTime = 20.0f;
// we start cum at the emission delay to have right at the start something
for (float time = 0.f, cum = emissiondelay; time < startTime; time += deltaTime) {
if( emissiondelay > EPSILON ) { // linked with time
while (cum >= emissiondelay)
{
pe->AddParticles();
cum -= emissiondelay;
}
cum += deltaTime;
} else { // Not linked with time
pe->AddParticles();
}
// We update the particles (position, color, size...)
pe->UpdateParticles(deltaTime);
}
}
void ShowParticles(CKBehavior* beh, CKBOOL show)
{
CKGUID guid = beh->GetPrototypeGuid();
// We get the emitter
ParticleEmitter *pe = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!pe) return;
// we now set the good mesh of the emitter
if (show) EmitterSetMesh(FALSE,guid,beh,pe);
CK3dEntity* entity = (CK3dEntity*)beh->GetCKObject(pe->m_Entity);
if (!entity) return;
entity->RemovePostRenderCallBack(RenderParticles_P,pe);
entity->RemovePostRenderCallBack(RenderParticles_L,pe);
entity->RemovePostRenderCallBack(RenderParticles_LL,pe);
entity->RemovePostRenderCallBack(RenderParticles_S,pe);
entity->RemovePostRenderCallBack(RenderParticles_LS,pe);
entity->RemovePostRenderCallBack(RenderParticles_O,pe);
entity->RemovePostRenderCallBack(RenderParticles_FS,pe);
entity->RemovePostRenderCallBack(RenderParticles_OS,pe);
entity->RemovePostRenderCallBack(RenderParticles_LOS,pe);
entity->RemovePostRenderCallBack(RenderParticles_CS,pe);
entity->RemovePostRenderCallBack(RenderParticles_RS,pe);
entity->RemovePostRenderCallBack(RenderParticles_PS,pe);
entity->RemovePostRenderCallBack(RenderParticles_FPS,pe);
if (show) {
entity->AddPostRenderCallBack(pe->m_RenderParticlesCallback, pe );
}
}
#ifdef USE_THR
// ACC - July 10, 2002
int UpdateParticleSystemEnqueue(ParticleEmitter* aPE, float aDeltaTime)
{
ThreadParam ThrParam;
ThrParam.pe = aPE;
ThrParam.DeltaTime = aDeltaTime;
ResetEvent(aPE->hasBeenComputedEvent);
aPE->hasBeenEnqueud = true;
PSqueue.Add(ThrParam);
return 0;
}
HANDLE hPSthread;
DWORD WINAPI PSWorkerThreadFunc(LPVOID junk)
{
// Forever loop
for(;;){
#ifdef MT_VERB
{
VxMutexLock lock (logguard);
fprintf(ACCLOG, "About to remove Thread param: count=%d\n", PSqueue.NumItems());
fflush(ACCLOG);
}
#endif
// This can block when queue is empty
ThreadParam currParam = PSqueue.Remove();
ParticleEmitter* pe = currParam.pe;
CKBehavior* beh = currParam.pe->m_Behavior;
#ifdef MT_VERB
{
VxMutexLock lock (logguard);
fprintf(ACCLOG, "Removed a Thread param: count=%d\n", PSqueue.NumItems());
fflush(ACCLOG);
}
#endif
//CKContext* ctx = beh->GetCKContext();
//ctx->OutputToConsoleEx(
pe->UpdateParticles(currParam.DeltaTime);
if (pe->m_CurrentImpact < pe->m_Impacts.Size()) {
beh->SetOutputParameterValue(0,&pe->m_Impacts[pe->m_CurrentImpact].m_Position);
beh->SetOutputParameterValue(1,&pe->m_Impacts[pe->m_CurrentImpact].m_Direction);
beh->SetOutputParameterObject(2,pe->m_Impacts[pe->m_CurrentImpact].m_Object);
beh->SetOutputParameterValue(3,&pe->m_Impacts[pe->m_CurrentImpact].m_UVs);
pe->m_CurrentImpact++;
beh->ActivateOutput(3);
}
pe->hasBeenEnqueud = false;
SetEvent(pe->hasBeenComputedEvent);
#ifdef MT_VERB
{
VxMutexLock lock (logguard);
fprintf(ACCLOG, "Setevent pe=%p\n", pe);
fflush(ACCLOG);
}
#endif
}
}
#endif // USE_THR
int GeneralParticleSystem(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
CKContext* ctx = behcontext.Context;
CKGUID guid = beh->GetPrototypeGuid();
// We get the emitter
ParticleEmitter *pe = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!pe) return CKBR_PARAMETERERROR;
pe->m_Behavior = beh;
pe->hasBeenRendered = false; //initialize every frame
CK3dEntity* entity = (CK3dEntity*)ctx->GetObject(pe->m_Entity);
// We get the activity
int activity = 0;
beh->GetLocalParameterValue(1,&activity);
if (beh->IsInputActive(3)) {
beh->ActivateInput(3,FALSE);
} else {
// Freezed Input
if (beh->IsInputActive(2)) {
beh->ActivateInput(2,FALSE);
beh->ActivateOutput(2);
// it it was reezed, we unfreeze it
if(activity & FREEZED) activity &= ~FREEZED;
else activity |= FREEZED;
} else {
// Activate input
if (beh->IsInputActive(0)) {
beh->ActivateInput(0,FALSE);
beh->ActivateOutput(0);
#ifdef USE_THR
// ACC, This is the point to create function
static bool isThreadCreated = false;
if(!isThreadCreated){
// Hijack this to create logfile
ACCLOG = fopen("\\acclog.txt", "w");
assert(ACCLOG != NULL);
hPSthread = CreateThread(NULL, NULL, PSWorkerThreadFunc, NULL,
0, NULL); // w2k/xp specific
isThreadCreated=true;
}
#endif
// we write the emission time to 0
float emissiontime = 0.0f;
beh->GetInputParameterValue(EMISSIONDELAY,&emissiontime); // we init the time with the delay to have one particle emitted at the activation
beh->SetLocalParameterValue(2,&emissiontime);
WarmUpParticles(behcontext);
activity |= ACTIVE;
ShowParticles(beh);
} else {
// Inactivate input
if (beh->IsInputActive(1)) {
beh->ActivateInput(1,FALSE);
activity = INACTIVE;
}
}
}
// we save the activity
beh->SetLocalParameterValue(1,&activity);
if(activity & FREEZED) {
return CKBR_OK;
}
// Reading Inputs
pe->ReadInputs(beh);
// shape of emitter object
if(guid == OBJECTSYSTEM_GUID) {
((ObjectEmitter*)pe)->m_Shape = entity->GetCurrentMesh();
}
// we update the time spent since last emission
float emissiontime = 0.0f;
beh->GetLocalParameterValue(2,&emissiontime);
emissiontime += behcontext.DeltaTime;
// We create new particles only if we are active
if(activity) {
float emissiondelay=0;
beh->GetInputParameterValue(EMISSIONDELAY,&emissiondelay);
if(emissiondelay>0) { // linked with time
float emissiondelayvariance=0;
beh->GetInputParameterValue(EMISSIONDELAYVAR,&emissiondelayvariance);
emissiondelay += emissiondelayvariance*RANDNUM;
if(emissiondelay<0.1f)
emissiondelay = 0.1f; //Avoid infinite loops
while(emissiontime>emissiondelay) {
emissiontime -= emissiondelay;
pe->AddParticles();
}
} else { // Not linked with time
pe->AddParticles();
}
}
// ACC - July 10,2002
// Original Code
#ifndef USE_THR
// We update the particles (position, color, size...)
pe->UpdateParticles(behcontext.DeltaTime);
#else
// CKContext* ctx = beh->GetCKContext();
// ctx->OutputToConsoleEx("Enque a Thread param: count=%d\n", PSqueue.NumItems());
// multi-thread. Enqueue to be processed
#ifdef MT_VERB
{
VxMutexLock lock (logguard);
fprintf(ACCLOG, "Enque a Thread param count=%d\n", PSqueue.NumItems());
fflush(ACCLOG);
}
#endif
UpdateParticleSystemEnqueue(pe, behcontext.DeltaTime);
#endif
///
// Saving Locals
// we write the time
beh->SetLocalParameterValue(2,&emissiontime);
}
// ACC, July 10, 2002:
#ifndef USE_THR
// TODO
//This code needs to be moved into thread function, however
// it imposes a condition that the values are not ready until the next frame
// potentially
// Deflector Impacts Management
if (pe->m_CurrentImpact < pe->m_Impacts.Size()) {
beh->SetOutputParameterValue(0,&pe->m_Impacts[pe->m_CurrentImpact].m_Position);
beh->SetOutputParameterValue(1,&pe->m_Impacts[pe->m_CurrentImpact].m_Direction);
beh->SetOutputParameterObject(2,pe->m_Impacts[pe->m_CurrentImpact].m_Object);
beh->SetOutputParameterValue(3,&pe->m_Impacts[pe->m_CurrentImpact].m_UVs);
pe->m_CurrentImpact++;
beh->ActivateOutput(3);
}
// Update the particle count output (if available)
int opCount = beh->GetOutputParameterCount();
if ((opCount == 1) || (opCount == 5)) {
beh->SetOutputParameterValue(opCount-1,&pe->particleCount);
}
// This section of code can go into the render call back, and return premature
// if particle is shutdown
// if there is no more particles and the behavior is inactive
if(!activity && !(pe->getParticles())) {
ShowParticles(beh,FALSE);
beh->ActivateOutput(1);
return CKBR_OK;
}
#endif
return CKBR_ACTIVATENEXTFRAME;
}
CKERROR GeneralParticleSystemCallback(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
CKContext* ctx = behcontext.Context;
// we get the guid
CKGUID guid = beh->GetPrototypeGuid();
// we get the frame entity
CK3dEntity* ement = (CK3dEntity*)beh->GetOwner();
switch (behcontext.CallbackMessage) {
case CKM_BEHAVIORATTACH:
{
if ((guid != OBJECTSYSTEM_GUID) &&
(guid != CURVESYSTEM_GUID)) {
// we test if it's a frame : if not -> reject
if (!(ement->GetFlags()&CK_3DENTITY_FRAME)) {
ctx->OutputToConsole("You can only attach this particule system to a Frame");
return CKBR_OWNERERROR;
}
}
}
case CKM_BEHAVIORLOAD:
{
ParticleManager* pm = (ParticleManager*)ctx->GetManagerByGuid(PARTICLE_MANAGER_GUID);
if(beh->GetLocalParameterCount() == 17)
{
// Mantis bug 3828
// Add new option to change the radial particle distance offset (0 by default for newly created particle
// so that the zbuffer problem doesn't occur)
CKParameterLocal *p;
p = beh->CreateLocalParameter(RadialParticleOffsetStr, CKPGUID_FLOAT);
const float defaultValue = 40.f; // default value for backward compatibility
p->SetValue(&defaultValue);
}
///////////////////////////
// Interactors Diplay
///////////////////////////
beh->SetLocalParameterValue(DISPLAYINTERACTORS,&pm->m_ShowInteractors);
// init of the local param
ParticleEmitter* em = pm->CreateNewEmitter(guid,CKOBJID(ement));
em->m_Behavior = beh;
beh->SetLocalParameterValue(0, &em, sizeof(ParticleEmitter*));
// we now set the good mesh of the emitter
if (!ctx->IsPlaying())
EmitterSetMesh(TRUE,guid,beh,em);
/////////////////////////////////////
// CALLBACKS
/////////////////////////////////////
// We read the settings
em->ReadSettings(beh);
// We read the inputs
em->ReadInputs(beh);
// we initialize the time
float time = 0.0f;
beh->SetLocalParameterValue(2,&time);
}
break;
case CKM_BEHAVIORNEWSCENE:
{
ParticleEmitter *pe = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!pe) return CKBR_PARAMETERERROR;
ement->ModifyMoveableFlags(VX_MOVEABLE_RENDERLAST,0);
if (AreScriptAndTargetActiveInScene(behcontext)) {
BOOL active;
beh->GetLocalParameterValue(1,&active);
if(active) {
// entity->SetRenderCallBack( pe-<2D>>m_RenderParticlesCallback, pe );
ShowParticles(beh,TRUE);
}
} else {
ShowParticles(beh,FALSE);
}
}
break;
case CKM_BEHAVIORSETTINGSEDITED:
{
ParticleEmitter *pe = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
pe->ReadSettings(beh);
if (ctx->IsPlaying() && AreScriptAndTargetActiveInScene(behcontext)) ShowParticles(beh);
}
break;
case CKM_BEHAVIORDETACH:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(em) { // we check if it's not the cancel button
// we now remove the emitter mesh of the frame
EmitterSetMesh(FALSE,guid,beh,em);
// We remove the render callbcak
if(ement) {
ement->RemovePostRenderCallBack(em->m_RenderParticlesCallback,em);
}
// we delete the particle system
ParticleManager* pm = (ParticleManager*)ctx->GetManagerByGuid(PARTICLE_MANAGER_GUID);
pm->DeleteEmitter(em);
beh->SetLocalParameterObject(0,NULL);
}
}
break;
case CKM_BEHAVIORPOSTSAVE:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!em) return CKBR_PARAMETERERROR;
// we now set the good mesh of the emitter
EmitterSetMesh(TRUE,guid,beh,em);
}
break;
case CKM_BEHAVIORRESET:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!em) return CKBR_PARAMETERERROR;
int activity = 0;
beh->GetLocalParameterValue(1,&activity);
activity &= ~FREEZED;
beh->SetLocalParameterValue(1,&activity);
em->InitParticleSystem();
// we now set the good mesh of the emitter
EmitterSetMesh(TRUE,guid,beh,em);
}
break;
case CKM_BEHAVIORPAUSE:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!em) return CKBR_PARAMETERERROR;
CKBOOL visibleOnPause = FALSE;
beh->GetLocalParameterValue(VISIBLEINPAUSE, &visibleOnPause);
if (visibleOnPause)
return CKBR_OK;
// we now set the good mesh of the emitter
EmitterSetMesh(TRUE,guid,beh,em);
}
case CKM_BEHAVIORDEACTIVATESCRIPT:
{
ShowParticles(beh,FALSE);
}
break;
case CKM_BEHAVIORPRESAVE:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!em) return CKBR_PARAMETERERROR;
// we now set the good mesh of the emitter
EmitterSetMesh(FALSE,guid,beh,em);
}
break;
case CKM_BEHAVIORRESUME:
{
ParticleEmitter *em = *(ParticleEmitter**)beh->GetLocalParameterReadDataPtr(0);
if(!em) return CKBR_PARAMETERERROR;
// we now remove the emitter mesh of the frame
EmitterSetMesh(FALSE,guid,beh,em);
}
case CKM_BEHAVIORACTIVATESCRIPT:
{
if (AreScriptAndTargetActiveInScene(behcontext)) {
int activity = 0;
beh->GetLocalParameterValue(1,&activity);
ShowParticles(beh, activity != 0);
}
}
break;
}
return CKBR_OK;
}
void
EmitterSetMesh(BOOL Set,CKGUID guid,CKBehavior* beh,ParticleEmitter *em)
{
CKContext* ctx = beh->GetCKContext();
// does nothing if we are not in interface mode
if (!ctx->IsInInterfaceMode()) {
return;
}
// we get the frame entity
CK3dEntity* ement = (CK3dEntity*)beh->GetOwner();
if (!ement) return;
if(em->m_Mesh) { // If a mesh, it's not an object or a curve PS
if (Set) {
ement->SetCurrentMesh((CKMesh*)ctx->GetObject(em->m_Mesh));
} else {
ement->RemoveMesh((CKMesh*)ctx->GetObject(em->m_Mesh));
}
}
}