Files
wagic/JGE/src/JParticleEffect.cpp

391 lines
8.7 KiB
C++

//-------------------------------------------------------------------------------------
//
// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows.
//
// Licensed under the BSD license, see LICENSE in JGE root for details.
//
// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) <jhkhui@gmail.com>
//
//-------------------------------------------------------------------------------------
#include <math.h>
#include "../include/JGE.h"
#include "../include/JParticleSystem.h"
#include "../include/JParticleEffect.h"
#include "../include/JParticleEmitter.h"
#include "../include/JFileSystem.h"
#include "../include/JResourceManager.h"
#include "tinyxml/tinyxml.h"
//-------------------------------------------------------------------------------------
JParticleEffect::JParticleEffect(JResourceManager* mgr)
{
mResourceManager = mgr;
mX = 0.0f;
mY = 0.0f;
mEmitterCount = 0;
}
JParticleEffect::~JParticleEffect()
{
for (int i=0;i<mEmitterCount;i++)
if (mParticleEmitters[i])
delete (mParticleEmitters[i]);
}
bool JParticleEffect::Load(const char* filename)
{
mX = 0.0f;
mY = 0.0f;
mEmitterCount = 0;
JFileSystem *fileSystem = JFileSystem::GetInstance();
if (fileSystem == NULL) return false;
JFile* jFile = fileSystem->OpenFile(filename);
if (!jFile) return false;
int size = fileSystem->GetFileSize(jFile);
char *xmlBuffer = new char[size];
fileSystem->ReadFile(jFile, xmlBuffer, size);
TiXmlDocument doc;
doc.Parse(xmlBuffer);
TiXmlNode* effect = 0;
TiXmlNode* emitter = 0;
TiXmlNode* param = 0;
TiXmlNode* key = 0;
TiXmlElement* element = 0;
float keyTime;
float value;
float baseValue;
int int_value;
//
// enum ParticleField
// {
// FIELD_SPEED,
// FIELD_SIZE,
// FIELD_ROTATION,
// FIELD_ALPHA,
// FIELD_RED,
// FIELD_GREEN,
// FIELD_BLUE,
// FIELD_COUNT
// };
const string lifeValues[] =
{
"speed",
"size",
"rotation",
"alpha",
"red",
"green",
"blue",
"radial_accel",
"tangential_accel",
"gravity"
};
const string typeNames[] =
{
"POINT",
"AREA",
"HORIZONTAL",
"VERTICAL",
"CIRCLE"
};
const string modeNames[] =
{
"REPEAT",
"ONCE",
"NTIMES",
"CONTINUOUS"
};
//////////////////////////////////////////////////////////////////////////
// One effect per file only, well, we may extend it later to permit
// multiple effect definitions:
//
// for (effect = doc.FirstChild("effect"); effect; effect = effect->NextSibling())
//
//////////////////////////////////////////////////////////////////////////
effect = doc.FirstChild("effect");
if (effect)
{
element = effect->ToElement();
printf("%s:%s\n", element->Value(), element->Attribute("name"));
for (emitter = effect->FirstChild("emitter"); emitter && mEmitterCount < MAX_EMITTER; emitter = emitter->NextSibling())
{
mParticleEmitters[mEmitterCount] = new JParticleEmitter(this);
element = emitter->ToElement();
if (element->QueryFloatAttribute("life", &value) == TIXML_SUCCESS)
mParticleEmitters[mEmitterCount]->mLife = value;
for (param = emitter->FirstChild(); param; param = param->NextSibling())
{
element = param->ToElement();
if (string("settings") == element->Attribute("name"))
{
if (string("NORMAL") == element->Attribute("blend"))
mParticleEmitters[mEmitterCount]->SetBlending(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
else if (string("ADDITIVE") == element->Attribute("blend"))
mParticleEmitters[mEmitterCount]->SetBlending(BLEND_SRC_ALPHA, BLEND_ONE);
for (unsigned int i=0;i<sizeof(modeNames)/sizeof(char*);i++)
{
if (modeNames[i] == element->Attribute("mode"))
{
mParticleEmitters[mEmitterCount]->mEmitterMode = i;
#if defined (_DEBUG)
printf("emitter mode:%s\n", modeNames[i].c_str());
#endif
break;
}
}
for (unsigned i=0;i<sizeof(typeNames)/sizeof(char*);i++)
{
if (typeNames[i] == element->Attribute("type"))
{
mParticleEmitters[mEmitterCount]->mType = i;
#if defined (_DEBUG)
printf("emitter type:%s\n", typeNames[i].c_str());
#endif
break;
}
}
string quadName = element->Attribute("image");
JQuad* quad = mResourceManager->GetQuad(quadName);
if (quad != NULL)
mParticleEmitters[mEmitterCount]->SetQuad(quad);
// if (element->QueryIntAttribute("image", &int_value) == TIXML_SUCCESS)
// {
// mParticleEmitters[mEmitterCount]->mQuadIndex = int_value;
//
// }
if (element->QueryIntAttribute("width", &int_value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mWidth = int_value;
}
if (element->QueryIntAttribute("height", &int_value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mHeight = int_value;
}
if (element->QueryIntAttribute("id", &int_value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mId = int_value;
}
if (element->QueryIntAttribute("repeat_count", &int_value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mRepeatTimes = int_value;
}
}
else if (string("quantity") == element->Attribute("name"))
{
for (key = param->FirstChild(); key; key = key->NextSibling())
{
element = key->ToElement();
if (element->QueryFloatAttribute("timeslice", &keyTime) == TIXML_SUCCESS &&
element->QueryFloatAttribute("value", &value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mQuantity.AddKey(keyTime, value);
}
}
}
else if (string("lifex") == element->Attribute("name"))
{
if (element->QueryFloatAttribute("base", &baseValue) == TIXML_SUCCESS &&
element->QueryFloatAttribute("max", &value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mLifeBase = baseValue;
mParticleEmitters[mEmitterCount]->mLifeMax= value;
}
}
else if (string("anglex") == element->Attribute("name"))
{
if (element->QueryFloatAttribute("base", &baseValue) == TIXML_SUCCESS &&
element->QueryFloatAttribute("max", &value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mAngleBase = baseValue*DEG2RAD;
mParticleEmitters[mEmitterCount]->mAngleMax= value*DEG2RAD;
}
}
else if (string("speedx") == element->Attribute("name"))
{
if (element->QueryFloatAttribute("base", &baseValue) == TIXML_SUCCESS &&
element->QueryFloatAttribute("max", &value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mSpeedBase = baseValue;
mParticleEmitters[mEmitterCount]->mSpeedMax= value;
}
}
else if (string("sizex") == element->Attribute("name"))
{
if (element->QueryFloatAttribute("base", &baseValue) == TIXML_SUCCESS &&
element->QueryFloatAttribute("max", &value) == TIXML_SUCCESS)
{
mParticleEmitters[mEmitterCount]->mSizeBase = baseValue;
mParticleEmitters[mEmitterCount]->mSizeMax= value;
}
}
else
{
for (int i=0;i<FIELD_COUNT;i++)
{
if (lifeValues[i] == element->Attribute("name"))
{
for (key = param->FirstChild(); key; key = key->NextSibling())
{
element = key->ToElement();
if (element->QueryFloatAttribute("lifeslice", &keyTime) == TIXML_SUCCESS &&
element->QueryFloatAttribute("value", &value) == TIXML_SUCCESS)
{
if (i==FIELD_ROTATION)
value *= DEG2RAD;
mParticleEmitters[mEmitterCount]->mData[i].AddKey(keyTime, value);
}
}
break;
}
}
}
}
mEmitterCount++;
}
}
fileSystem->CloseFile(jFile);
delete[] xmlBuffer;
return true;
}
void JParticleEffect::SetParticleSystem(JParticleSystem* particleSys)
{
mParticleSystem = particleSys;
}
void JParticleEffect::SetPosition(float x, float y)
{
mX = x;
mY = y;
}
JParticleSystem* JParticleEffect::GetParticleSystem()
{
return mParticleSystem;
}
float JParticleEffect::GetX()
{
return mX;
}
float JParticleEffect::GetY()
{
return mY;
}
void JParticleEffect::Update(float dt)
{
// mTimer += dt;
for (int i=0;i<mEmitterCount;i++)
mParticleEmitters[i]->Update(dt);
}
void JParticleEffect::Render()
{
for (int i=0;i<mEmitterCount;i++)
mParticleEmitters[i]->Render();
}
bool JParticleEffect::Done()
{
bool done = true;
for (int i=0;i<mEmitterCount;i++)
if (!mParticleEmitters[i]->Done())
done = false;
return (done);
}
void JParticleEffect::Start()
{
for (int i=0;i<mEmitterCount;i++)
mParticleEmitters[i]->Start();
}
void JParticleEffect::Stop()
{
for (int i=0;i<mEmitterCount;i++)
mParticleEmitters[i]->SetActive(false);
}
void JParticleEffect::MoveTo(float x, float y)
{
float dx = x - mX;
float dy = y - mY;
mX = x;
mY = y;
for (int i=0;i<mEmitterCount;i++)
{
mParticleEmitters[i]->MoveAllParticles(dx, dy);
}
}