forked from Mirrors/openclonk
the dynamic particle system now runs the calculations in a different thread
added PV_KeyFramesstable-5.4
parent
40b66d1c76
commit
8025e7c2b0
|
@ -740,7 +740,6 @@ bool C4Game::Execute() // Returns true if the game is over
|
|||
EXEC_S_DR( pGlobalEffects->Execute(NULL); , GEStats , "GEEx\0");
|
||||
EXEC_S_DR( PXS.Execute(); , PXSStat , "PXSEx")
|
||||
EXEC_S_DR( Particles.GlobalParticles.Exec(); , PartStat , "ParEx")
|
||||
EXEC_S_DR( DynamicParticles.globalParticles.Exec(); , DynPartStat , "DParEx")
|
||||
EXEC_S_DR( MassMover.Execute(); , MassMoverStat , "MMvEx")
|
||||
EXEC_S_DR( Weather.Execute(); , WeatherStat , "WtrEx")
|
||||
EXEC_S_DR( Landscape.Execute(); , LandscapeStat , "LdsEx")
|
||||
|
|
|
@ -262,7 +262,7 @@ void C4Viewport::Draw(C4TargetFacet &cgo0, bool fDrawOverlay)
|
|||
|
||||
// draw global dynamic particles
|
||||
C4ST_STARTNEW(PartStat, "C4Viewport::Draw: Dynamic Particles")
|
||||
::DynamicParticles.globalParticles.Draw(cgo, NULL);
|
||||
::DynamicParticles.DrawGlobalParticles(cgo);
|
||||
C4ST_STOP(PartStat)
|
||||
|
||||
// Draw PathFinder
|
||||
|
|
|
@ -1554,7 +1554,7 @@ static bool FnCreateParticleEx(C4PropList * _this, C4String *name, long x, long
|
|||
valueSpeedY.Set(speedY);
|
||||
valueSize.Set(size);
|
||||
// create
|
||||
::DynamicParticles.Create(pDef, (float)x, (float)y, valueSpeedX, valueSpeedY, valueSize, (float)lifetime, properties, obj ? (attachment == 1 ? &obj->DynamicBackParticles : &obj->DynamicFrontParticles) : NULL, obj);
|
||||
::DynamicParticles.Create(pDef, (float)x, (float)y, valueSpeedX, valueSpeedY, valueSize, (float)lifetime, properties, obj ? (attachment == 1 ? obj->DynamicBackParticles : obj->DynamicFrontParticles) : NULL, obj);
|
||||
// success, even if not created
|
||||
return true;
|
||||
}
|
||||
|
@ -1636,13 +1636,34 @@ static C4ValueArray* FnPV_Linear(C4PropList * _this, long startValue, long endVa
|
|||
static C4ValueArray* FnPV_Random(C4PropList * _this, long startValue, long endValue, long rerollInterval)
|
||||
{
|
||||
C4ValueArray *pArray = new C4ValueArray(4);
|
||||
pArray->SetItem(0, C4VInt(C4PV_Linear));
|
||||
pArray->SetItem(0, C4VInt(C4PV_Random));
|
||||
pArray->SetItem(1, C4VInt(startValue));
|
||||
pArray->SetItem(2, C4VInt(endValue));
|
||||
pArray->SetItem(3, C4VInt(rerollInterval));
|
||||
return pArray;
|
||||
}
|
||||
|
||||
static C4Value FnPV_KeyFrames(C4PropList * _this, C4Value *pars)
|
||||
{
|
||||
C4ValueArray *pArray = new C4ValueArray(C4AUL_MAX_Par);
|
||||
pArray->SetItem(0, C4VInt(C4PV_KeyFrames));
|
||||
const int offset = 1;
|
||||
|
||||
// Read all parameters
|
||||
int i = 0;
|
||||
for (; i < C4AUL_MAX_Par; i++)
|
||||
{
|
||||
C4Value Data = *(pars++);
|
||||
// No data given?
|
||||
if (Data.GetType() == C4V_Nil) break;
|
||||
|
||||
pArray->SetItem(offset + i, C4VInt(Data.getInt()));
|
||||
}
|
||||
pArray->SetSize(i + offset);
|
||||
return C4Value(pArray);
|
||||
}
|
||||
|
||||
|
||||
static bool FnSetSkyParallax(C4PropList * _this, Nillable<long> iMode, Nillable<long> iParX, Nillable<long> iParY, Nillable<long> iXDir, Nillable<long> iYDir, Nillable<long> iX, Nillable<long> iY)
|
||||
{
|
||||
// set all parameters that aren't nil
|
||||
|
@ -2486,6 +2507,7 @@ void InitGameFunctionMap(C4AulScriptEngine *pEngine)
|
|||
|
||||
F(PV_Linear);
|
||||
F(PV_Random);
|
||||
// F(PV_KeyFrames); added below
|
||||
|
||||
AddFunc(pEngine, "IncinerateLandscape", FnIncinerateLandscape);
|
||||
AddFunc(pEngine, "GetGravity", FnGetGravity);
|
||||
|
@ -2626,6 +2648,7 @@ C4ScriptFnDef C4ScriptGameFnMap[]=
|
|||
{ "Message", 1, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnMessage },
|
||||
{ "AddMessage", 1, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnAddMessage },
|
||||
{ "EffectCall", 1, C4V_Any, { C4V_Object ,C4V_PropList,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnEffectCall },
|
||||
{ "PV_KeyFrames", 1, C4V_Array, { C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnPV_KeyFrames },
|
||||
|
||||
{ NULL, 0, C4V_Nil, { C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil}, 0 }
|
||||
};
|
||||
|
|
|
@ -33,8 +33,19 @@ void C4DynamicParticleValueProvider::Floatify(float denominator)
|
|||
startValue /= denominator;
|
||||
endValue /= denominator;
|
||||
|
||||
if (valueFunction == &C4DynamicParticleValueProvider::Random)
|
||||
RollRandom();
|
||||
// special treatment for keyframes
|
||||
if (valueFunction == &C4DynamicParticleValueProvider::KeyFrames)
|
||||
{
|
||||
for (int i = 0; i < keyFrameCount; ++i)
|
||||
{
|
||||
keyFrames[2 * i] /= 1000.0f; // even numbers are the time values
|
||||
keyFrames[2 * i + 1] /= denominator; // odd numbers are the actual values
|
||||
//LogF("KF is %f @ %f", keyFrames[2 * i + 1], keyFrames[2 * i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (valueFunction == &C4DynamicParticleValueProvider::Random)
|
||||
RollRandom();
|
||||
}
|
||||
|
||||
void C4DynamicParticleValueProvider::RollRandom()
|
||||
|
@ -64,6 +75,31 @@ float C4DynamicParticleValueProvider::Random(C4DynamicParticle *forParticle)
|
|||
return currentValue;
|
||||
}
|
||||
|
||||
float C4DynamicParticleValueProvider::KeyFrames(C4DynamicParticle *forParticle)
|
||||
{
|
||||
float age = forParticle->GetRelativeAge();
|
||||
if (smoothing == 0) // linear
|
||||
{
|
||||
for (int i = 0; i < keyFrameCount; ++i)
|
||||
{
|
||||
if (age > keyFrames[i * 2]) continue;
|
||||
assert(i >= 1);
|
||||
|
||||
float x1 = keyFrames[(i - 1) * 2];
|
||||
float x2 = keyFrames[i * 2];
|
||||
float y1 = keyFrames[(i - 1) * 2 + 1];
|
||||
float y2 = keyFrames[i * 2 + 1];
|
||||
float position = (age - x1) / (x2 - x1);
|
||||
float totalRange = (y2 - y1);
|
||||
|
||||
float value = position * totalRange + y1;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return startValue;
|
||||
}
|
||||
|
||||
void C4DynamicParticleValueProvider::Set(float _startValue, float _endValue, C4ParticleValueProviderID what)
|
||||
{
|
||||
startValue = _startValue;
|
||||
|
@ -79,6 +115,10 @@ void C4DynamicParticleValueProvider::Set(float _startValue, float _endValue, C4P
|
|||
break;
|
||||
case C4PV_Random:
|
||||
valueFunction = &C4DynamicParticleValueProvider::Random;
|
||||
break;
|
||||
case C4PV_KeyFrames:
|
||||
valueFunction = &C4DynamicParticleValueProvider::KeyFrames;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
};
|
||||
|
@ -97,9 +137,9 @@ void C4DynamicParticleValueProvider::Set(const C4Value &value)
|
|||
Set(valueArray);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int32_t valueInt = value.getInt();
|
||||
|
||||
|
||||
Set((float)valueInt, (float)valueInt, C4PV_Const);
|
||||
}
|
||||
|
||||
|
@ -122,7 +162,9 @@ void C4DynamicParticleValueProvider::Set(C4ValueArray *fromArray)
|
|||
|
||||
case C4PV_Linear:
|
||||
if (arraySize >= 3)
|
||||
{
|
||||
Set((float)(*fromArray)[1].getInt(), (float)(*fromArray)[2].getInt(), C4PV_Linear);
|
||||
}
|
||||
break;
|
||||
case C4PV_Random:
|
||||
if (arraySize >= 4)
|
||||
|
@ -130,7 +172,31 @@ void C4DynamicParticleValueProvider::Set(C4ValueArray *fromArray)
|
|||
Set((float)(*fromArray)[1].getInt(), (float)(*fromArray)[2].getInt(), C4PV_Random);
|
||||
rerollInterval = (*fromArray)[3].getInt();
|
||||
RollRandom();
|
||||
|
||||
}
|
||||
case C4PV_KeyFrames:
|
||||
if (arraySize >= 5)
|
||||
{
|
||||
smoothing = (*fromArray)[1].getInt();
|
||||
keyFrames = (float*) malloc(sizeof(float) * (arraySize + 3)); // 2 additional information floats at the beginning and ending
|
||||
keyFrameCount = 0;
|
||||
const int startingOffset = 2;
|
||||
int i = startingOffset;
|
||||
for (; i < arraySize; ++i)
|
||||
{
|
||||
keyFrames[2 + i - startingOffset] = (float)(*fromArray)[i].getInt();
|
||||
}
|
||||
keyFrameCount = (i - startingOffset) / 2 + 2;
|
||||
Set(keyFrames[2 + 1], keyFrames[2 * keyFrameCount - 1], C4PV_KeyFrames);
|
||||
|
||||
// add two points for easier interpolation at beginning and ending
|
||||
keyFrames[0] = -500.f;
|
||||
keyFrames[1] = keyFrames[2 + 1];
|
||||
keyFrames[2 * keyFrameCount - 2] = 1500.f;
|
||||
keyFrames[2 * keyFrameCount - 1] = keyFrames[keyFrameCount - 1 - 2];
|
||||
|
||||
//for (int i = 0; i < keyFrameCount; ++i)
|
||||
// LogF("KF is %f @ %d of %d", keyFrames[i * 2 + 1], int(keyFrames[i * 2]), keyFrameCount);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
@ -154,6 +220,7 @@ C4DynamicParticleProperties::C4DynamicParticleProperties()
|
|||
|
||||
void C4DynamicParticleProperties::Floatify()
|
||||
{
|
||||
size.Floatify(1.f);
|
||||
forceX.Floatify(10.f);
|
||||
forceY.Floatify(10.f);
|
||||
speedDampingX.Floatify(1000.f);
|
||||
|
@ -229,16 +296,16 @@ void C4DynamicParticle::Init()
|
|||
lifetime = startingLifetime = 5.f * 38.f;
|
||||
}
|
||||
|
||||
bool C4DynamicParticle::Exec(C4Object *obj)
|
||||
bool C4DynamicParticle::Exec(C4Object *obj, float timeDelta)
|
||||
{
|
||||
// die of old age? :<
|
||||
lifetime -= 1.f;
|
||||
lifetime -= timeDelta;
|
||||
if (lifetime <= 0.f) return false;
|
||||
|
||||
// movement
|
||||
float currentForceX = properties.forceX.GetValue(this);
|
||||
float currentForceY = properties.forceY.GetValue(this);
|
||||
|
||||
|
||||
currentSpeedX += currentForceX;
|
||||
currentSpeedY += currentForceY;
|
||||
|
||||
|
@ -251,11 +318,11 @@ bool C4DynamicParticle::Exec(C4Object *obj)
|
|||
currentSpeedY *= currentDampingY;
|
||||
|
||||
// todo: collision check
|
||||
|
||||
positionX += currentSpeedX;
|
||||
positionY += currentSpeedY;
|
||||
|
||||
positionX += timeDelta * currentSpeedX;
|
||||
positionY += timeDelta * currentSpeedY;
|
||||
drawingData.SetPosition(positionX, positionY, properties.size.GetValue(this));
|
||||
|
||||
|
||||
}
|
||||
else if(!properties.size.IsConstant())
|
||||
{
|
||||
|
@ -284,7 +351,7 @@ void C4DynamicParticleChunk::Clear()
|
|||
void C4DynamicParticleChunk::ReplaceParticle(int indexTo, int indexFrom)
|
||||
{
|
||||
C4DynamicParticle *oldParticle = particles[indexTo];
|
||||
|
||||
|
||||
if (indexFrom != indexTo) // false when "replacing" the last one
|
||||
{
|
||||
memcpy(&vertexCoordinates[indexTo * C4DynamicParticle::DrawingData::vertexCountPerParticle], &vertexCoordinates[indexFrom * C4DynamicParticle::DrawingData::vertexCountPerParticle], sizeof(C4DynamicParticle::DrawingData::Vertex) * C4DynamicParticle::DrawingData::vertexCountPerParticle);
|
||||
|
@ -295,11 +362,11 @@ void C4DynamicParticleChunk::ReplaceParticle(int indexTo, int indexFrom)
|
|||
delete oldParticle;
|
||||
}
|
||||
|
||||
bool C4DynamicParticleChunk::Exec(C4Object *obj)
|
||||
bool C4DynamicParticleChunk::Exec(C4Object *obj, float timeDelta)
|
||||
{
|
||||
for (int i = 0; i < particleCount; ++i)
|
||||
{
|
||||
if (!particles[i]->Exec(obj))
|
||||
if (!particles[i]->Exec(obj, timeDelta))
|
||||
{
|
||||
ReplaceParticle(i, particleCount - 1);
|
||||
--particleCount;
|
||||
|
@ -359,19 +426,26 @@ C4DynamicParticle *C4DynamicParticleChunk::AddNewParticle()
|
|||
return newParticle;
|
||||
}
|
||||
|
||||
void C4DynamicParticleList::Exec(C4Object *obj)
|
||||
void C4DynamicParticleList::Exec(float timeDelta)
|
||||
{
|
||||
if (particleChunks.empty()) return;
|
||||
|
||||
accessMutex.Enter();
|
||||
|
||||
for (std::list<C4DynamicParticleChunk>::iterator iter = particleChunks.begin(); iter != particleChunks.end();)
|
||||
{
|
||||
if (iter->Exec(obj))
|
||||
if (iter->Exec(targetObject, timeDelta))
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = particleChunks.erase(iter);
|
||||
lastAccessedChunk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
accessMutex.Leave();
|
||||
}
|
||||
|
||||
void C4DynamicParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
||||
|
@ -384,9 +458,9 @@ void C4DynamicParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
pDraw->DeactivateBlitModulation();
|
||||
pDraw->ResetBlitMode();
|
||||
pDraw->SetTexture();
|
||||
|
||||
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
|
||||
|
||||
// apply zoom
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
@ -400,11 +474,15 @@ void C4DynamicParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
|
||||
accessMutex.Enter();
|
||||
|
||||
for (std::list<C4DynamicParticleChunk>::iterator iter = particleChunks.begin(); iter != particleChunks.end(); ++iter)
|
||||
{
|
||||
iter->Draw(cgo, obj);
|
||||
}
|
||||
|
||||
accessMutex.Leave();
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
@ -416,6 +494,8 @@ void C4DynamicParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
|
||||
C4DynamicParticle *C4DynamicParticleList::AddNewParticle(C4ParticleDef *def, bool additive)
|
||||
{
|
||||
accessMutex.Enter();
|
||||
|
||||
// if not cached, find correct chunk in list
|
||||
C4DynamicParticleChunk *chunk = 0;
|
||||
if (lastAccessedChunk && lastAccessedChunk->IsOfType(def))
|
||||
|
@ -441,15 +521,84 @@ C4DynamicParticle *C4DynamicParticleList::AddNewParticle(C4ParticleDef *def, boo
|
|||
|
||||
assert(chunk && "No suitable particle chunk could be found or created.");
|
||||
lastAccessedChunk = chunk;
|
||||
|
||||
accessMutex.Leave();
|
||||
return chunk->AddNewParticle();
|
||||
}
|
||||
|
||||
void C4DynamicParticleSystem::CalculationThread::Execute()
|
||||
{
|
||||
DynamicParticles.ExecuteCalculation();
|
||||
}
|
||||
|
||||
void C4DynamicParticleSystem::ExecuteCalculation()
|
||||
{
|
||||
int gameTime = Game.FrameCounter;
|
||||
if (currentSimulationTime < gameTime)
|
||||
{
|
||||
float timeDelta = 1.f;
|
||||
if (currentSimulationTime != 0)
|
||||
timeDelta = (float)(gameTime - currentSimulationTime);
|
||||
currentSimulationTime = gameTime;
|
||||
|
||||
particleListAccessMutex.Enter();
|
||||
|
||||
for (std::list<C4DynamicParticleList>::iterator iter = particleLists.begin(); iter != particleLists.end(); ++iter)
|
||||
{
|
||||
iter->Exec(timeDelta);
|
||||
}
|
||||
|
||||
particleListAccessMutex.Leave();
|
||||
}
|
||||
Sleep(1000 / 38);
|
||||
}
|
||||
|
||||
C4DynamicParticleList *C4DynamicParticleSystem::GetNewParticleList(C4Object *forObject)
|
||||
{
|
||||
C4DynamicParticleList *newList = 0;
|
||||
|
||||
particleListAccessMutex.Enter();
|
||||
particleLists.push_back(C4DynamicParticleList(forObject));
|
||||
newList = &particleLists.back();
|
||||
particleListAccessMutex.Leave();
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
void C4DynamicParticleSystem::ReleaseParticleList(C4DynamicParticleList *first, C4DynamicParticleList *second)
|
||||
{
|
||||
particleListAccessMutex.Enter();
|
||||
|
||||
for(std::list<C4DynamicParticleList>::iterator iter = particleLists.begin(); iter != particleLists.end();)
|
||||
{
|
||||
C4DynamicParticleList *list = &(*iter);
|
||||
if (list == first || list == second)
|
||||
{
|
||||
iter = particleLists.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
particleListAccessMutex.Leave();
|
||||
}
|
||||
|
||||
C4DynamicParticle *C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider speedX, C4DynamicParticleValueProvider speedY, C4DynamicParticleValueProvider size, float lifetime, C4PropList *properties, C4DynamicParticleList *pxList, C4Object *object)
|
||||
{
|
||||
// todo: check amount etc
|
||||
|
||||
if (!pxList)
|
||||
pxList = &globalParticles;
|
||||
{
|
||||
pxList = globalParticles;
|
||||
}
|
||||
|
||||
if (pxList == globalParticles && globalParticles == 0)
|
||||
{
|
||||
globalParticles = GetNewParticleList();
|
||||
pxList = globalParticles;
|
||||
}
|
||||
|
||||
C4DynamicParticle *particle = pxList->AddNewParticle(of_def, true);
|
||||
particle->properties.Set(properties);
|
||||
|
@ -469,7 +618,7 @@ void C4DynamicParticleSystem::PreparePrimitiveRestartIndices(int forAmount)
|
|||
{
|
||||
const uint32_t PRI = 0xffffffff;
|
||||
int neededAmount = 5 * forAmount;
|
||||
|
||||
|
||||
if (primitiveRestartIndices.size() < neededAmount)
|
||||
{
|
||||
uint32_t oldValue = 0;
|
||||
|
@ -498,4 +647,13 @@ void C4DynamicParticleSystem::PreparePrimitiveRestartIndices(int forAmount)
|
|||
}
|
||||
}
|
||||
|
||||
void C4DynamicParticleSystem::Clear()
|
||||
{
|
||||
currentSimulationTime = 0;
|
||||
|
||||
particleListAccessMutex.Enter();
|
||||
particleLists.clear();
|
||||
particleListAccessMutex.Leave();
|
||||
}
|
||||
|
||||
C4DynamicParticleSystem DynamicParticles;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <C4Particles.h>
|
||||
#include <StdScheduler.h>
|
||||
|
||||
#ifndef INC_C4DynamicParticles
|
||||
#define INC_C4DynamicParticles
|
||||
|
@ -25,6 +26,7 @@ enum C4ParticleValueProviderID
|
|||
C4PV_Const,
|
||||
C4PV_Linear,
|
||||
C4PV_Random,
|
||||
C4PV_KeyFrames,
|
||||
};
|
||||
|
||||
class C4DynamicParticleList;
|
||||
|
@ -41,14 +43,24 @@ protected:
|
|||
|
||||
// used by Random
|
||||
float currentValue;
|
||||
int rerollInterval;
|
||||
|
||||
union
|
||||
{
|
||||
int rerollInterval; // for Random
|
||||
int keyFrameCount; // for KeyFrames
|
||||
};
|
||||
int smoothing;
|
||||
float *keyFrames;
|
||||
|
||||
C4DynamicParticleValueProviderFunction valueFunction;
|
||||
bool isConstant;
|
||||
public:
|
||||
bool IsConstant() { return isConstant; }
|
||||
C4DynamicParticleValueProvider() : startValue(0.f), endValue(0.f), currentValue(0.f), rerollInterval(0), valueFunction(0), isConstant(true) { }
|
||||
|
||||
C4DynamicParticleValueProvider() : startValue(0.f), endValue(0.f), currentValue(0.f), rerollInterval(0), smoothing(0), keyFrames(0), valueFunction(0), isConstant(true) { }
|
||||
~C4DynamicParticleValueProvider()
|
||||
{
|
||||
if (keyFrames != 0) free(keyFrames);
|
||||
}
|
||||
void RollRandom();
|
||||
|
||||
// divides by denominator
|
||||
|
@ -62,6 +74,7 @@ public:
|
|||
float Linear(C4DynamicParticle *forParticle);
|
||||
float Const(C4DynamicParticle *forParticle);
|
||||
float Random(C4DynamicParticle *forParticle);
|
||||
float KeyFrames(C4DynamicParticle *forParticle);
|
||||
};
|
||||
|
||||
class C4DynamicParticleProperties
|
||||
|
@ -164,7 +177,7 @@ public:
|
|||
drawingData.SetPosition(positionX, positionY, properties.size.GetValue(this));
|
||||
}
|
||||
|
||||
bool Exec(C4Object *obj);
|
||||
bool Exec(C4Object *obj, float timeDelta);
|
||||
|
||||
friend class C4DynamicParticleChunk;
|
||||
friend class C4DynamicParticleSystem;
|
||||
|
@ -192,7 +205,7 @@ public:
|
|||
}
|
||||
// removes all particles
|
||||
void Clear();
|
||||
bool Exec(C4Object *obj);
|
||||
bool Exec(C4Object *obj, float timeDelta);
|
||||
void Draw(C4TargetFacet cgo, C4Object *obj);
|
||||
bool IsOfType(C4ParticleDef *def);
|
||||
|
||||
|
@ -206,29 +219,65 @@ class C4DynamicParticleList
|
|||
private:
|
||||
std::list<C4DynamicParticleChunk> particleChunks;
|
||||
|
||||
C4Object *targetObject;
|
||||
|
||||
// caching..
|
||||
C4DynamicParticleChunk *lastAccessedChunk;
|
||||
|
||||
// for making sure that the list is not drawn and calculated at the same time
|
||||
CStdCSec accessMutex;
|
||||
public:
|
||||
C4DynamicParticleList() : lastAccessedChunk(0)
|
||||
C4DynamicParticleList(C4Object *obj = 0) : targetObject(obj), lastAccessedChunk(0)
|
||||
{
|
||||
|
||||
}
|
||||
void Exec(C4Object *obj = 0);
|
||||
void Exec(float timeDelta = 1.f);
|
||||
void Draw(C4TargetFacet cgo, C4Object *obj);
|
||||
C4DynamicParticle *AddNewParticle(C4ParticleDef *def, bool additive);
|
||||
};
|
||||
|
||||
class C4DynamicParticleSystem
|
||||
{
|
||||
class CalculationThread : public StdThread
|
||||
{
|
||||
protected:
|
||||
virtual void Execute();
|
||||
public:
|
||||
CalculationThread() { StdThread::Start(); }
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<uint32_t> primitiveRestartIndices;
|
||||
std::list<C4ParticleList> particleLists;
|
||||
std::list<C4DynamicParticleList> particleLists;
|
||||
|
||||
CalculationThread calculationThread;
|
||||
CStdCSec particleListAccessMutex;
|
||||
int currentSimulationTime; // in game time
|
||||
|
||||
// calculates the physics in all of the existing particle lists
|
||||
void ExecuteCalculation();
|
||||
|
||||
C4DynamicParticleList *globalParticles;
|
||||
public:
|
||||
C4DynamicParticleSystem()
|
||||
{
|
||||
currentSimulationTime = 0;
|
||||
globalParticles = 0;
|
||||
}
|
||||
|
||||
void Clear();
|
||||
void DrawGlobalParticles(C4TargetFacet cgo) { if (globalParticles) globalParticles->Draw(cgo, 0); }
|
||||
|
||||
C4DynamicParticleList *GetNewParticleList(C4Object *forTarget = 0);
|
||||
// releases up to 2 lists
|
||||
void ReleaseParticleList(C4DynamicParticleList *first, C4DynamicParticleList *second = 0);
|
||||
|
||||
void PreparePrimitiveRestartIndices(int forSize);
|
||||
void *GetPrimitiveRestartArray() { return (void*)&primitiveRestartIndices[0]; }
|
||||
|
||||
C4DynamicParticleList globalParticles;
|
||||
C4DynamicParticle *Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider speedX, C4DynamicParticleValueProvider speedY, C4DynamicParticleValueProvider size, float lifetime, C4PropList *properties, C4DynamicParticleList *pxList=NULL, C4Object *object=NULL);
|
||||
|
||||
friend class CalculationThread;
|
||||
};
|
||||
|
||||
extern C4DynamicParticleSystem DynamicParticles;
|
||||
|
|
|
@ -170,6 +170,8 @@ void C4Action::GetBridgeData(int32_t &riBridgeTime, bool &rfMoveClonk, bool &rfW
|
|||
|
||||
C4Object::C4Object()
|
||||
{
|
||||
DynamicFrontParticles = DynamicBackParticles = 0;
|
||||
|
||||
Default();
|
||||
}
|
||||
|
||||
|
@ -229,6 +231,11 @@ void C4Object::Default()
|
|||
pEffects=NULL;
|
||||
pGfxOverlay=NULL;
|
||||
iLastAttachMovementFrame=-1;
|
||||
|
||||
if (DynamicFrontParticles == 0)
|
||||
DynamicFrontParticles = DynamicParticles.GetNewParticleList(this);
|
||||
if (DynamicBackParticles == 0)
|
||||
DynamicBackParticles = DynamicParticles.GetNewParticleList(this);
|
||||
}
|
||||
|
||||
bool C4Object::Init(C4PropList *pDef, C4Object *pCreator,
|
||||
|
@ -1052,8 +1059,6 @@ void C4Object::Execute()
|
|||
// particles
|
||||
if (BackParticles) BackParticles.Exec(this);
|
||||
if (FrontParticles) FrontParticles.Exec(this);
|
||||
DynamicBackParticles.Exec();
|
||||
DynamicFrontParticles.Exec();
|
||||
// effects
|
||||
if (pEffects)
|
||||
{
|
||||
|
@ -2567,6 +2572,9 @@ void C4Object::ClearInfo(C4ObjectInfo *pInfo)
|
|||
|
||||
void C4Object::Clear()
|
||||
{
|
||||
DynamicParticles.ReleaseParticleList(DynamicFrontParticles, DynamicBackParticles);
|
||||
DynamicFrontParticles = DynamicBackParticles = NULL;
|
||||
|
||||
if (pEffects) { delete pEffects; pEffects=NULL; }
|
||||
if (FrontParticles) FrontParticles.Clear();
|
||||
if (BackParticles) BackParticles.Clear();
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
StdMeshInstance* pMeshInstance; // Instance for mesh-type objects
|
||||
C4Effect *pEffects; // linked list of effects
|
||||
C4ParticleList FrontParticles, BackParticles; // lists of object local particles
|
||||
C4DynamicParticleList DynamicFrontParticles, DynamicBackParticles; // the same only for the dynamic particle system
|
||||
C4DynamicParticleList *DynamicFrontParticles, *DynamicBackParticles; // the same only for the dynamic particle system
|
||||
|
||||
uint32_t ColorMod; // color by which the object-drawing is modulated
|
||||
uint32_t BlitMode; // extra blitting flags (like additive, ClrMod2, etc.)
|
||||
|
|
Loading…
Reference in New Issue