Add support for multi-threaded CPU particles simulation
This commit is contained in:
@@ -1580,11 +1580,11 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
|
||||
#if 0
|
||||
// Prevent recursive calls
|
||||
for (int32 i = _callStack.Count() - 1; i >= 0; i--)
|
||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(9, 24))
|
||||
if (context.CallStack[i]->Type == GRAPH_NODE_MAKE_TYPE(9, 24))
|
||||
{
|
||||
const auto callFunc = _callStack[i]->Assets[0].Get();
|
||||
const auto callFunc = context.CallStack[i]->Assets[0].Get();
|
||||
if (callFunc == function)
|
||||
{
|
||||
value = Value::Zero;
|
||||
@@ -1879,7 +1879,7 @@ void AnimGraphExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& va
|
||||
Graph* graph;
|
||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (context.CallStack[i]->Type == GRAPH_NODE_MAKE_TYPE(9, 24) && context.Functions.TryGet(context.CallStack[i], graph) && context.GraphStack.Last() == (Graph*)graph)
|
||||
if (context.CallStack[i]->Type == GRAPH_NODE_MAKE_TYPE(9, 24) && context.Functions.TryGet(context.CallStack[i], graph) && context.GraphStack.Last() == graph)
|
||||
{
|
||||
functionCallNode = (AnimGraphNode*)context.CallStack[i];
|
||||
break;
|
||||
|
||||
@@ -103,7 +103,8 @@ namespace
|
||||
int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
|
||||
{
|
||||
const auto node = _graph.SpawnModules[index];
|
||||
auto& data = _data->SpawnModulesData[index];
|
||||
auto& context = Context.Get();
|
||||
auto& data = context.Data->SpawnModulesData[index];
|
||||
|
||||
// Accumulate the previous frame fraction
|
||||
float spawnCount = data.SpawnCounter;
|
||||
@@ -115,13 +116,13 @@ int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
|
||||
case 100:
|
||||
{
|
||||
const float rate = Math::Max((float)TryGetValue(node->GetBox(0), node->Values[2]), 0.0f);
|
||||
spawnCount += rate * _deltaTime;
|
||||
spawnCount += rate * context.DeltaTime;
|
||||
break;
|
||||
}
|
||||
// Single Burst
|
||||
case 101:
|
||||
{
|
||||
const bool isFirstUpdate = (_data->Time - _deltaTime) <= 0.0f;
|
||||
const bool isFirstUpdate = (context.Data->Time - context.DeltaTime) <= 0.0f;
|
||||
if (isFirstUpdate)
|
||||
{
|
||||
const float count = Math::Max((float)TryGetValue(node->GetBox(0), node->Values[2]), 0.0f);
|
||||
@@ -133,11 +134,11 @@ int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
|
||||
case 102:
|
||||
{
|
||||
float& nextSpawnTime = data.NextSpawnTime;
|
||||
if (nextSpawnTime - _data->Time <= 0.0f)
|
||||
if (nextSpawnTime - context.Data->Time <= 0.0f)
|
||||
{
|
||||
const float count = Math::Max((float)TryGetValue(node->GetBox(0), node->Values[2]), 0.0f);
|
||||
const float delay = Math::Max((float)TryGetValue(node->GetBox(1), node->Values[3]), 0.0f);
|
||||
nextSpawnTime = _data->Time + delay;
|
||||
nextSpawnTime = context.Data->Time + delay;
|
||||
spawnCount += count;
|
||||
}
|
||||
break;
|
||||
@@ -146,13 +147,13 @@ int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
|
||||
case 103:
|
||||
{
|
||||
float& nextSpawnTime = data.NextSpawnTime;
|
||||
if (nextSpawnTime - _data->Time <= 0.0f)
|
||||
if (nextSpawnTime - context.Data->Time <= 0.0f)
|
||||
{
|
||||
const Vector2 countMinMax = (Vector2)TryGetValue(node->GetBox(0), node->Values[2]);
|
||||
const Vector2 delayMinMax = (Vector2)TryGetValue(node->GetBox(1), node->Values[3]);
|
||||
const float count = Math::Max(countMinMax.X + RAND * (countMinMax.Y - countMinMax.X), 0.0f);
|
||||
const float delay = Math::Max(delayMinMax.X + RAND * (delayMinMax.Y - delayMinMax.X), 0.0f);
|
||||
nextSpawnTime = _data->Time + delay;
|
||||
nextSpawnTime = context.Data->Time + delay;
|
||||
spawnCount += count;
|
||||
}
|
||||
break;
|
||||
@@ -170,8 +171,9 @@ int32 ParticleEmitterGraphCPUExecutor::ProcessSpawnModule(int32 index)
|
||||
|
||||
void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode* node, int32 particlesStart, int32 particlesEnd)
|
||||
{
|
||||
auto stride = _data->Buffer->Stride;
|
||||
auto start = _data->Buffer->GetParticleCPU(particlesStart);
|
||||
auto& context = Context.Get();
|
||||
auto stride = context.Data->Buffer->Stride;
|
||||
auto start = context.Data->Buffer->GetParticleCPU(particlesStart);
|
||||
|
||||
switch (node->TypeID)
|
||||
{
|
||||
@@ -181,7 +183,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
auto spriteFacingMode = node->Values[2].AsInt;
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* spriteFacingModePtr = start + attribute.Offset;
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
@@ -192,14 +194,14 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
if ((ParticleSpriteFacingMode)spriteFacingMode == ParticleSpriteFacingMode::CustomFacingVector ||
|
||||
(ParticleSpriteFacingMode)spriteFacingMode == ParticleSpriteFacingMode::FixedAxis)
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
byte* customFacingVectorPtr = start + attribute.Offset;
|
||||
auto box = node->GetBox(0);
|
||||
if (node->UsePerParticleDataResolve())
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
const Vector3 vector = (Vector3)GetValue(box, 3);
|
||||
*((Vector3*)customFacingVectorPtr) = vector;
|
||||
customFacingVectorPtr += stride;
|
||||
@@ -223,7 +225,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
auto modelFacingMode = node->Values[2].AsInt;
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* modelFacingModePtr = start + attribute.Offset;
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
@@ -236,11 +238,11 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Update Age
|
||||
case 300:
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* agePtr = start + attribute.Offset;
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
*((float*)agePtr) += _deltaTime;
|
||||
*((float*)agePtr) += context.DeltaTime;
|
||||
agePtr += stride;
|
||||
}
|
||||
break;
|
||||
@@ -249,16 +251,16 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
case 301:
|
||||
case 304:
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* velocityPtr = start + attribute.Offset;
|
||||
auto box = node->GetBox(0);
|
||||
if (node->UsePerParticleDataResolve())
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
const Vector3 force = (Vector3)GetValue(box, 2);
|
||||
*((Vector3*)velocityPtr) += force * _deltaTime;
|
||||
*((Vector3*)velocityPtr) += force * context.DeltaTime;
|
||||
velocityPtr += stride;
|
||||
}
|
||||
}
|
||||
@@ -267,7 +269,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
const Vector3 force = (Vector3)GetValue(box, 2);
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
*((Vector3*)velocityPtr) += force * _deltaTime;
|
||||
*((Vector3*)velocityPtr) += force * context.DeltaTime;
|
||||
velocityPtr += stride;
|
||||
}
|
||||
}
|
||||
@@ -276,9 +278,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Conform to Sphere
|
||||
case 305:
|
||||
{
|
||||
auto& position = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocity = _data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& mass = _data->Buffer->Layout->Attributes[node->Attributes[2]];
|
||||
auto& position = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocity = context.Data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& mass = context.Data->Buffer->Layout->Attributes[node->Attributes[2]];
|
||||
|
||||
byte* positionPtr = start + position.Offset;
|
||||
byte* velocityPtr = start + velocity.Offset;
|
||||
@@ -308,7 +310,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
float ratio = Math::SmoothStep(0.0f, stickDistance * 2.0f, Math::Abs(distToSurface)); \
|
||||
float tgtSpeed = Math::Sign(distToSurface) * attractionSpeed * ratio; \
|
||||
float deltaSpeed = tgtSpeed - spdNormal; \
|
||||
Vector3 deltaVelocity = dir * (Math::Sign(deltaSpeed) * Math::Min(Math::Abs(deltaSpeed), _deltaTime * Math::Lerp(stickForce, attractionForce, ratio)) / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
Vector3 deltaVelocity = dir * (Math::Sign(deltaSpeed) * Math::Min(Math::Abs(deltaSpeed), context.DeltaTime * Math::Lerp(stickForce, attractionForce, ratio)) / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
*(Vector3*)velocityPtr = velocity + deltaVelocity; \
|
||||
positionPtr += stride; \
|
||||
velocityPtr += stride; \
|
||||
@@ -318,7 +320,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -338,7 +340,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Kill (sphere)
|
||||
case 306:
|
||||
{
|
||||
auto& position = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& position = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + position.Offset;
|
||||
|
||||
@@ -356,8 +358,8 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
if (sign * lengthSqr <= sign * sphereRadiusSqr) \
|
||||
{ \
|
||||
particlesEnd--; \
|
||||
_data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(_data->Buffer->GetParticleCPU(particleIndex), _data->Buffer->GetParticleCPU(_data->Buffer->CPU.Count), _data->Buffer->Stride); \
|
||||
context.Data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(context.Data->Buffer->GetParticleCPU(particleIndex), context.Data->Buffer->GetParticleCPU(context.Data->Buffer->CPU.Count), context.Data->Buffer->Stride); \
|
||||
particleIndex--; \
|
||||
} \
|
||||
positionPtr += stride
|
||||
@@ -366,7 +368,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -386,7 +388,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Kill (box)
|
||||
case 307:
|
||||
{
|
||||
auto& position = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& position = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + position.Offset;
|
||||
|
||||
@@ -409,8 +411,8 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
if (collision) \
|
||||
{ \
|
||||
particlesEnd--; \
|
||||
_data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(_data->Buffer->GetParticleCPU(particleIndex), _data->Buffer->GetParticleCPU(_data->Buffer->CPU.Count), _data->Buffer->Stride); \
|
||||
context.Data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(context.Data->Buffer->GetParticleCPU(particleIndex), context.Data->Buffer->GetParticleCPU(context.Data->Buffer->CPU.Count), context.Data->Buffer->Stride); \
|
||||
particleIndex--; \
|
||||
} \
|
||||
positionPtr += stride
|
||||
@@ -419,7 +421,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -447,8 +449,8 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
if (kill) \
|
||||
{ \
|
||||
particlesEnd--; \
|
||||
_data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(_data->Buffer->GetParticleCPU(particleIndex), _data->Buffer->GetParticleCPU(_data->Buffer->CPU.Count), _data->Buffer->Stride); \
|
||||
context.Data->Buffer->CPU.Count--; \
|
||||
Platform::MemoryCopy(context.Data->Buffer->GetParticleCPU(particleIndex), context.Data->Buffer->GetParticleCPU(context.Data->Buffer->CPU.Count), context.Data->Buffer->Stride); \
|
||||
particleIndex--; \
|
||||
}
|
||||
|
||||
@@ -456,7 +458,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -479,9 +481,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
auto box = node->GetBox(0);
|
||||
const bool useSpriteSize = node->Values[3].AsBool;
|
||||
|
||||
auto& velocity = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& mass = _data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
byte* spriteSizePtr = useSpriteSize ? start + _data->Buffer->Layout->Attributes[node->Attributes[2]].Offset : nullptr;
|
||||
auto& velocity = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& mass = context.Data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
byte* spriteSizePtr = useSpriteSize ? start + context.Data->Buffer->Layout->Attributes[node->Attributes[2]].Offset : nullptr;
|
||||
|
||||
byte* velocityPtr = start + velocity.Offset;
|
||||
byte* massPtr = start + mass.Offset;
|
||||
@@ -492,7 +494,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
float particleDrag = drag; \
|
||||
if (useSpriteSize) \
|
||||
particleDrag *= ((Vector2*)spriteSizePtr)->MulValues(); \
|
||||
*((Vector3*)velocityPtr) *= Math::Max(0.0f, 1.0f - (particleDrag * _deltaTime) / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
*((Vector3*)velocityPtr) *= Math::Max(0.0f, 1.0f - (particleDrag * context.DeltaTime) / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
velocityPtr += stride; \
|
||||
massPtr += stride; \
|
||||
spriteSizePtr += stride
|
||||
@@ -501,7 +503,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -521,9 +523,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Turbulence
|
||||
case 311:
|
||||
{
|
||||
auto& position = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocity = _data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& mass = _data->Buffer->Layout->Attributes[node->Attributes[2]];
|
||||
auto& position = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocity = context.Data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& mass = context.Data->Buffer->Layout->Attributes[node->Attributes[2]];
|
||||
|
||||
byte* positionPtr = start + position.Offset;
|
||||
byte* velocityPtr = start + velocity.Offset;
|
||||
@@ -551,7 +553,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
Vector3 vectorFieldUVW = Vector3::Transform(*((Vector3*)positionPtr), invFieldTransformMatrix); \
|
||||
Vector3 force = Noise3D(vectorFieldUVW + 0.5f, octavesCount, roughness); \
|
||||
force = Vector3::Transform(force, fieldTransformMatrix) * intensity; \
|
||||
*((Vector3*)velocityPtr) += force * (_deltaTime / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
*((Vector3*)velocityPtr) += force * (context.DeltaTime / Math::Max(*(float*)massPtr, ZeroTolerance)); \
|
||||
positionPtr += stride; \
|
||||
velocityPtr += stride; \
|
||||
massPtr += stride
|
||||
@@ -560,7 +562,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -581,7 +583,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
case 200:
|
||||
case 302:
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* dataPtr = start + attribute.Offset;
|
||||
int32 dataSize = attribute.GetSize();
|
||||
auto box = node->GetBox(0);
|
||||
@@ -590,7 +592,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
const Value value = GetValue(box, 4).Cast(type);
|
||||
Platform::MemoryCopy(dataPtr, &value.AsPointer, dataSize);
|
||||
dataPtr += stride;
|
||||
@@ -637,7 +639,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
case 362:
|
||||
case 363:
|
||||
{
|
||||
auto& attribute = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& attribute = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
byte* dataPtr = start + attribute.Offset;
|
||||
int32 dataSize = attribute.GetSize();
|
||||
auto box = node->GetBox(0);
|
||||
@@ -646,7 +648,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
const Value value = GetValue(box, 2).Cast(type);
|
||||
Platform::MemoryCopy(dataPtr, &value.AsPointer, dataSize);
|
||||
dataPtr += stride;
|
||||
@@ -666,7 +668,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (sphere surface)
|
||||
case 202:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -691,7 +693,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -711,7 +713,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (plane)
|
||||
case 203:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -729,7 +731,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -749,7 +751,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (circle)
|
||||
case 204:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -772,7 +774,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -792,7 +794,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (disc)
|
||||
case 205:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -815,7 +817,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -835,7 +837,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (box surface)
|
||||
case 206:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -865,7 +867,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -885,7 +887,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (box volume)
|
||||
case 207:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -903,7 +905,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -923,7 +925,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (cylinder)
|
||||
case 208:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -948,7 +950,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -968,7 +970,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (line)
|
||||
case 209:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -986,7 +988,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1006,7 +1008,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (torus)
|
||||
case 210:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -1050,7 +1052,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1070,7 +1072,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (sphere volume)
|
||||
case 211:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
|
||||
@@ -1095,7 +1097,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1121,8 +1123,8 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
// Position (spiral)
|
||||
case 214:
|
||||
{
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocityAttr = _data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]];
|
||||
auto& velocityAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[1]];
|
||||
|
||||
byte* positionPtr = start + positionAttr.Offset;
|
||||
byte* velocityPtr = start + velocityAttr.Offset;
|
||||
@@ -1131,7 +1133,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
auto rotationSpeedBox = node->GetBox(1);
|
||||
auto velocityScaleBox = node->GetBox(2);
|
||||
|
||||
auto& arc = node->SpiralModuleProgress;
|
||||
auto& arc = *(float*)&context.Data->CustomData[node->CustomDataOffset];
|
||||
|
||||
#define INPUTS_FETCH() \
|
||||
const Vector3 center = (Vector3)GetValue(centerBox, 2); \
|
||||
@@ -1151,7 +1153,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1171,9 +1173,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
|
||||
// Helper macros for collision modules to share the code
|
||||
#define COLLISION_BEGIN() \
|
||||
auto& positionAttr = _data->Buffer->Layout->Attributes[node->Attributes[0]]; \
|
||||
auto& velocityAttr = _data->Buffer->Layout->Attributes[node->Attributes[1]]; \
|
||||
auto& ageAttr = _data->Buffer->Layout->Attributes[node->Attributes[2]]; \
|
||||
auto& positionAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[0]]; \
|
||||
auto& velocityAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[1]]; \
|
||||
auto& ageAttr = context.Data->Buffer->Layout->Attributes[node->Attributes[2]]; \
|
||||
byte* positionPtr = start + positionAttr.Offset; \
|
||||
byte* velocityPtr = start + velocityAttr.Offset; \
|
||||
byte* agePtr = start + ageAttr.Offset; \
|
||||
@@ -1221,7 +1223,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
#define LOGIC() \
|
||||
Vector3 position = *(Vector3*)positionPtr; \
|
||||
Vector3 velocity = *(Vector3*)velocityPtr; \
|
||||
Vector3 nextPos = position + velocity * _deltaTime; \
|
||||
Vector3 nextPos = position + velocity * context.DeltaTime; \
|
||||
Vector3 n = planeNormal; \
|
||||
float distToPlane = Vector3::Dot(nextPos, n) - Vector3::Dot(planePosition, n) - radius; \
|
||||
if (distToPlane < 0.0f) \
|
||||
@@ -1233,7 +1235,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1263,7 +1265,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
#define LOGIC() \
|
||||
Vector3 position = *(Vector3*)positionPtr; \
|
||||
Vector3 velocity = *(Vector3*)velocityPtr; \
|
||||
Vector3 nextPos = position + velocity * _deltaTime; \
|
||||
Vector3 nextPos = position + velocity * context.DeltaTime; \
|
||||
Vector3 dir = nextPos - spherePosition; \
|
||||
float sqrLength = Vector3::Dot(dir, dir); \
|
||||
float totalRadius = sphereRadius + sign * radius; \
|
||||
@@ -1278,7 +1280,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1308,7 +1310,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
#define LOGIC() \
|
||||
Vector3 position = *(Vector3*)positionPtr; \
|
||||
Vector3 velocity = *(Vector3*)velocityPtr; \
|
||||
Vector3 nextPos = position + velocity * _deltaTime; \
|
||||
Vector3 nextPos = position + velocity * context.DeltaTime; \
|
||||
Vector3 dir = nextPos - boxPosition; \
|
||||
Vector3 absDir = Vector3::Abs(dir); \
|
||||
Vector3 halfBoxSize = boxSize * 0.5f + radius * sign; \
|
||||
@@ -1338,7 +1340,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
@@ -1370,7 +1372,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
#define LOGIC() \
|
||||
Vector3 position = *(Vector3*)positionPtr; \
|
||||
Vector3 velocity = *(Vector3*)velocityPtr; \
|
||||
Vector3 nextPos = position + velocity * _deltaTime; \
|
||||
Vector3 nextPos = position + velocity * context.DeltaTime; \
|
||||
Vector3 dir = nextPos - cylinderPosition; \
|
||||
float halfHeight = cylinderHeight * 0.5f + radius * sign; \
|
||||
float cylinderRadiusT = cylinderRadius + radius * sign; \
|
||||
@@ -1403,7 +1405,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessModule(ParticleEmitterGraphCPUNode*
|
||||
{
|
||||
for (int32 particleIndex = particlesStart; particleIndex < particlesEnd; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
INPUTS_FETCH();
|
||||
LOGIC();
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
|
||||
#define GET_VIEW() auto mainViewTask = MainRenderTask::Instance && MainRenderTask::Instance->LastUsedFrame != 0 ? MainRenderTask::Instance : nullptr
|
||||
#define ACCESS_PARTICLE_ATTRIBUTE(index) (_data->Buffer->GetParticleCPU(_particleIndex) + _data->Buffer->Layout->Attributes[node->Attributes[index]].Offset)
|
||||
#define ACCESS_PARTICLE_ATTRIBUTE(index) (context.Data->Buffer->GetParticleCPU(context.ParticleIndex) + context.Data->Buffer->Layout->Attributes[node->Attributes[index]].Offset)
|
||||
#define GET_PARTICLE_ATTRIBUTE(index, type) *(type*)ACCESS_PARTICLE_ATTRIBUTE(index)
|
||||
|
||||
void ParticleEmitterGraphCPUExecutor::ProcessGroupParameters(Box* box, Node* node, Value& value)
|
||||
{
|
||||
auto& context = Context.Get();
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Get
|
||||
@@ -21,7 +22,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParameters(Box* box, Node* nod
|
||||
const auto param = _graph.GetParameter((Guid)node->Values[0], paramIndex);
|
||||
if (param)
|
||||
{
|
||||
value = _data->Parameters[paramIndex];
|
||||
value = context.Data->Parameters[paramIndex];
|
||||
switch (param->Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
@@ -130,6 +131,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupTextures(Box* box, Node* node,
|
||||
|
||||
void ParticleEmitterGraphCPUExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
{
|
||||
auto& context = Context.Get();
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Linearize Depth
|
||||
@@ -141,15 +143,13 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupTools(Box* box, Node* node, Va
|
||||
}
|
||||
// Time
|
||||
case 8:
|
||||
{
|
||||
value = box->ID == 0 ? _data->Time : _deltaTime;
|
||||
value = box->ID == 0 ? context.Data->Time : context.DeltaTime;
|
||||
break;
|
||||
}
|
||||
// Transform Position To Screen UV
|
||||
case 9:
|
||||
{
|
||||
GET_VIEW();
|
||||
const Matrix viewProjection = _viewTask ? _viewTask->View.PrevViewProjection : Matrix::Identity;
|
||||
const Matrix viewProjection = context.ViewTask ? context.ViewTask->View.PrevViewProjection : Matrix::Identity;
|
||||
const Vector3 position = (Vector3)TryGetValue(node->GetBox(0), Value::Zero);
|
||||
Vector4 projPos;
|
||||
Vector3::Transform(position, viewProjection);
|
||||
@@ -165,6 +165,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupTools(Box* box, Node* node, Va
|
||||
|
||||
void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* nodeBase, Value& value)
|
||||
{
|
||||
auto& context = Context.Get();
|
||||
auto node = (ParticleEmitterGraphCPUNode*)nodeBase;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
@@ -199,8 +200,8 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
// Particle Attribute (by index)
|
||||
case 303:
|
||||
{
|
||||
const auto particleIndex = tryGetValue(node->GetBox(1), _particleIndex);
|
||||
byte* ptr = (_data->Buffer->GetParticleCPU((uint32)particleIndex) + _data->Buffer->Layout->Attributes[node->Attributes[0]].Offset);
|
||||
const auto particleIndex = tryGetValue(node->GetBox(1), context.ParticleIndex);
|
||||
byte* ptr = (context.Data->Buffer->GetParticleCPU((uint32)particleIndex) + context.Data->Buffer->Layout->Attributes[node->Attributes[0]].Offset);
|
||||
switch ((ParticleAttribute::ValueTypes)node->Attributes[1])
|
||||
{
|
||||
case ParticleAttribute::ValueTypes::Float:
|
||||
@@ -296,19 +297,19 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
// Effect Position
|
||||
case 200:
|
||||
{
|
||||
value = _effect->GetPosition();
|
||||
value = context.Effect->GetPosition();
|
||||
break;
|
||||
}
|
||||
// Effect Rotation
|
||||
case 201:
|
||||
{
|
||||
value = _effect->GetOrientation();
|
||||
value = context.Effect->GetOrientation();
|
||||
break;
|
||||
}
|
||||
// Effect Scale
|
||||
case 202:
|
||||
{
|
||||
value = _effect->GetScale();
|
||||
value = context.Effect->GetScale();
|
||||
break;
|
||||
}
|
||||
// Simulation Mode
|
||||
@@ -320,25 +321,25 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
// View Position
|
||||
case 204:
|
||||
{
|
||||
value = _viewTask ? _viewTask->View.Position : Vector3::Zero;
|
||||
value = context.ViewTask ? context.ViewTask->View.Position : Vector3::Zero;
|
||||
break;
|
||||
}
|
||||
// View Direction
|
||||
case 205:
|
||||
{
|
||||
value = _viewTask ? _viewTask->View.Direction : Vector3::Forward;
|
||||
value = context.ViewTask ? context.ViewTask->View.Direction : Vector3::Forward;
|
||||
break;
|
||||
}
|
||||
// View Far Plane
|
||||
case 206:
|
||||
{
|
||||
value = _viewTask ? _viewTask->View.Far : 0.0f;
|
||||
value = context.ViewTask ? context.ViewTask->View.Far : 0.0f;
|
||||
break;
|
||||
}
|
||||
// Screen Size
|
||||
case 207:
|
||||
{
|
||||
const Vector4 size = _viewTask ? _viewTask->View.ScreenSize : Vector4::Zero;
|
||||
const Vector4 size = context.ViewTask ? context.ViewTask->View.ScreenSize : Vector4::Zero;
|
||||
if (box->ID == 0)
|
||||
value = Vector2(size.X, size.Y);
|
||||
else
|
||||
@@ -358,11 +359,11 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
|
||||
#if 0
|
||||
// Prevent recursive calls
|
||||
for (int32 i = _callStack.Count() - 1; i >= 0; i--)
|
||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300))
|
||||
if (context.CallStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300))
|
||||
{
|
||||
const auto callFunc = ((ParticleEmitterGraphCPUNode*)_callStack[i])->Assets[0].Get();
|
||||
const auto callFunc = context.CallStack[i]->Assets[0].Get();
|
||||
if (callFunc == function)
|
||||
{
|
||||
value = Value::Zero;
|
||||
@@ -372,14 +373,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create a instanced version of the function graph
|
||||
ParticleEmitterGraphCPU* graph;
|
||||
if (!_functions.TryGet(nodeBase, graph))
|
||||
{
|
||||
graph = New<ParticleEmitterGraphCPU>();
|
||||
function->LoadSurface((ParticleEmitterGraphCPU&)*graph);
|
||||
_functions.Add(nodeBase, graph);
|
||||
}
|
||||
// Get function graph
|
||||
Graph* graph = (Graph*)&function->Graph;
|
||||
context.Functions[nodeBase] = graph;
|
||||
|
||||
// Peek the function output (function->Outputs maps the functions outputs to output nodes indices)
|
||||
const int32 outputIndex = box->ID - 16;
|
||||
@@ -388,22 +384,22 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
ParticleEmitterGraphCPU::Node* functionOutputNode = &graph->Nodes[function->Outputs[outputIndex]];
|
||||
Node* functionOutputNode = &graph->Nodes[function->Outputs[outputIndex]];
|
||||
Box* functionOutputBox = functionOutputNode->TryGetBox(0);
|
||||
|
||||
// Evaluate the function output
|
||||
_graphStack.Push((Graph*)graph);
|
||||
context.GraphStack.Push(graph);
|
||||
value = functionOutputBox && functionOutputBox->HasConnection() ? eatBox(nodeBase, functionOutputBox->FirstConnection()) : Value::Zero;
|
||||
_graphStack.Pop();
|
||||
context.GraphStack.Pop();
|
||||
break;
|
||||
}
|
||||
// Particle Index
|
||||
case 301:
|
||||
value = _particleIndex;
|
||||
value = context.ParticleIndex;
|
||||
break;
|
||||
// Particles Count
|
||||
case 302:
|
||||
value = (uint32)_data->Buffer->CPU.Count;
|
||||
value = (uint32)context.Data->Buffer->CPU.Count;
|
||||
break;
|
||||
default:
|
||||
VisjectExecutor::ProcessGroupParticles(box, nodeBase, value);
|
||||
@@ -413,20 +409,21 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
|
||||
void ParticleEmitterGraphCPUExecutor::ProcessGroupFunction(Box* box, Node* node, Value& value)
|
||||
{
|
||||
auto& context = Context.Get();
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Function Input
|
||||
case 1:
|
||||
{
|
||||
// Find the function call
|
||||
ParticleEmitterGraphCPUNode* functionCallNode = nullptr;
|
||||
ASSERT(_graphStack.Count() >= 2);
|
||||
ParticleEmitterGraphCPU* graph;
|
||||
for (int32 i = _callStack.Count() - 1; i >= 0; i--)
|
||||
Node* functionCallNode = nullptr;
|
||||
ASSERT(context.GraphStack.Count() >= 2);
|
||||
Graph* graph;
|
||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300) && _functions.TryGet(_callStack[i], graph) && _graphStack[_graphStack.Count() - 1] == (Graph*)graph)
|
||||
if (context.CallStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300) && context.Functions.TryGet(context.CallStack[i], graph) && context.GraphStack[context.GraphStack.Count() - 1] == graph)
|
||||
{
|
||||
functionCallNode = (ParticleEmitterGraphCPUNode*)_callStack[i];
|
||||
functionCallNode = context.CallStack[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -436,7 +433,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupFunction(Box* box, Node* node,
|
||||
break;
|
||||
}
|
||||
const auto function = functionCallNode->Assets[0].As<ParticleEmitterFunction>();
|
||||
if (!_functions.TryGet((Node*)functionCallNode, graph) || !function)
|
||||
if (!context.Functions.TryGet(functionCallNode, graph) || !function)
|
||||
{
|
||||
value = Value::Zero;
|
||||
break;
|
||||
@@ -461,9 +458,9 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupFunction(Box* box, Node* node,
|
||||
if (functionCallBox && functionCallBox->HasConnection())
|
||||
{
|
||||
// Use provided input value from the function call
|
||||
_graphStack.Pop();
|
||||
context.GraphStack.Pop();
|
||||
value = eatBox(node, functionCallBox->FirstConnection());
|
||||
_graphStack.Push((Graph*)graph);
|
||||
context.GraphStack.Push(graph);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Engine/Particles/ParticleEffect.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
|
||||
ThreadLocal<ParticleEmitterGraphCPUContext, 64> ParticleEmitterGraphCPUExecutor::Context;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool SortRibbonParticles(const int32& a, const int32& b, ParticleBufferCPUDataAccessor<float>* data)
|
||||
@@ -35,8 +37,7 @@ void ParticleEmitterGraphCPU::CreateDefault()
|
||||
|
||||
bool ParticleEmitterGraphCPU::Load(ReadStream* stream, bool loadMeta)
|
||||
{
|
||||
// Base
|
||||
if (ParticleEmitterGraph::Load(stream, loadMeta))
|
||||
if (Base::Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
// Assign the offset in the sorted indices buffer to the rendering modules
|
||||
@@ -61,7 +62,7 @@ bool ParticleEmitterGraphCPU::Load(ReadStream* stream, bool loadMeta)
|
||||
for (int32 i = 0; i < RibbonRenderingModules.Count(); i++)
|
||||
{
|
||||
const auto module = RibbonRenderingModules[i];
|
||||
module->Ribbon.RibbonOrderOffset = ribbonOrderOffset;
|
||||
module->RibbonOrderOffset = ribbonOrderOffset;
|
||||
ribbonOrderOffset += Capacity;
|
||||
}
|
||||
|
||||
@@ -96,18 +97,16 @@ void ParticleEmitterGraphCPU::InitializeNode(Node* node)
|
||||
if (node->Used)
|
||||
return;
|
||||
|
||||
// Base
|
||||
ParticleEmitterGraph::InitializeNode(node);
|
||||
Base::InitializeNode(node);
|
||||
|
||||
switch (node->Type)
|
||||
{
|
||||
// Position (spiral)
|
||||
case GRAPH_NODE_MAKE_TYPE(15, 214):
|
||||
{
|
||||
node->SpiralModuleProgress = 0.0f;
|
||||
node->CustomDataOffset = CustomDataSize;
|
||||
CustomDataSize += sizeof(float);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParticleEmitterGraphCPUExecutor::ParticleEmitterGraphCPUExecutor(ParticleEmitterGraphCPU& graph)
|
||||
@@ -120,9 +119,19 @@ ParticleEmitterGraphCPUExecutor::ParticleEmitterGraphCPUExecutor(ParticleEmitter
|
||||
_perGroupProcessCall[16] = (ProcessBoxHandler)&ParticleEmitterGraphCPUExecutor::ProcessGroupFunction;
|
||||
}
|
||||
|
||||
ParticleEmitterGraphCPUExecutor::~ParticleEmitterGraphCPUExecutor()
|
||||
void ParticleEmitterGraphCPUExecutor::Init(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt)
|
||||
{
|
||||
_functions.ClearDelete();
|
||||
auto& context = Context.Get();
|
||||
context.GraphStack.Clear();
|
||||
context.GraphStack.Push((Graph*)&_graph);
|
||||
context.Data = &data;
|
||||
context.Emitter = emitter;
|
||||
context.Effect = effect;
|
||||
context.DeltaTime = dt;
|
||||
context.ParticleIndex = 0;
|
||||
context.ViewTask = effect->GetRenderTask();
|
||||
context.CallStack.Clear();
|
||||
context.Functions.Clear();
|
||||
}
|
||||
|
||||
bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, BoundingBox& result)
|
||||
@@ -240,20 +249,14 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
case 401:
|
||||
{
|
||||
// Prepare graph data
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
_data = &data;
|
||||
_emitter = emitter;
|
||||
_effect = effect;
|
||||
_deltaTime = 0.0f;
|
||||
_viewTask = effect->GetRenderTask();
|
||||
_callStack.Clear();
|
||||
auto& context = Context.Get();
|
||||
Init(emitter, effect, data);
|
||||
|
||||
// Find the maximum radius of the particle light
|
||||
float maxRadius = 0.0f;
|
||||
for (int32 particleIndex = 0; particleIndex < count; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
const float radius = (float)GetValue(module->GetBox(1), 3);
|
||||
if (radius > maxRadius)
|
||||
maxRadius = radius;
|
||||
@@ -370,14 +373,8 @@ void ParticleEmitterGraphCPUExecutor::Draw(ParticleEmitter* emitter, ParticleEff
|
||||
const int32 stride = buffer->Stride;
|
||||
|
||||
// Prepare graph data
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
_data = &data;
|
||||
_emitter = emitter;
|
||||
_effect = effect;
|
||||
_deltaTime = 0.0f;
|
||||
_viewTask = effect->GetRenderTask();
|
||||
_callStack.Clear();
|
||||
Init(emitter, effect, data);
|
||||
auto& context = Context.Get();
|
||||
|
||||
// Draw lights
|
||||
for (int32 moduleIndex = 0; moduleIndex < emitter->Graph.LightModules.Count(); moduleIndex++)
|
||||
@@ -405,7 +402,7 @@ void ParticleEmitterGraphCPUExecutor::Draw(ParticleEmitter* emitter, ParticleEff
|
||||
|
||||
for (int32 particleIndex = 0; particleIndex < count; particleIndex++)
|
||||
{
|
||||
_particleIndex = particleIndex;
|
||||
context.ParticleIndex = particleIndex;
|
||||
|
||||
const Vector4 color = (Vector4)GetValue(module->GetBox(0), 2);
|
||||
const float radius = (float)GetValue(module->GetBox(1), 3);
|
||||
@@ -429,15 +426,8 @@ void ParticleEmitterGraphCPUExecutor::Draw(ParticleEmitter* emitter, ParticleEff
|
||||
void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt, bool canSpawn)
|
||||
{
|
||||
// Prepare data
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
_data = &data;
|
||||
_emitter = emitter;
|
||||
_effect = effect;
|
||||
_particleIndex = 0;
|
||||
_deltaTime = dt;
|
||||
_viewTask = effect->GetRenderTask();
|
||||
_callStack.Clear();
|
||||
Init(emitter, effect, data, dt);
|
||||
auto& context = Context.Get();
|
||||
auto& cpu = data.Buffer->CPU;
|
||||
|
||||
// Update particles
|
||||
@@ -452,20 +442,20 @@ void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleE
|
||||
// Dead particles removal
|
||||
if (_graph._attrAge != -1 && _graph._attrLifetime != -1)
|
||||
{
|
||||
byte* agePtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrAge].Offset;
|
||||
byte* lifetimePtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrLifetime].Offset;
|
||||
byte* agePtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrAge].Offset;
|
||||
byte* lifetimePtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrLifetime].Offset;
|
||||
for (int32 particleIndex = 0; particleIndex < cpu.Count; particleIndex++)
|
||||
{
|
||||
if (*(float*)agePtr >= *(float*)lifetimePtr)
|
||||
{
|
||||
cpu.Count--;
|
||||
Platform::MemoryCopy(_data->Buffer->GetParticleCPU(particleIndex), _data->Buffer->GetParticleCPU(cpu.Count), _data->Buffer->Stride);
|
||||
Platform::MemoryCopy(data.Buffer->GetParticleCPU(particleIndex), data.Buffer->GetParticleCPU(cpu.Count), data.Buffer->Stride);
|
||||
particleIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
agePtr += _data->Buffer->Stride;
|
||||
lifetimePtr += _data->Buffer->Stride;
|
||||
agePtr += data.Buffer->Stride;
|
||||
lifetimePtr += data.Buffer->Stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,12 +464,12 @@ void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleE
|
||||
// Debug validation for NANs in data
|
||||
if (_graph._attrPosition != -1)
|
||||
{
|
||||
byte* positionPtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrPosition].Offset;
|
||||
byte* positionPtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrPosition].Offset;
|
||||
for (int32 particleIndex = 0; particleIndex < cpu.Count; particleIndex++)
|
||||
{
|
||||
Vector3 pos = *((Vector3*)positionPtr);
|
||||
ASSERT(!pos.IsNanOrInfinity());
|
||||
positionPtr += _data->Buffer->Stride;
|
||||
positionPtr += data.Buffer->Stride;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -487,26 +477,26 @@ void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleE
|
||||
// Euler integration
|
||||
if (_graph._attrPosition != -1 && _graph._attrVelocity != -1)
|
||||
{
|
||||
byte* positionPtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrPosition].Offset;
|
||||
byte* velocityPtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrVelocity].Offset;
|
||||
byte* positionPtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrPosition].Offset;
|
||||
byte* velocityPtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrVelocity].Offset;
|
||||
for (int32 particleIndex = 0; particleIndex < cpu.Count; particleIndex++)
|
||||
{
|
||||
*((Vector3*)positionPtr) += *((Vector3*)velocityPtr) * _deltaTime;
|
||||
positionPtr += _data->Buffer->Stride;
|
||||
velocityPtr += _data->Buffer->Stride;
|
||||
*((Vector3*)positionPtr) += *((Vector3*)velocityPtr) * dt;
|
||||
positionPtr += data.Buffer->Stride;
|
||||
velocityPtr += data.Buffer->Stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Angular Euler Integration
|
||||
if (_graph._attrRotation != -1 && _graph._attrAngularVelocity != -1)
|
||||
{
|
||||
byte* rotationPtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrRotation].Offset;
|
||||
byte* angularVelocityPtr = cpu.Buffer.Get() + _data->Buffer->Layout->Attributes[_graph._attrAngularVelocity].Offset;
|
||||
byte* rotationPtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrRotation].Offset;
|
||||
byte* angularVelocityPtr = cpu.Buffer.Get() + data.Buffer->Layout->Attributes[_graph._attrAngularVelocity].Offset;
|
||||
for (int32 particleIndex = 0; particleIndex < cpu.Count; particleIndex++)
|
||||
{
|
||||
*((Vector3*)rotationPtr) += *((Vector3*)angularVelocityPtr) * _deltaTime;
|
||||
rotationPtr += _data->Buffer->Stride;
|
||||
angularVelocityPtr += _data->Buffer->Stride;
|
||||
*((Vector3*)rotationPtr) += *((Vector3*)angularVelocityPtr) * dt;
|
||||
rotationPtr += data.Buffer->Stride;
|
||||
angularVelocityPtr += data.Buffer->Stride;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,16 +535,14 @@ void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleE
|
||||
// Sort ribbon particles
|
||||
if (cpu.RibbonOrder.IsEmpty())
|
||||
{
|
||||
cpu.RibbonOrder.Resize(_graph.RibbonRenderingModules.Count() * _data->Buffer->Capacity);
|
||||
cpu.RibbonOrder.Resize(_graph.RibbonRenderingModules.Count() * data.Buffer->Capacity);
|
||||
}
|
||||
ASSERT(cpu.RibbonOrder.Count() == _graph.RibbonRenderingModules.Count() * _data->Buffer->Capacity);
|
||||
ASSERT(cpu.RibbonOrder.Count() == _graph.RibbonRenderingModules.Count() * data.Buffer->Capacity);
|
||||
for (int32 i = 0; i < _graph.RibbonRenderingModules.Count(); i++)
|
||||
{
|
||||
const auto module = _graph.RibbonRenderingModules[i];
|
||||
|
||||
ParticleBufferCPUDataAccessor<float> sortKeyData(_data->Buffer, emitter->Graph.Layout.GetAttributeOffset(module->Attributes[1]));
|
||||
|
||||
int32* ribbonOrderData = cpu.RibbonOrder.Get() + module->Ribbon.RibbonOrderOffset;
|
||||
ParticleBufferCPUDataAccessor<float> sortKeyData(data.Buffer, emitter->Graph.Layout.GetAttributeOffset(module->Attributes[1]));
|
||||
int32* ribbonOrderData = cpu.RibbonOrder.Get() + module->RibbonOrderOffset;
|
||||
|
||||
for (int32 j = 0; j < cpu.Count; j++)
|
||||
{
|
||||
@@ -567,23 +555,13 @@ void ParticleEmitterGraphCPUExecutor::Update(ParticleEmitter* emitter, ParticleE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
int32 ParticleEmitterGraphCPUExecutor::UpdateSpawn(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt)
|
||||
{
|
||||
// Prepare data
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
_data = &data;
|
||||
_emitter = emitter;
|
||||
_effect = effect;
|
||||
_particleIndex = 0;
|
||||
_deltaTime = dt;
|
||||
_viewTask = effect->GetRenderTask();
|
||||
_callStack.Clear();
|
||||
auto& context = Context.Get();
|
||||
Init(emitter, effect, data, dt);
|
||||
|
||||
// Spawn particles
|
||||
int32 spawnCount = 0;
|
||||
@@ -592,16 +570,14 @@ int32 ParticleEmitterGraphCPUExecutor::UpdateSpawn(ParticleEmitter* emitter, Par
|
||||
spawnCount += ProcessSpawnModule(i);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
_data = nullptr;
|
||||
|
||||
return spawnCount;
|
||||
}
|
||||
|
||||
VisjectExecutor::Value ParticleEmitterGraphCPUExecutor::eatBox(Node* caller, Box* box)
|
||||
{
|
||||
// Check if graph is looped or is too deep
|
||||
if (_callStack.Count() >= PARTICLE_EMITTER_MAX_CALL_STACK)
|
||||
auto& context = Context.Get();
|
||||
if (context.CallStack.Count() >= PARTICLE_EMITTER_MAX_CALL_STACK)
|
||||
{
|
||||
OnError(caller, box, TEXT("Graph is looped or too deep!"));
|
||||
return Value::Zero;
|
||||
@@ -615,7 +591,7 @@ VisjectExecutor::Value ParticleEmitterGraphCPUExecutor::eatBox(Node* caller, Box
|
||||
#endif
|
||||
|
||||
// Add to the calling stack
|
||||
_callStack.Add(caller);
|
||||
context.CallStack.Add(caller);
|
||||
|
||||
// Call per group custom processing event
|
||||
Value value;
|
||||
@@ -624,12 +600,13 @@ VisjectExecutor::Value ParticleEmitterGraphCPUExecutor::eatBox(Node* caller, Box
|
||||
(this->*func)(box, parentNode, value);
|
||||
|
||||
// Remove from the calling stack
|
||||
_callStack.RemoveLast();
|
||||
context.CallStack.RemoveLast();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
VisjectExecutor::Graph* ParticleEmitterGraphCPUExecutor::GetCurrentGraph() const
|
||||
{
|
||||
return _graphStack.Peek();
|
||||
auto& context = Context.Get();
|
||||
return context.GraphStack.Peek();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Particles/ParticlesData.h"
|
||||
#include "Engine/Visject/VisjectGraph.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Threading/ThreadLocal.h"
|
||||
|
||||
struct RenderContext;
|
||||
class ParticleEffect;
|
||||
@@ -31,16 +32,6 @@ class ParticleEmitterGraphCPUExecutor;
|
||||
|
||||
class ParticleEmitterGraphCPUBox : public VisjectGraphBox
|
||||
{
|
||||
public:
|
||||
|
||||
ParticleEmitterGraphCPUBox()
|
||||
{
|
||||
}
|
||||
|
||||
ParticleEmitterGraphCPUBox(void* parent, byte id, VariantType type)
|
||||
: VisjectGraphBox(parent, id, type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ParticleEmitterGraphCPUNode : public ParticleEmitterGraphNode<VisjectGraphNode<ParticleEmitterGraphCPUBox>>
|
||||
@@ -54,23 +45,13 @@ public:
|
||||
|
||||
union
|
||||
{
|
||||
/// <summary>
|
||||
/// The spiral position module progress value.
|
||||
/// </summary>
|
||||
float SpiralModuleProgress;
|
||||
|
||||
struct
|
||||
{
|
||||
int32 RibbonOrderOffset;
|
||||
} Ribbon;
|
||||
int32 CustomDataOffset;
|
||||
int32 RibbonOrderOffset;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// True if this node uses the per-particle data resolve instead of optimized whole-collection fetch.
|
||||
/// </summary>
|
||||
/// <returns>True if use per particle data resolve, otherwise can optimize resolve pass.</returns>
|
||||
FORCE_INLINE bool UsePerParticleDataResolve() const
|
||||
{
|
||||
return UsesParticleData || !IsConstant;
|
||||
@@ -83,32 +64,31 @@ public:
|
||||
class ParticleEmitterGraphCPU : public ParticleEmitterGraph<VisjectGraph<ParticleEmitterGraphCPUNode, ParticleEmitterGraphCPUBox, ParticleSystemParameter>, ParticleEmitterGraphCPUNode, Variant>
|
||||
{
|
||||
friend ParticleEmitterGraphCPUExecutor;
|
||||
typedef ParticleEmitterGraph<VisjectGraph<ParticleEmitterGraphCPUNode, ParticleEmitterGraphCPUBox, ParticleSystemParameter>, ParticleEmitterGraphCPUNode, Variant> Base;
|
||||
private:
|
||||
|
||||
struct NodeState
|
||||
{
|
||||
union
|
||||
{
|
||||
int32 SpiralProgress;
|
||||
};
|
||||
};
|
||||
Array<byte> _defaultParticleData;
|
||||
|
||||
public:
|
||||
|
||||
// Size of the custom pre-node data buffer used for state tracking (eg. position on spiral arc progression).
|
||||
int32 CustomDataSize = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the default surface graph (the main root node) for the particle emitter. Ensure to dispose the previous graph data before.
|
||||
/// </summary>
|
||||
void CreateDefault();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Determines whenever this emitter uses lights rendering.
|
||||
/// </summary>
|
||||
/// <returns>True if emitter uses lights rendering, otherwise false.</returns>
|
||||
FORCE_INLINE bool UsesLightRendering() const
|
||||
{
|
||||
return LightModules.HasItems();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position attribute offset from the particle data layout start (in bytes).
|
||||
/// </summary>
|
||||
/// <returns>The offset in bytes.</returns>
|
||||
FORCE_INLINE int32 GetPositionAttributeOffset() const
|
||||
{
|
||||
return _attrPosition != -1 ? Layout.Attributes[_attrPosition].Offset : -1;
|
||||
@@ -117,7 +97,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the age attribute offset from the particle data layout start (in bytes).
|
||||
/// </summary>
|
||||
/// <returns>The offset in bytes.</returns>
|
||||
FORCE_INLINE int32 GetAgeAttributeOffset() const
|
||||
{
|
||||
return _attrAge != -1 ? Layout.Attributes[_attrAge].Offset : -1;
|
||||
@@ -127,37 +106,35 @@ public:
|
||||
|
||||
// [ParticleEmitterGraph]
|
||||
bool Load(ReadStream* stream, bool loadMeta) override;
|
||||
|
||||
bool onNodeLoaded(Node* n) override
|
||||
{
|
||||
ParticleEmitterGraph::onNodeLoaded(n);
|
||||
return VisjectGraph::onNodeLoaded(n);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// [ParticleEmitterGraph]
|
||||
void InitializeNode(Node* node) override;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The CPU particles emitter graph evaluation context.
|
||||
/// </summary>
|
||||
struct ParticleEmitterGraphCPUContext
|
||||
{
|
||||
float DeltaTime;
|
||||
uint32 ParticleIndex;
|
||||
ParticleEmitterInstance* Data;
|
||||
ParticleEmitter* Emitter;
|
||||
ParticleEffect* Effect;
|
||||
class SceneRenderTask* ViewTask;
|
||||
Array<VisjectExecutor::Node*, FixedAllocation<PARTICLE_EMITTER_MAX_CALL_STACK>> CallStack;
|
||||
Array<VisjectExecutor::Graph*, FixedAllocation<32>> GraphStack;
|
||||
Dictionary<VisjectExecutor::Node*, VisjectExecutor::Graph*> Functions;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The Particle Emitter Graph simulation on a CPU.
|
||||
/// </summary>
|
||||
class ParticleEmitterGraphCPUExecutor : public VisjectExecutor
|
||||
{
|
||||
private:
|
||||
|
||||
// Runtime
|
||||
ParticleEmitterGraphCPU& _graph;
|
||||
float _deltaTime;
|
||||
uint32 _particleIndex;
|
||||
ParticleEmitterInstance* _data;
|
||||
ParticleEmitter* _emitter;
|
||||
ParticleEffect* _effect;
|
||||
class SceneRenderTask* _viewTask;
|
||||
Array<Node*, FixedAllocation<PARTICLE_EMITTER_MAX_CALL_STACK>> _callStack;
|
||||
Array<Graph*, FixedAllocation<32>> _graphStack;
|
||||
Dictionary<Node*, ParticleEmitterGraphCPU*> _functions;
|
||||
|
||||
// Per-thread context to allow async execution
|
||||
static ThreadLocal<ParticleEmitterGraphCPUContext, 64> Context;
|
||||
|
||||
public:
|
||||
|
||||
@@ -167,11 +144,6 @@ public:
|
||||
/// <param name="graph">The graph to execute.</param>
|
||||
explicit ParticleEmitterGraphCPUExecutor(ParticleEmitterGraphCPU& graph);
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="ParticleEmitterGraphCPUExecutor"/> class.
|
||||
/// </summary>
|
||||
~ParticleEmitterGraphCPUExecutor();
|
||||
|
||||
/// <summary>
|
||||
/// Computes the local bounds of the particle emitter instance.
|
||||
/// </summary>
|
||||
@@ -214,6 +186,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void Init(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, float dt = 0.0f);
|
||||
Value eatBox(Node* caller, Box* box) override;
|
||||
Graph* GetCurrentGraph() const override;
|
||||
|
||||
@@ -226,17 +199,7 @@ private:
|
||||
int32 ProcessSpawnModule(int32 index);
|
||||
void ProcessModule(ParticleEmitterGraphCPUNode* node, int32 particlesStart, int32 particlesEnd);
|
||||
|
||||
Value TryGetValue(Box* box, int32 defaultValueBoxIndex, const Value& defaultValue)
|
||||
{
|
||||
const auto parentNode = box->GetParent<Node>();
|
||||
if (box->HasConnection())
|
||||
return eatBox(parentNode, box->FirstConnection());
|
||||
if (parentNode->Values.Count() > defaultValueBoxIndex)
|
||||
return parentNode->Values[defaultValueBoxIndex];
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
Value GetValue(Box* box, int32 defaultValueBoxIndex)
|
||||
FORCE_INLINE Value GetValue(Box* box, int32 defaultValueBoxIndex)
|
||||
{
|
||||
const auto parentNode = box->GetParent<Node>();
|
||||
if (box->HasConnection())
|
||||
|
||||
@@ -52,36 +52,18 @@ public:
|
||||
/// <summary>
|
||||
/// The Particle Emitter Graph used to simulate particles.
|
||||
/// </summary>
|
||||
template<class Base, class NodeType, class ValueType>
|
||||
class ParticleEmitterGraph : public Base
|
||||
template<class BaseType, class NodeType, class ValueType>
|
||||
class ParticleEmitterGraph : public BaseType
|
||||
{
|
||||
public:
|
||||
|
||||
typedef ValueType Value;
|
||||
|
||||
/// <summary>
|
||||
/// The particle emitter module types.
|
||||
/// </summary>
|
||||
enum class ModuleType
|
||||
{
|
||||
/// <summary>
|
||||
/// The spawn module.
|
||||
/// </summary>
|
||||
Spawn,
|
||||
|
||||
/// <summary>
|
||||
/// The init module.
|
||||
/// </summary>
|
||||
Initialize,
|
||||
|
||||
/// <summary>
|
||||
/// The update module.
|
||||
/// </summary>
|
||||
Update,
|
||||
|
||||
/// <summary>
|
||||
/// The render module.
|
||||
/// </summary>
|
||||
Render,
|
||||
};
|
||||
|
||||
@@ -172,8 +154,6 @@ public:
|
||||
|
||||
bool UsesVolumetricFogRendering = false;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void InitializeNode(NodeType* node)
|
||||
{
|
||||
// Skip if already initialized
|
||||
@@ -314,10 +294,8 @@ protected:
|
||||
}
|
||||
// Particle Emitter Function
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 300):
|
||||
{
|
||||
node->Assets[0] = Content::LoadAsync<Asset>((Guid)node->Values[0]);
|
||||
break;
|
||||
}
|
||||
// Particle Index
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 301):
|
||||
node->UsesParticleData = true;
|
||||
@@ -566,7 +544,7 @@ public:
|
||||
UsesVolumetricFogRendering = false;
|
||||
|
||||
// Base
|
||||
Base::Clear();
|
||||
BaseType::Clear();
|
||||
}
|
||||
|
||||
bool Load(ReadStream* stream, bool loadMeta) override
|
||||
@@ -575,7 +553,7 @@ public:
|
||||
Version++;
|
||||
|
||||
// Base
|
||||
if (Base::Load(stream, loadMeta))
|
||||
if (BaseType::Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
// Compute particle data layout and initialize used nodes (for only used nodes, start depth searching rom the modules)
|
||||
@@ -678,6 +656,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
return Base::onNodeLoaded(n);
|
||||
return BaseType::onNodeLoaded(n);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ Asset::LoadResult ParticleEmitter::load()
|
||||
EnablePooling = root->Values[3].AsBool;
|
||||
CustomBounds = (BoundingBox)root->Values[4];
|
||||
UseAutoBounds = root->Values[5].AsBool;
|
||||
IsUsingLights = Graph.UsesLightRendering();
|
||||
IsUsingLights = Graph.LightModules.HasItems();
|
||||
}
|
||||
|
||||
// Select simulation mode
|
||||
|
||||
@@ -24,6 +24,14 @@ Asset::LoadResult ParticleEmitterFunction::load()
|
||||
MemoryReadStream stream(surfaceChunk->Get(), surfaceChunk->Size());
|
||||
if (Graph.Load(&stream, false))
|
||||
return LoadResult::Failed;
|
||||
for (int32 i = 0; i < Graph.Nodes.Count(); i++)
|
||||
{
|
||||
// Initialize all used nodes (starting from function output as roots)
|
||||
if (Graph.Nodes[i].Type == GRAPH_NODE_MAKE_TYPE(16, 2))
|
||||
{
|
||||
Graph.InitializeNode(&Graph.Nodes[i]);
|
||||
}
|
||||
}
|
||||
#if COMPILE_WITH_PARTICLE_GPU_GRAPH
|
||||
stream.SetPosition(0);
|
||||
if (GraphGPU.Load(&stream, false))
|
||||
|
||||
@@ -335,7 +335,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
break;
|
||||
int32 count = buffer->CPU.Count;
|
||||
ASSERT(buffer->CPU.RibbonOrder.Count() == emitter->Graph.RibbonRenderingModules.Count() * buffer->Capacity);
|
||||
int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->Ribbon.RibbonOrderOffset;
|
||||
int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->RibbonOrderOffset;
|
||||
|
||||
ParticleBufferCPUDataAccessor<Vector3> positionData(buffer, emitter->Graph.Layout.GetAttributeOffset(module->Attributes[0]));
|
||||
|
||||
@@ -483,7 +483,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
Vector2 uvOffset = module->Values[5].AsVector2();
|
||||
|
||||
ParticleBufferCPUDataAccessor<float> sortKeyData(buffer, emitter->Graph.Layout.GetAttributeOffset(module->Attributes[1]));
|
||||
int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->Ribbon.RibbonOrderOffset;
|
||||
int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->RibbonOrderOffset;
|
||||
int32 count = buffer->CPU.Count;
|
||||
|
||||
// Setup ribbon data
|
||||
@@ -1073,6 +1073,7 @@ ParticleBuffer* Particles::AcquireParticleBuffer(ParticleEmitter* emitter)
|
||||
|
||||
if (emitter->EnablePooling && EnableParticleBufferPooling)
|
||||
{
|
||||
PoolLocker.Lock();
|
||||
const auto entries = Pool.TryGet(emitter);
|
||||
if (entries)
|
||||
{
|
||||
@@ -1087,7 +1088,6 @@ ParticleBuffer* Particles::AcquireParticleBuffer(ParticleEmitter* emitter)
|
||||
{
|
||||
Delete(result);
|
||||
result = nullptr;
|
||||
|
||||
if (entries->IsEmpty())
|
||||
{
|
||||
Pool.Remove(emitter);
|
||||
@@ -1096,6 +1096,7 @@ ParticleBuffer* Particles::AcquireParticleBuffer(ParticleEmitter* emitter)
|
||||
}
|
||||
}
|
||||
}
|
||||
PoolLocker.Unlock();
|
||||
}
|
||||
|
||||
if (!result)
|
||||
|
||||
@@ -24,6 +24,7 @@ void ParticleEmitterInstance::ClearState()
|
||||
Version = 0;
|
||||
Time = 0;
|
||||
SpawnModulesData.Clear();
|
||||
CustomData.Clear();
|
||||
#if COMPILE_WITH_GPU_PARTICLES
|
||||
GPU.DeltaTime = 0.0f;
|
||||
GPU.SpawnCount = 0;
|
||||
@@ -61,12 +62,16 @@ void ParticleEmitterInstance::Sync(ParticleSystemInstance& systemInstance, Parti
|
||||
if (SpawnModulesData.Count() != emitter->Graph.SpawnModules.Count())
|
||||
{
|
||||
SpawnModulesData.Resize(emitter->Graph.SpawnModules.Count(), false);
|
||||
|
||||
SpawnerData data;
|
||||
data.SpawnCounter = 0;
|
||||
data.NextSpawnTime = 0;
|
||||
SpawnModulesData.SetAll(data);
|
||||
}
|
||||
if (CustomData.Count() != emitter->Graph.CustomDataSize)
|
||||
{
|
||||
CustomData.Resize(emitter->Graph.CustomDataSize, false);
|
||||
Platform::MemoryClear(CustomData.Get(), CustomData.Count());
|
||||
}
|
||||
}
|
||||
|
||||
// Sync buffer version
|
||||
|
||||
@@ -83,8 +83,10 @@ public:
|
||||
/// </summary>
|
||||
Array<SpawnerData> SpawnModulesData;
|
||||
|
||||
#if COMPILE_WITH_GPU_PARTICLES
|
||||
// Custom per-node data (eg. position on spiral module for arc progress tracking)
|
||||
Array<byte> CustomData;
|
||||
|
||||
#if COMPILE_WITH_GPU_PARTICLES
|
||||
struct
|
||||
{
|
||||
/// <summary>
|
||||
@@ -97,7 +99,6 @@ public:
|
||||
/// </summary>
|
||||
int32 SpawnCount;
|
||||
} GPU;
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user