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;