From a8a141e73c435d93a23fdd0f0d1aa86aa6f8ca90 Mon Sep 17 00:00:00 2001 From: Lukas Joergensen Date: Thu, 31 Jul 2014 00:31:02 +0200 Subject: [PATCH] RibbonNode class. Simple RibbonNode class for an implementation similar to that of ParticleEmitterNodes. Datablock currently has no static fields. --- Engine/source/T3D/fx/ribbonNode.cpp | 324 ++++++++++++++++++++++++++++ Engine/source/T3D/fx/ribbonNode.h | 108 ++++++++++ 2 files changed, 432 insertions(+) create mode 100644 Engine/source/T3D/fx/ribbonNode.cpp create mode 100644 Engine/source/T3D/fx/ribbonNode.h diff --git a/Engine/source/T3D/fx/ribbonNode.cpp b/Engine/source/T3D/fx/ribbonNode.cpp new file mode 100644 index 000000000..0343fc5b3 --- /dev/null +++ b/Engine/source/T3D/fx/ribbonNode.cpp @@ -0,0 +1,324 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "ribbonNode.h" +#include "console/consoleTypes.h" +#include "core/stream/bitStream.h" +#include "T3D/fx/ribbon.h" +#include "math/mathIO.h" +#include "sim/netConnection.h" +#include "console/engineAPI.h" + +IMPLEMENT_CO_DATABLOCK_V1(RibbonNodeData); +IMPLEMENT_CO_NETOBJECT_V1(RibbonNode); + +ConsoleDocClass( RibbonNodeData, + "@brief Contains additional data to be associated with a RibbonNode." + "@ingroup FX\n" + ); + +ConsoleDocClass( RibbonNode, "" + ); + + +//----------------------------------------------------------------------------- +// RibbonNodeData +//----------------------------------------------------------------------------- +RibbonNodeData::RibbonNodeData() +{ +} + +RibbonNodeData::~RibbonNodeData() +{ + +} + +//----------------------------------------------------------------------------- +// initPersistFields +//----------------------------------------------------------------------------- +void RibbonNodeData::initPersistFields() +{ + Parent::initPersistFields(); +} + + +//----------------------------------------------------------------------------- +// RibbonNode +//----------------------------------------------------------------------------- +RibbonNode::RibbonNode() +{ + // Todo: ScopeAlways? + mNetFlags.set(Ghostable); + mTypeMask |= EnvironmentObjectType; + + mActive = true; + + mDataBlock = NULL; + mRibbonDatablock = NULL; + mRibbonDatablockId = 0; + mRibbon = NULL; +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +RibbonNode::~RibbonNode() +{ + // +} + +//----------------------------------------------------------------------------- +// initPersistFields +//----------------------------------------------------------------------------- +void RibbonNode::initPersistFields() +{ + addField( "active", TYPEID< bool >(), Offset(mActive,RibbonNode), + "Controls whether ribbon is emitted from this node." ); + addField( "ribbon", TYPEID< RibbonData >(), Offset(mRibbonDatablock, RibbonNode), + "Datablock to use for the ribbon." ); + + Parent::initPersistFields(); +} + +//----------------------------------------------------------------------------- +// onAdd +//----------------------------------------------------------------------------- +bool RibbonNode::onAdd() +{ + if( !Parent::onAdd() ) + return false; + + if( !mRibbonDatablock && mRibbonDatablockId != 0 ) + { + if( Sim::findObject(mRibbonDatablockId, mRibbonDatablock) == false ) + Con::errorf(ConsoleLogEntry::General, "RibbonNode::onAdd: Invalid packet, bad datablockId(mRibbonDatablock): %d", mRibbonDatablockId); + } + + if( isClientObject() ) + { + setRibbonDatablock( mRibbonDatablock ); + } + else + { + setMaskBits( StateMask | EmitterDBMask ); + } + + mObjBox.minExtents.set(-0.5, -0.5, -0.5); + mObjBox.maxExtents.set( 0.5, 0.5, 0.5); + resetWorldBox(); + addToScene(); + + return true; +} + +//----------------------------------------------------------------------------- +// onRemove +//----------------------------------------------------------------------------- +void RibbonNode::onRemove() +{ + removeFromScene(); + if( isClientObject() ) + { + if( mRibbon ) + { + mRibbon->deleteOnEnd(); + mRibbon = NULL; + } + } + + Parent::onRemove(); +} + +//----------------------------------------------------------------------------- +// onNewDataBlock +//----------------------------------------------------------------------------- +bool RibbonNode::onNewDataBlock( GameBaseData *dptr, bool reload ) +{ + mDataBlock = dynamic_cast( dptr ); + if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) + return false; + + // Todo: Uncomment if this is a "leaf" class + scriptOnNewDataBlock(); + return true; +} + +//----------------------------------------------------------------------------- +void RibbonNode::inspectPostApply() +{ + Parent::inspectPostApply(); + setMaskBits(StateMask | EmitterDBMask); +} + +//----------------------------------------------------------------------------- +// processTick +//----------------------------------------------------------------------------- +void RibbonNode::processTick(const Move* move) +{ + Parent::processTick(move); + + if ( isMounted() ) + { + MatrixF mat; + mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat ); + setTransform( mat ); + } +} + +//----------------------------------------------------------------------------- +// advanceTime +//----------------------------------------------------------------------------- +void RibbonNode::advanceTime(F32 dt) +{ + Parent::advanceTime(dt); + + if(!mActive || mRibbon.isNull() || !mDataBlock) + return; + + MatrixF trans(getTransform()); + Point3F pos = getPosition(); + mRibbon->addSegmentPoint(pos, trans); +} + +//----------------------------------------------------------------------------- +// packUpdate +//----------------------------------------------------------------------------- +U32 RibbonNode::packUpdate(NetConnection* con, U32 mask, BitStream* stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if ( stream->writeFlag( mask & InitialUpdateMask ) ) + { + mathWrite(*stream, getTransform()); + mathWrite(*stream, getScale()); + } + + if ( stream->writeFlag( mask & EmitterDBMask ) ) + { + if( stream->writeFlag(mRibbonDatablock != NULL) ) + { + stream->writeRangedU32(mRibbonDatablock->getId(), DataBlockObjectIdFirst, + DataBlockObjectIdLast); + } + } + + if ( stream->writeFlag( mask & StateMask ) ) + { + stream->writeFlag( mActive ); + } + + return retMask; +} + +//----------------------------------------------------------------------------- +// unpackUpdate +//----------------------------------------------------------------------------- +void RibbonNode::unpackUpdate(NetConnection* con, BitStream* stream) +{ + Parent::unpackUpdate(con, stream); + + if ( stream->readFlag() ) + { + MatrixF temp; + Point3F tempScale; + mathRead(*stream, &temp); + mathRead(*stream, &tempScale); + + setScale(tempScale); + setTransform(temp); + } + + if ( stream->readFlag() ) + { + mRibbonDatablockId = stream->readFlag() ? + stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast) : 0; + + RibbonData *emitterDB = NULL; + Sim::findObject( mRibbonDatablockId, emitterDB ); + if ( isProperlyAdded() ) + setRibbonDatablock( emitterDB ); + } + + if ( stream->readFlag() ) + { + mActive = stream->readFlag(); + } +} + +//----------------------------------------------------------------------------- +// setRibbonDatablock +//----------------------------------------------------------------------------- +void RibbonNode::setRibbonDatablock(RibbonData* data) +{ + if ( isServerObject() ) + { + setMaskBits( EmitterDBMask ); + } + else + { + Ribbon* pRibbon = NULL; + if ( data ) + { + // Create emitter with new datablock + pRibbon = new Ribbon; + pRibbon->onNewDataBlock( data, false ); + if( pRibbon->registerObject() == false ) + { + Con::warnf(ConsoleLogEntry::General, "Could not register base ribbon of class: %s", data->getName() ? data->getName() : data->getIdString() ); + delete pRibbon; + return; + } + } + + // Replace emitter + if ( mRibbon ) + mRibbon->deleteOnEnd(); + + mRibbon = pRibbon; + } + + mRibbonDatablock = data; +} + +DefineEngineMethod(RibbonNode, setRibbonDatablock, void, (RibbonData* ribbonDatablock), (0), + "Assigns the datablock for this ribbon node.\n" + "@param ribbonDatablock RibbonData datablock to assign\n" + "@tsexample\n" + "// Assign a new emitter datablock\n" + "%emitter.setRibbonDatablock( %ribbonDatablock );\n" + "@endtsexample\n" ) +{ + if ( !ribbonDatablock ) + { + Con::errorf("RibbonData datablock could not be found when calling setRibbonDataBlock in ribbonNode."); + return; + } + + object->setRibbonDatablock(ribbonDatablock); +} + +DefineEngineMethod(RibbonNode, setActive, void, (bool active),, + "Turns the ribbon on or off.\n" + "@param active New ribbon state\n" ) +{ + object->setActive( active ); +} diff --git a/Engine/source/T3D/fx/ribbonNode.h b/Engine/source/T3D/fx/ribbonNode.h new file mode 100644 index 000000000..62b1158e4 --- /dev/null +++ b/Engine/source/T3D/fx/ribbonNode.h @@ -0,0 +1,108 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _RIBBON_NODE_H_ +#define _RIBBON_NODE_H_ + +#ifndef _GAMEBASE_H_ +#include "T3D/gameBase/gameBase.h" +#endif + +class RibbonData; +class Ribbon; + +//***************************************************************************** +// ParticleEmitterNodeData +//***************************************************************************** +class RibbonNodeData : public GameBaseData +{ + typedef GameBaseData Parent; + + //-------------------------------------- Console set variables +public: + F32 timeMultiple; + + //-------------------------------------- load set variables + +public: + RibbonNodeData(); + ~RibbonNodeData(); + + DECLARE_CONOBJECT(RibbonNodeData); + static void initPersistFields(); +}; + + +//***************************************************************************** +// ParticleEmitterNode +//***************************************************************************** +class RibbonNode : public GameBase +{ + typedef GameBase Parent; + + enum MaskBits + { + StateMask = Parent::NextFreeMask << 0, + EmitterDBMask = Parent::NextFreeMask << 1, + NextFreeMask = Parent::NextFreeMask << 2, + }; + + RibbonNodeData* mDataBlock; + +protected: + bool onAdd(); + void onRemove(); + bool onNewDataBlock( GameBaseData *dptr, bool reload ); + void inspectPostApply(); + + RibbonData* mRibbonDatablock; + S32 mRibbonDatablockId; + + SimObjectPtr mRibbon; + + bool mActive; + +public: + RibbonNode(); + ~RibbonNode(); + + Ribbon *getRibbonEmitter() {return mRibbon;} + + // Time/Move Management + + void processTick(const Move* move); + void advanceTime(F32 dt); + + DECLARE_CONOBJECT(RibbonNode); + static void initPersistFields(); + + U32 packUpdate (NetConnection *conn, U32 mask, BitStream* stream); + void unpackUpdate(NetConnection *conn, BitStream* stream); + + inline bool getActive( void ) { return mActive; }; + inline void setActive( bool active ) { mActive = active; setMaskBits( StateMask ); }; + + void setRibbonDatablock(RibbonData* data); +}; + +#endif // _RIBBON_NODE_H_ +