forked from Mirrors/openclonk
dynamic particles: made the attachment an entry in the particle properties
parent
32968f2735
commit
0707458264
|
@ -133,12 +133,17 @@
|
|||
<row>
|
||||
<col>CollisionVertex</col>
|
||||
<col>0 to 1000</col>
|
||||
<col>The offset of the particle's hit point relative to its width. When set, the particle will collide with the landscape. If unsure, something around 750 should be fine.</col>
|
||||
<col>The offset of the particle's hit point relative to its width. When set, the particle will collide with the landscape. 0 means the particle will collide with its center.</col>
|
||||
</row>
|
||||
<row>
|
||||
<col>OnCollision</col>
|
||||
<col><funclink>PC_Die</funclink>, <funclink>PC_Bounce</funclink></col>
|
||||
<col>Defines what happens when the particle collides with the landscape.</col>
|
||||
</row>
|
||||
<row>
|
||||
<col>Attach</col>
|
||||
<col>bit mask</col>
|
||||
<col>Defines the attachment of the particles to the calling object. Can be a combination of ATTACH_Front, ATTACH_Back, and ATTACH_MoveRelative. For example <code>ATTACH_Front | ATTACH_MoveRelative</code></col>
|
||||
</row>
|
||||
</table>
|
||||
</text>
|
||||
|
|
|
@ -1533,7 +1533,7 @@ static bool FnCreateParticle(C4PropList * _this, C4String *szName, long iX, long
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool FnCreateParticleEx(C4PropList * _this, C4String *name, long x, long y, C4Value speedX, C4Value speedY, C4Value lifetime, C4PropList *properties, int amount, int attachment)
|
||||
static bool FnCreateParticleEx(C4PropList * _this, C4String *name, long x, long y, C4Value speedX, C4Value speedY, C4Value lifetime, C4PropList *properties, int amount)
|
||||
{
|
||||
// safety
|
||||
C4Object *obj = Object(_this);
|
||||
|
@ -1541,12 +1541,6 @@ static bool FnCreateParticleEx(C4PropList * _this, C4String *name, long x, long
|
|||
#ifndef USE_CONSOLE
|
||||
if (amount <= 0) amount = 1;
|
||||
|
||||
// local offset
|
||||
if (obj)
|
||||
{
|
||||
x += obj->GetX();
|
||||
y += obj->GetY();
|
||||
}
|
||||
// get particle
|
||||
C4ParticleDef *pDef=::Particles.GetDef(FnStringPar(name));
|
||||
if (!pDef) return false;
|
||||
|
@ -1556,7 +1550,7 @@ static bool FnCreateParticleEx(C4PropList * _this, C4String *name, long x, long
|
|||
valueSpeedY.Set(speedY);
|
||||
valueLifetime.Set(lifetime);
|
||||
// create
|
||||
::DynamicParticles.Create(pDef, (float)x, (float)y, valueSpeedX, valueSpeedY, valueLifetime, properties, amount, obj ? (attachment == 1 ? obj->DynamicBackParticles : obj->DynamicFrontParticles) : NULL, obj);
|
||||
::DynamicParticles.Create(pDef, (float)x, (float)y, valueSpeedX, valueSpeedY, valueLifetime, properties, amount, obj);
|
||||
#endif
|
||||
// success, even if not created
|
||||
return true;
|
||||
|
@ -2684,6 +2678,10 @@ C4ScriptConstDef C4ScriptGameConstMap[]=
|
|||
{ "PLRZOOM_LimitMin" ,C4V_Int, PLRZOOM_LimitMin },
|
||||
{ "PLRZOOM_LimitMax" ,C4V_Int, PLRZOOM_LimitMax },
|
||||
|
||||
{ "ATTACH_Front" ,C4V_Int, C4ATTACH_Front },
|
||||
{ "ATTACH_Back" ,C4V_Int, C4ATTACH_Back },
|
||||
{ "ATTACH_MoveRelative" ,C4V_Int, C4ATTACH_MoveRelative },
|
||||
|
||||
{ NULL, C4V_Nil, 0}
|
||||
};
|
||||
|
||||
|
|
|
@ -43,28 +43,28 @@ void C4DynamicParticle::DrawingData::SetPosition(float x, float y, float size, f
|
|||
|
||||
if (rotation == 0.f)
|
||||
{
|
||||
vertices[0].x = x - sizeX;
|
||||
vertices[0].y = y + sizeY;
|
||||
vertices[1].x = x - sizeX;
|
||||
vertices[1].y = y - sizeY;
|
||||
vertices[2].x = x + sizeX;
|
||||
vertices[2].y = y + sizeY;
|
||||
vertices[3].x = x + sizeX;
|
||||
vertices[3].y = y - sizeY;
|
||||
vertices[0].x = x - sizeX + offsetX;
|
||||
vertices[0].y = y + sizeY + offsetY;
|
||||
vertices[1].x = x - sizeX + offsetX;
|
||||
vertices[1].y = y - sizeY + offsetY;
|
||||
vertices[2].x = x + sizeX + offsetX;
|
||||
vertices[2].y = y + sizeY + offsetY;
|
||||
vertices[3].x = x + sizeX + offsetX;
|
||||
vertices[3].y = y - sizeY + offsetY;
|
||||
}
|
||||
else
|
||||
{
|
||||
float sine = sinf(rotation);
|
||||
float cosine = cosf(rotation);
|
||||
|
||||
vertices[0].x = x + ((-sizeX) * cosine - (+sizeY) * sine);
|
||||
vertices[0].y = y + ((-sizeX) * sine + (+sizeY) * cosine);
|
||||
vertices[1].x = x + ((-sizeX) * cosine - (-sizeY) * sine);
|
||||
vertices[1].y = y + ((-sizeX) * sine + (-sizeY) * cosine);
|
||||
vertices[2].x = x + ((+sizeX) * cosine - (+sizeY) * sine);
|
||||
vertices[2].y = y + ((+sizeX) * sine + (+sizeY) * cosine);
|
||||
vertices[3].x = x + ((+sizeX) * cosine - (-sizeY) * sine);
|
||||
vertices[3].y = y + ((+sizeX) * sine + (-sizeY) * cosine);
|
||||
vertices[0].x = x + ((-sizeX) * cosine - (+sizeY) * sine) + offsetX;
|
||||
vertices[0].y = y + ((-sizeX) * sine + (+sizeY) * cosine) + offsetY;
|
||||
vertices[1].x = x + ((-sizeX) * cosine - (-sizeY) * sine) + offsetX;
|
||||
vertices[1].y = y + ((-sizeX) * sine + (-sizeY) * cosine) + offsetY;
|
||||
vertices[2].x = x + ((+sizeX) * cosine - (+sizeY) * sine) + offsetX;
|
||||
vertices[2].y = y + ((+sizeX) * sine + (+sizeY) * cosine) + offsetY;
|
||||
vertices[3].x = x + ((+sizeX) * cosine - (-sizeY) * sine) + offsetX;
|
||||
vertices[3].y = y + ((+sizeX) * sine + (-sizeY) * cosine) + offsetY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,6 +598,11 @@ void C4DynamicParticleProperties::Set(C4PropList *dataSource)
|
|||
// needs to be constant
|
||||
blitMode = (uint32_t) property.getInt();
|
||||
}
|
||||
else if(&Strings.P[P_Attach] == key)
|
||||
{
|
||||
// needs to be constant
|
||||
attachment = (uint32_t) property.getInt();
|
||||
}
|
||||
else if(&Strings.P[P_Phase] == key)
|
||||
{
|
||||
phase.Set(property);
|
||||
|
@ -770,6 +775,17 @@ void C4DynamicParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
C4TexRef *textureRef = (*sourceDefinition->Gfx.GetFace().ppTex);
|
||||
assert(textureRef != 0 && "Particle definition had no texture assigned.");
|
||||
|
||||
|
||||
|
||||
// use a relative offset?
|
||||
bool resetMatrix(false);
|
||||
if ((attachment & C4ATTACH_MoveRelative) && (obj != 0))
|
||||
{
|
||||
resetMatrix = true;
|
||||
glPushMatrix();
|
||||
glTranslatef((float)obj->GetX(), (float)obj->GetY(), 0.0f);
|
||||
}
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, (blitMode & C4GFXBLIT_ADDITIVE) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -780,11 +796,14 @@ void C4DynamicParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
glTexCoordPointer(2, GL_FLOAT, stride, &(vertexCoordinates[0].u));
|
||||
glColorPointer(4, GL_FLOAT, stride, &(vertexCoordinates[0].r));
|
||||
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) (5 * particleCount), GL_UNSIGNED_INT, ::DynamicParticles.GetPrimitiveRestartArray());
|
||||
|
||||
if (resetMatrix)
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool C4DynamicParticleChunk::IsOfType(C4ParticleDef *def, uint32_t _blitMode) const
|
||||
bool C4DynamicParticleChunk::IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t _attachment) const
|
||||
{
|
||||
return def == sourceDefinition && blitMode == _blitMode;
|
||||
return def == sourceDefinition && blitMode == _blitMode && attachment == _attachment;
|
||||
}
|
||||
|
||||
C4DynamicParticle *C4DynamicParticleChunk::AddNewParticle()
|
||||
|
@ -888,19 +907,19 @@ void C4DynamicParticleList::Clear()
|
|||
accessMutex.Leave();
|
||||
}
|
||||
|
||||
C4DynamicParticle *C4DynamicParticleList::AddNewParticle(C4ParticleDef *def, uint32_t blitMode)
|
||||
C4DynamicParticle *C4DynamicParticleList::AddNewParticle(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment)
|
||||
{
|
||||
accessMutex.Enter();
|
||||
|
||||
// if not cached, find correct chunk in list
|
||||
C4DynamicParticleChunk *chunk = 0;
|
||||
if (lastAccessedChunk && lastAccessedChunk->IsOfType(def, blitMode))
|
||||
if (lastAccessedChunk && lastAccessedChunk->IsOfType(def, blitMode, attachment))
|
||||
chunk = lastAccessedChunk;
|
||||
else
|
||||
{
|
||||
for (std::list<C4DynamicParticleChunk>::iterator iter = particleChunks.begin(); iter != particleChunks.end(); ++iter)
|
||||
{
|
||||
if (!iter->IsOfType(def, blitMode)) continue;
|
||||
if (!iter->IsOfType(def, blitMode, attachment)) continue;
|
||||
chunk = &(*iter);
|
||||
break;
|
||||
}
|
||||
|
@ -913,6 +932,7 @@ C4DynamicParticle *C4DynamicParticleList::AddNewParticle(C4ParticleDef *def, uin
|
|||
chunk = &particleChunks.back();
|
||||
chunk->sourceDefinition = def;
|
||||
chunk->blitMode = blitMode;
|
||||
chunk->attachment = attachment;
|
||||
}
|
||||
|
||||
assert(chunk && "No suitable particle chunk could be found or created.");
|
||||
|
@ -997,20 +1017,12 @@ void C4DynamicParticleSystem::ReleaseParticleList(C4DynamicParticleList *first,
|
|||
}
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
void C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider &speedX, C4DynamicParticleValueProvider &speedY, C4DynamicParticleValueProvider &lifetime, C4PropList *properties, int amount, C4DynamicParticleList *pxList, C4Object *object)
|
||||
void C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider &speedX, C4DynamicParticleValueProvider &speedY, C4DynamicParticleValueProvider &lifetime, C4PropList *properties, int amount, C4Object *object)
|
||||
{
|
||||
// todo: check amount etc
|
||||
|
||||
if (!pxList)
|
||||
{
|
||||
pxList = globalParticles;
|
||||
}
|
||||
C4DynamicParticleList * pxList(globalParticles);
|
||||
|
||||
if (pxList == globalParticles && globalParticles == 0)
|
||||
{
|
||||
globalParticles = GetNewParticleList();
|
||||
pxList = globalParticles;
|
||||
}
|
||||
|
||||
// initialize the particle properties
|
||||
// this is done here, because it would also be the right place to implement caching
|
||||
|
@ -1020,6 +1032,36 @@ void C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4
|
|||
speedX.Floatify(10.f);
|
||||
speedY.Floatify(10.f);
|
||||
|
||||
// position offset that will be added to the particle
|
||||
float xoff(0.f), yoff(0.f);
|
||||
|
||||
// offset only for the drawing position - this is needed so that particles relative to an object work correctly
|
||||
float drawingOffsetX(0.f), drawingOffsetY(0.f);
|
||||
|
||||
if (object != 0)
|
||||
{
|
||||
// for all types of particles add object's offset (mainly for collision etc.)
|
||||
xoff = object->GetX();
|
||||
yoff = object->GetY();
|
||||
|
||||
// figure out particle list to use
|
||||
if (particleProperties.attachment & C4ATTACH_Front) pxList = object->DynamicFrontParticles;
|
||||
else if (particleProperties.attachment & C4ATTACH_Back) pxList = object->DynamicBackParticles;
|
||||
|
||||
if (particleProperties.attachment & C4ATTACH_MoveRelative)
|
||||
{
|
||||
drawingOffsetX = -xoff;
|
||||
drawingOffsetY = -yoff;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity for global particles - might have to be created first
|
||||
if (pxList == globalParticles && globalParticles == 0)
|
||||
{
|
||||
globalParticles = GetNewParticleList();
|
||||
pxList = globalParticles;
|
||||
}
|
||||
|
||||
while (amount--)
|
||||
{
|
||||
if (speedX.IsRandom()) speedX.RollRandom();
|
||||
|
@ -1027,7 +1069,7 @@ void C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4
|
|||
if (lifetime.IsRandom()) lifetime.RollRandom();
|
||||
|
||||
// create a particle in the fitting chunk
|
||||
C4DynamicParticle *particle = pxList->AddNewParticle(of_def, particleProperties.blitMode);
|
||||
C4DynamicParticle *particle = pxList->AddNewParticle(of_def, particleProperties.blitMode, particleProperties.attachment);
|
||||
|
||||
// initialize some more properties
|
||||
particle->properties = particleProperties;
|
||||
|
@ -1039,7 +1081,8 @@ void C4DynamicParticleSystem::Create(C4ParticleDef *of_def, float x, float y, C4
|
|||
particle->currentSpeedX = speedX.GetValue(particle);
|
||||
particle->currentSpeedY = speedY.GetValue(particle);
|
||||
particle->drawingData.aspect = of_def->Aspect;
|
||||
particle->SetPosition(x, y);
|
||||
particle->drawingData.SetOffset(drawingOffsetX, drawingOffsetY);
|
||||
particle->SetPosition(x + xoff, y + yoff);
|
||||
particle->drawingData.SetColor(particle->properties.colorR.GetValue(particle), particle->properties.colorG.GetValue(particle), particle->properties.colorB.GetValue(particle), particle->properties.colorAlpha.GetValue(particle));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,14 @@ enum C4ParticleValueProviderID
|
|||
C4PV_Speed,
|
||||
};
|
||||
|
||||
enum C4ParticleAttachmentPropertyID
|
||||
{
|
||||
C4ATTACH_None = 0,
|
||||
C4ATTACH_Front = 1,
|
||||
C4ATTACH_Back = 2,
|
||||
C4ATTACH_MoveRelative = 4
|
||||
};
|
||||
|
||||
enum C4ParticleCollisionFuncID
|
||||
{
|
||||
C4PC_Die,
|
||||
|
@ -148,6 +156,8 @@ public:
|
|||
|
||||
uint32_t blitMode;
|
||||
|
||||
uint32_t attachment;
|
||||
|
||||
C4DynamicParticleProperties();
|
||||
|
||||
|
||||
|
@ -190,6 +200,14 @@ public:
|
|||
float sizeX, sizeY;
|
||||
float aspect;
|
||||
|
||||
float offsetX, offsetY;
|
||||
|
||||
void SetOffset(float x, float y)
|
||||
{
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
}
|
||||
|
||||
void SetPointer(Vertex *startingVertex, bool initial = false)
|
||||
{
|
||||
vertices = startingVertex;
|
||||
|
@ -221,7 +239,7 @@ public:
|
|||
void SetPosition(float x, float y, float size, float rotation = 0.f, float stretch = 1.f);
|
||||
void SetPhase(int phase, C4ParticleDef *sourceDef);
|
||||
|
||||
DrawingData() : currentStretch(1.f), originalSize(0.0001f), aspect(1.f)
|
||||
DrawingData() : currentStretch(1.f), originalSize(0.0001f), aspect(1.f), offsetX(0.f), offsetY(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -260,7 +278,11 @@ class C4DynamicParticleChunk
|
|||
{
|
||||
private:
|
||||
C4ParticleDef *sourceDefinition;
|
||||
|
||||
uint32_t blitMode;
|
||||
|
||||
// whether the particles are translated according to the object's position
|
||||
uint32_t attachment;
|
||||
|
||||
std::vector<C4DynamicParticle*> particles;
|
||||
std::vector<C4DynamicParticle::DrawingData::Vertex> vertexCoordinates;
|
||||
|
@ -269,7 +291,7 @@ private:
|
|||
// delete the particle at indexTo. If possible, replace it with the particle at indexFrom to keep the particles tighly packed
|
||||
void DeleteAndReplaceParticle(size_t indexToReplace, size_t indexFrom);
|
||||
public:
|
||||
C4DynamicParticleChunk() : sourceDefinition(0), blitMode(0), particleCount(0)
|
||||
C4DynamicParticleChunk() : sourceDefinition(0), blitMode(0), attachment(C4ATTACH_None), particleCount(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -281,7 +303,7 @@ public:
|
|||
void Clear();
|
||||
bool Exec(C4Object *obj, float timeDelta);
|
||||
void Draw(C4TargetFacet cgo, C4Object *obj);
|
||||
bool IsOfType(C4ParticleDef *def, uint32_t _blitMode) const;
|
||||
bool IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t attachment) const;
|
||||
|
||||
C4DynamicParticle *AddNewParticle();
|
||||
|
||||
|
@ -301,17 +323,19 @@ private:
|
|||
|
||||
// for making sure that the list is not drawn and calculated at the same time
|
||||
CStdCSec accessMutex;
|
||||
|
||||
public:
|
||||
C4DynamicParticleList(C4Object *obj = 0) : targetObject(obj), lastAccessedChunk(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// deletes all the particles
|
||||
void Clear();
|
||||
|
||||
void Exec(float timeDelta = 1.f);
|
||||
void Draw(C4TargetFacet cgo, C4Object *obj);
|
||||
C4DynamicParticle *AddNewParticle(C4ParticleDef *def, uint32_t blitMode);
|
||||
C4DynamicParticle *AddNewParticle(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -376,7 +400,7 @@ public:
|
|||
void PreparePrimitiveRestartIndices(uint32_t forSize);
|
||||
void *GetPrimitiveRestartArray() { return (void*)&primitiveRestartIndices[0]; }
|
||||
|
||||
void Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider &speedX, C4DynamicParticleValueProvider &speedY, C4DynamicParticleValueProvider &lifetime, C4PropList *properties, int amount = 1, C4DynamicParticleList *pxList=NULL, C4Object *object=NULL);
|
||||
void Create(C4ParticleDef *of_def, float x, float y, C4DynamicParticleValueProvider &speedX, C4DynamicParticleValueProvider &speedY, C4DynamicParticleValueProvider &lifetime, C4PropList *properties, int amount = 1, C4Object *object=NULL);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue