Browse Source

Merge pull request #425 from Areloch/MaterialMacroMagic

Initial pass at implementing MaterialAsset macromagic utility functions
Brian Roberts 4 years ago
parent
commit
1fbf46fa90

+ 94 - 0
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.));
+
+/// <summary>
+/// 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
+/// </summary>
+#define DECLARE_MATERIALASSET(className,name,bitmask)      protected: \
+                                      StringTableEntry m##name##Name;\
+                                      StringTableEntry m##name##AssetId;\
+                                      AssetPtr<MaterialAsset>  m##name##Asset;\
+                                      public: \
+                                      const StringTableEntry& get##name() const { return m##name##Name; }\
+                                      void set##name(FileName _in) { m##name##Name = _in; }\
+                                      const AssetPtr<MaterialAsset> & get##name##Asset() const { return m##name##Asset; }\
+                                      void set##name##Asset(AssetPtr<MaterialAsset>_in) { m##name##Asset = _in; }\
+static bool _set##name##Name(void* obj, const char* index, const char* data)\
+{\
+   className* shape = static_cast<className*>(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<className*>(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_
 

+ 18 - 16
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();
-}
+}

+ 5 - 3
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_
+#endif // _RENDERMESHEXAMPLE_H_

+ 13 - 86
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<GroundPlane*>(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<GroundPlane*>(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());
    }
 }
 

+ 1 - 8
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<StringTableEntry>* 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<MaterialAsset> mMaterialAsset;
-   StringTableEntry mMaterialAssetId;
+   DECLARE_MATERIALASSET(GroundPlane, Material, -1);
 
    PhysicsBody *mPhysicsRep;
 

+ 1 - 1
Templates/BaseGame/game/data/ExampleModule/levels/ExampleLevel.mis

@@ -36,7 +36,7 @@ new Scene(EditorTemplateLevel) {
       squareSize = "128";
       scaleU = "25";
       scaleV = "25";
-      Material = "FloorGray";
+      MaterialFile = "FloorGray";
       canSave = "1";
       canSaveDynamicFields = "1";
          Enabled = "1";