diff --git a/Engine/source/T3D/assets/MaterialAsset.h b/Engine/source/T3D/assets/MaterialAsset.h index 3eab28afb..7e45a539f 100644 --- a/Engine/source/T3D/assets/MaterialAsset.h +++ b/Engine/source/T3D/assets/MaterialAsset.h @@ -19,6 +19,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- +#pragma once + #ifndef MATERIALASSET_H #define MATERIALASSET_H @@ -42,6 +44,10 @@ #include "gfx/gfxDevice.h" #endif +#ifndef _NETCONNECTION_H_ +#include "sim/netConnection.h" +#endif + #include "gui/editor/guiInspectorTypes.h" #include "materials/matTextureTarget.h" @@ -118,5 +124,93 @@ public: static void consoleInit(); }; +#define assetText(x,suff) std::string(std::string(#x) + std::string(#suff)).c_str() + +#define initMaterialAsset(name) m##name##Name = StringTable->EmptyString(); m##name##AssetId = StringTable->EmptyString(); m##name##Asset = NULL; +#define bindMaterialAsset(name) if (m##name##AssetId != StringTable->EmptyString()) m##name##Asset = m##name##AssetId; + +#define scriptBindMaterialAsset(name, consoleClass, docs) addProtectedField(assetText(name, File), TypeMaterialName, Offset(m##name##Name, consoleClass), consoleClass::_set##name##Name, & defaultProtectedGetFn, assetText(name, docs)); \ + addProtectedField(assetText(name, Asset), TypeMaterialAssetId, Offset(m##name##AssetId, consoleClass), consoleClass::_set##name##Asset, & defaultProtectedGetFn, assetText(name, asset reference.)); + +/// +/// DECLARE_MATERIALASSET is a utility macro for MaterialAssets. It takes in the name of the class using it, the name of the field for the material, and a networking bitmask +/// The first 2 are for setting up/filling out the fields and class member defines +/// The bitmask is for when the material is changed, it can automatically kick a network update on the owner object to pass the changed asset to clients +/// +#define DECLARE_MATERIALASSET(className,name,bitmask) protected: \ + StringTableEntry m##name##Name;\ + StringTableEntry m##name##AssetId;\ + AssetPtr m##name##Asset;\ + public: \ + const StringTableEntry& get##name() const { return m##name##Name; }\ + void set##name(FileName _in) { m##name##Name = _in; }\ + const AssetPtr & get##name##Asset() const { return m##name##Asset; }\ + void set##name##Asset(AssetPtr_in) { m##name##Asset = _in; }\ +static bool _set##name##Name(void* obj, const char* index, const char* data)\ +{\ + className* shape = static_cast(obj);\ + \ + StringTableEntry assetId = MaterialAsset::getAssetIdByMaterialName(StringTable->insert(data));\ + if (assetId != StringTable->EmptyString())\ + {\ + if (shape->_set##name##Asset(obj, index, assetId))\ + {\ + if (assetId == StringTable->insert("Core_Rendering:noMaterial"))\ + {\ + shape->m##name##Name = data;\ + shape->m##name##AssetId = StringTable->EmptyString();\ + \ + return true;\ + }\ + else\ + {\ + shape->m##name##AssetId = assetId;\ + shape->m##name##Name = StringTable->EmptyString();\ + \ + return false;\ + }\ + }\ + }\ + else\ + {\ + shape->m##name##Asset = StringTable->EmptyString();\ + }\ + \ + return true;\ +}\ +\ +static bool _set##name##Asset(void* obj, const char* index, const char* data)\ +{\ + className* shape = static_cast(obj);\ + shape->m##name##AssetId = StringTable->insert(data);\ + if (MaterialAsset::getAssetById(shape->m##name##AssetId, &shape->m##name##Asset))\ + {\ + if (shape->m##name##Asset.getAssetId() != StringTable->insert("Core_Rendering:noMaterial"))\ + shape->m##name##Name = StringTable->EmptyString();\ + \ + shape->setMaskBits(bitmask);\ + return true;\ + }\ + return false;\ +} + +#define packMaterialAsset(netconn, name)\ + if (stream->writeFlag(m##name##Asset.notNull()))\ + {\ + NetStringHandle assetIdStr = m##name##Asset.getAssetId();\ + ##netconn##->packNetStringHandleU(stream, assetIdStr);\ + }\ + else\ + stream->writeString(m##name##Name); + +#define unpackMaterialAsset(netconn, name)\ + if (stream->readFlag())\ + {\ + m##name##AssetId = StringTable->insert(##netconn##->unpackNetStringHandleU(stream).getString());\ + MaterialAsset::getAssetById(m##name##AssetId, &m##name##Asset);\ + }\ + else\ + m##name##Name = stream->readSTString();\ + #endif // _ASSET_BASE_H_ diff --git a/Engine/source/T3D/examples/renderMeshExample.cpp b/Engine/source/T3D/examples/renderMeshExample.cpp index 42f48b049..49094598d 100644 --- a/Engine/source/T3D/examples/renderMeshExample.cpp +++ b/Engine/source/T3D/examples/renderMeshExample.cpp @@ -33,7 +33,6 @@ #include "lighting/lightQuery.h" #include "console/engineAPI.h" - IMPLEMENT_CO_NETOBJECT_V1(RenderMeshExample); ConsoleDocClass( RenderMeshExample, @@ -63,6 +62,8 @@ RenderMeshExample::RenderMeshExample() // Make sure we the Material instance to NULL // so we don't try to access it incorrectly mMaterialInst = NULL; + + initMaterialAsset(Material); } RenderMeshExample::~RenderMeshExample() @@ -77,8 +78,7 @@ RenderMeshExample::~RenderMeshExample() void RenderMeshExample::initPersistFields() { addGroup( "Rendering" ); - addField( "material", TypeMaterialName, Offset( mMaterialName, RenderMeshExample ), - "The name of the material used to render the mesh." ); + scriptBindMaterialAsset(Material, RenderMeshExample, "The material used to render the mesh."); endGroup( "Rendering" ); // SceneObject already handles exposing the transform @@ -145,8 +145,10 @@ U32 RenderMeshExample::packUpdate( NetConnection *conn, U32 mask, BitStream *str } // Write out any of the updated editable properties - if ( stream->writeFlag( mask & UpdateMask ) ) - stream->write( mMaterialName ); + if (stream->writeFlag(mask & UpdateMask)) + { + packMaterialAsset(conn, Material); + } return retMask; } @@ -166,7 +168,7 @@ void RenderMeshExample::unpackUpdate(NetConnection *conn, BitStream *stream) if ( stream->readFlag() ) // UpdateMask { - stream->read( &mMaterialName ); + unpackMaterialAsset(conn, Material); if ( isProperlyAdded() ) updateMaterial(); @@ -248,18 +250,18 @@ void RenderMeshExample::createGeometry() void RenderMeshExample::updateMaterial() { - if ( mMaterialName.isEmpty() ) - return; + if (mMaterialAsset.notNull()) + { + if (mMaterialInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMaterialInst->getMaterial()->getName(), String::NoCase)) + return; - // If the material name matches then don't bother updating it. - if ( mMaterialInst && mMaterialName.equal( mMaterialInst->getMaterial()->getName(), String::NoCase ) ) - return; + SAFE_DELETE(mMaterialInst); - SAFE_DELETE( mMaterialInst ); + mMaterialInst = MATMGR->createMatInstance(mMaterialAsset->getMaterialDefinitionName(), getGFXVertexFormat< VertexType >()); - mMaterialInst = MATMGR->createMatInstance( mMaterialName, getGFXVertexFormat< VertexType >() ); - if ( !mMaterialInst ) - Con::errorf( "RenderMeshExample::updateMaterial - no Material called '%s'", mMaterialName.c_str() ); + if (!mMaterialInst) + Con::errorf("RenderMeshExample::updateMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName()); + } } void RenderMeshExample::prepRenderImage( SceneRenderState *state ) @@ -353,4 +355,4 @@ DefineEngineMethod( RenderMeshExample, postApply, void, (),, "A utility method for forcing a network update.\n") { object->inspectPostApply(); -} \ No newline at end of file +} diff --git a/Engine/source/T3D/examples/renderMeshExample.h b/Engine/source/T3D/examples/renderMeshExample.h index 0b2347c3b..82a38a65b 100644 --- a/Engine/source/T3D/examples/renderMeshExample.h +++ b/Engine/source/T3D/examples/renderMeshExample.h @@ -33,6 +33,8 @@ #include "gfx/gfxPrimitiveBuffer.h" #endif +#include "T3D/assets/MaterialAsset.h" + class BaseMatInstance; @@ -65,8 +67,8 @@ class RenderMeshExample : public SceneObject //-------------------------------------------------------------------------- // Rendering variables //-------------------------------------------------------------------------- - // The name of the Material we will use for rendering - String mMaterialName; + DECLARE_MATERIALASSET(RenderMeshExample, Material, UpdateMask); + // The actual Material instance BaseMatInstance* mMaterialInst; @@ -131,4 +133,4 @@ public: void prepRenderImage( SceneRenderState *state ); }; -#endif // _RENDERMESHEXAMPLE_H_ \ No newline at end of file +#endif // _RENDERMESHEXAMPLE_H_ diff --git a/Engine/source/T3D/groundPlane.cpp b/Engine/source/T3D/groundPlane.cpp index d71448e86..62cee84ee 100644 --- a/Engine/source/T3D/groundPlane.cpp +++ b/Engine/source/T3D/groundPlane.cpp @@ -86,8 +86,7 @@ GroundPlane::GroundPlane() mConvexList = new Convex; mTypeMask |= TerrainLikeObjectType; - mMaterialAsset = StringTable->EmptyString(); - mMaterialAssetId = StringTable->EmptyString(); + initMaterialAsset(Material); } GroundPlane::~GroundPlane() @@ -107,13 +106,7 @@ void GroundPlane::initPersistFields() addField( "scaleU", TypeF32, Offset( mScaleU, GroundPlane ), "Scale of texture repeat in the U direction." ); addField( "scaleV", TypeF32, Offset( mScaleV, GroundPlane ), "Scale of texture repeat in the V direction." ); - addProtectedField("materialAsset", TypeMaterialAssetId, Offset(mMaterialAssetId, GroundPlane), - &GroundPlane::_setMaterialAsset, &defaultProtectedGetFn, - "The material asset."); - - addProtectedField("material", TypeMaterialName, Offset(mMaterialName, GroundPlane), - &GroundPlane::_setMaterialName, &defaultProtectedGetFn, - "The material name."); + scriptBindMaterialAsset(Material, GroundPlane, "The material used to render the ground plane."); endGroup( "Plane" ); @@ -124,72 +117,6 @@ void GroundPlane::initPersistFields() removeField( "rotation" ); } -bool GroundPlane::_setMaterialAsset(void* obj, const char* index, const char* data) -{ - GroundPlane* gp = static_cast(obj);// ->setFile(FileName(data)); - - gp->mMaterialAssetId = StringTable->insert(data); - - return gp->setMaterialAsset(gp->mMaterialAssetId); -} - -bool GroundPlane::_setMaterialName(void* obj, const char* index, const char* data) -{ - GroundPlane* gp = static_cast(obj);// ->setFile(FileName(data)); - - StringTableEntry assetId = MaterialAsset::getAssetIdByMaterialName(StringTable->insert(data)); - if (assetId != StringTable->EmptyString()) - { - //Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break - //the TSStatic - if (gp->setMaterialAsset(assetId)) - { - if (assetId == StringTable->insert("Core_Rendering:NoMaterial")) - { - gp->mMaterialName = data; - gp->mMaterialAssetId = StringTable->EmptyString(); - - return true; - } - else - { - gp->mMaterialAssetId = assetId; - gp->mMaterialName = StringTable->EmptyString(); - - return false; - } - } - } - else - { - gp->mMaterialAsset = StringTable->EmptyString(); - gp->mMaterialName = data; - } - - return true; -} - -bool GroundPlane::setMaterialAsset(const StringTableEntry materialAssetId) -{ - if (MaterialAsset::getAssetById(materialAssetId, &mMaterialAsset)) - { - //Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break - //the TSStatic - if (mMaterialAsset.getAssetId() != StringTable->insert("Core_Rendering:noMaterial")) - { - mMaterialName = StringTable->EmptyString(); - } - - _updateMaterial(); - - setMaskBits(-1); - - return true; - } - - return false; -} - bool GroundPlane::onAdd() { if( !Parent::onAdd() ) @@ -263,8 +190,8 @@ U32 GroundPlane::packUpdate( NetConnection* connection, U32 mask, BitStream* str stream->write( mSquareSize ); stream->write( mScaleU ); stream->write( mScaleV ); - stream->writeString( mMaterialAsset.getAssetId() ); - stream->write( mMaterialName ); + + packMaterialAsset(connection, Material); return retMask; } @@ -277,11 +204,7 @@ void GroundPlane::unpackUpdate( NetConnection* connection, BitStream* stream ) stream->read( &mScaleU ); stream->read( &mScaleV ); - char buffer[256]; - stream->readString(buffer); - setMaterialAsset(StringTable->insert(buffer)); - - stream->read( &mMaterialName ); + unpackMaterialAsset(connection, Material); // If we're added then something possibly changed in // the editor... do an update of the material and the @@ -295,13 +218,17 @@ void GroundPlane::unpackUpdate( NetConnection* connection, BitStream* stream ) void GroundPlane::_updateMaterial() { - if (!mMaterialAsset.isNull()) + if (mMaterialAsset.notNull()) { - String matName = mMaterialAsset->getMaterialDefinitionName(); + if (mMaterial && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMaterial->getMaterial()->getName(), String::NoCase)) + return; + + SAFE_DELETE(mMaterial); + + mMaterial = MATMGR->createMatInstance(mMaterialAsset->getMaterialDefinitionName(), getGFXVertexFormat< VertexType >()); - mMaterial = MATMGR->createMatInstance(matName, getGFXVertexFormat< VertexType >()); if (!mMaterial) - Con::errorf("GroundPlane::_updateMaterial - no material called '%s'", matName.c_str()); + Con::errorf("GroundPlane::_updateMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName()); } } diff --git a/Engine/source/T3D/groundPlane.h b/Engine/source/T3D/groundPlane.h index 829a3a1e2..c1f943dc0 100644 --- a/Engine/source/T3D/groundPlane.h +++ b/Engine/source/T3D/groundPlane.h @@ -64,9 +64,6 @@ public: GroundPlane(); virtual ~GroundPlane(); - static bool _setMaterialAsset(void* obj, const char* index, const char* data); - static bool _setMaterialName(void* obj, const char* index, const char* data); - virtual bool onAdd(); virtual void onRemove(); virtual U32 packUpdate( NetConnection* connection, U32 mask, BitStream* stream ); @@ -81,8 +78,6 @@ public: static void initPersistFields(); - bool setMaterialAsset(const StringTableEntry materialAssetId); - virtual void getUtilizedAssets(Vector* usedAssetsList); protected: @@ -109,11 +104,9 @@ private: F32 mSquareSize; ///< World units per grid cell edge. F32 mScaleU; ///< Scale factor for U texture coordinates. F32 mScaleV; ///< Scale factor for V texture coordinates. - String mMaterialName; ///< Object name of material to use. BaseMatInstance* mMaterial; ///< Instantiated material based on given material name. - AssetPtr mMaterialAsset; - StringTableEntry mMaterialAssetId; + DECLARE_MATERIALASSET(GroundPlane, Material, -1); PhysicsBody *mPhysicsRep;