dynamic particles: made the attachment an entry in the particle properties

stable-5.4
David Dormagen 2013-10-18 12:33:31 +02:00
parent 32968f2735
commit 0707458264
4 changed files with 117 additions and 47 deletions

View File

@ -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>

View File

@ -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}
};

View File

@ -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));
}
}

View File

@ -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
};