//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "console/consoleTypes.h" #include "core/bitStream.h" #include "game/fx/particleEmitter.h" #include "game/fx/particleEngine.h" #include "math/mathIO.h" IMPLEMENT_CO_DATABLOCK_V1(ParticleEmitterNodeData); IMPLEMENT_CO_NETOBJECT_V1(ParticleEmitterNode); //-------------------------------------------------------------------------- //-------------------------------------- // ParticleEmitterNodeData::ParticleEmitterNodeData() { timeMultiple = 1.0; } ParticleEmitterNodeData::~ParticleEmitterNodeData() { } //-------------------------------------------------------------------------- void ParticleEmitterNodeData::initPersistFields() { Parent::initPersistFields(); addField("timeMultiple", TypeF32, Offset(timeMultiple, ParticleEmitterNodeData)); } //-------------------------------------------------------------------------- bool ParticleEmitterNodeData::onAdd() { if(!Parent::onAdd()) return false; if (timeMultiple < 0.01 || timeMultiple > 100) { Con::warnf("ParticleEmitterNodeData::onAdd(%s): timeMultiple must be between 0.01 and 100", getName()); timeMultiple = timeMultiple < 0.01 ? 0.01 : 100; } return true; } bool ParticleEmitterNodeData::preload(bool server, char errorBuffer[256]) { if (Parent::preload(server, errorBuffer) == false) return false; return true; } //-------------------------------------------------------------------------- void ParticleEmitterNodeData::packData(BitStream* stream) { Parent::packData(stream); stream->write(timeMultiple); } void ParticleEmitterNodeData::unpackData(BitStream* stream) { Parent::unpackData(stream); stream->read(&timeMultiple); } //-------------------------------------------------------------------------- //-------------------------------------- // ParticleEmitterNode::ParticleEmitterNode() { // Todo: ScopeAlways? mNetFlags.set(Ghostable); mTypeMask |= EnvironmentObjectType; mEmitterDatablock = NULL; mEmitterDatablockId = 0; mEmitter = NULL; mVelocity = 1.0; } ParticleEmitterNode::~ParticleEmitterNode() { // } //-------------------------------------------------------------------------- void ParticleEmitterNode::initPersistFields() { Parent::initPersistFields(); addField("emitter", TypeParticleEmitterDataPtr, Offset(mEmitterDatablock, ParticleEmitterNode)); addField("velocity", TypeF32, Offset(mVelocity, ParticleEmitterNode)); } //-------------------------------------------------------------------------- bool ParticleEmitterNode::onAdd() { if(!Parent::onAdd()) return false; if (!mEmitterDatablock && mEmitterDatablockId != 0) { if (Sim::findObject(mEmitterDatablockId, mEmitterDatablock) == false) Con::errorf(ConsoleLogEntry::General, "ParticleEmitterNode::onAdd: Invalid packet, bad datablockId(mEmitterDatablock): %d", mEmitterDatablockId); } if (mEmitterDatablock == NULL) return false; if (isClientObject()) { ParticleEmitter* pEmitter = new ParticleEmitter; pEmitter->onNewDataBlock(mEmitterDatablock); if (pEmitter->registerObject() == false) { Con::warnf(ConsoleLogEntry::General, "Could not register base emitter for particle of class: %s", mDataBlock->getName()); delete pEmitter; return false; } mEmitter = pEmitter; } mObjBox.min.set(-0.5, -0.5, -0.5); mObjBox.max.set( 0.5, 0.5, 0.5); resetWorldBox(); addToScene(); return true; } void ParticleEmitterNode::onRemove() { removeFromScene(); if (isClientObject()) { mEmitter->deleteWhenEmpty(); mEmitter = NULL; } Parent::onRemove(); } void ParticleEmitterNode::onGroupAdd() { Parent::onGroupAdd(); // To make sure that we don't orphan our emitter on mission end, // let's add it to our parent group, so it will get cleaned up. SimGroup* myGroup = getGroup(); if (myGroup && mEmitter) myGroup->addObject(mEmitter); } bool ParticleEmitterNode::onNewDataBlock(GameBaseData* dptr) { mDataBlock = dynamic_cast(dptr); if (!mDataBlock || !Parent::onNewDataBlock(dptr)) return false; // Todo: Uncomment if this is a "leaf" class scriptOnNewDataBlock(); return true; } //-------------------------------------------------------------------------- void ParticleEmitterNode::advanceTime(F32 dt) { Parent::advanceTime(dt); Point3F emitPoint, emitVelocity; Point3F emitAxis(0, 0, 1); getTransform().mulV(emitAxis); getTransform().getColumn(3, &emitPoint); emitVelocity = emitAxis * mVelocity; mEmitter->emitParticles(emitPoint, emitPoint, emitAxis, emitVelocity, (U32)(dt * mDataBlock->timeMultiple * 1000.0f)); } //-------------------------------------------------------------------------- U32 ParticleEmitterNode::packUpdate(NetConnection* con, U32 mask, BitStream* stream) { U32 retMask = Parent::packUpdate(con, mask, stream); mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); if (stream->writeFlag(mEmitterDatablock != NULL)) { stream->writeRangedU32(mEmitterDatablock->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); } return retMask; } void ParticleEmitterNode::unpackUpdate(NetConnection* con, BitStream* stream) { Parent::unpackUpdate(con, stream); MatrixF temp; Point3F tempScale; mathRead(*stream, &temp); mathRead(*stream, &tempScale); if (stream->readFlag()) { mEmitterDatablockId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); } else { mEmitterDatablockId = 0; } setScale(tempScale); setTransform(temp); } void ParticleEmitterNode::setEmitterDataBlock(ParticleEmitterData* data) { if (!data) return; if (mEmitter) { mEmitterDatablock = data; ParticleEmitter* pEmitter = new ParticleEmitter; pEmitter->onNewDataBlock(mEmitterDatablock); if (pEmitter->registerObject() == false) { Con::warnf(ConsoleLogEntry::General, "Could not register base emitter for particle of class: %s", mDataBlock->getName()); delete pEmitter; pEmitter = NULL; } if (pEmitter) { mEmitter->deleteWhenEmpty(); mEmitter = pEmitter; } } } ConsoleMethod(ParticleEmitterNode, setEmitterDataBlock, void, 3, 3, "(data)") { ParticleEmitterData* data = dynamic_cast(Sim::findObject(dAtoi(argv[2]))); if (!data) data = dynamic_cast(Sim::findObject(argv[2])); if (data) object->setEmitterDataBlock(data); }