浏览代码

Merge pull request #436 from Areloch/AssetificationPass01

Assetifies MeshRoad, Decal Road, and the material slot of GroundCover
Brian Roberts 4 年之前
父节点
当前提交
2ba8ccd333

+ 81 - 2
Engine/source/T3D/assets/MaterialAsset.cpp

@@ -19,6 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
+#pragma once
 
 #ifndef MATERIALASSET_H
 #include "MaterialAsset.h"
@@ -40,6 +41,8 @@
 #include "assets/assetPtr.h"
 #endif
 
+#include "T3D\assets\assetImporter.h"
+
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT(MaterialAsset);
@@ -231,6 +234,82 @@ StringTableEntry MaterialAsset::getAssetIdByMaterialName(StringTableEntry matNam
             materialAssetId = matAsset->getAssetId();
             break;
          }
+         AssetDatabase.releaseAsset(query->mAssetList[i]); //cleanup if that's not the one we needed
+      }
+
+      if (materialAssetId == StringTable->EmptyString())
+      {
+         //Try auto-importing it if it exists already
+         BaseMaterialDefinition* baseMatDef;
+         if (!Sim::findObject(matName, baseMatDef))
+         {
+            //Not even a real material, apparently?
+            //return back a blank
+            return StringTable->EmptyString();
+         }
+
+         //Ok, a real mat def, we can work with this
+#if TORQUE_DEBUG
+         Con::warnf("MaterialAsset::getAssetIdByMaterialName - Attempted to in-place import a material(%s) that had no associated asset", matName);
+#endif
+
+         AssetImporter* autoAssetImporter;
+         if (!Sim::findObject("autoAssetImporter", autoAssetImporter))
+         {
+            autoAssetImporter = new AssetImporter();
+            autoAssetImporter->registerObject("autoAssetImporter");
+         }
+
+         autoAssetImporter->resetImportSession(true);
+
+         String originalMaterialDefFile = Torque::Path(baseMatDef->getFilename()).getPath();
+
+         autoAssetImporter->setTargetPath(originalMaterialDefFile);
+
+         autoAssetImporter->resetImportConfig();
+
+         AssetImportObject* assetObj = autoAssetImporter->addImportingAsset("MaterialAsset", originalMaterialDefFile, nullptr, matName);
+
+         //Find out if the filepath has an associated module to it. If we're importing in-place, it needs to be within a module's directory
+         ModuleDefinition* targetModuleDef = AssetImporter::getModuleFromPath(originalMaterialDefFile);
+
+         if (targetModuleDef == nullptr)
+         {
+            return StringTable->EmptyString();
+         }
+         else
+         {
+            autoAssetImporter->setTargetModuleId(targetModuleDef->getModuleId());
+         }
+
+         autoAssetImporter->processImportAssets();
+
+         bool hasIssues = autoAssetImporter->validateAssets();
+
+         if (hasIssues)
+         {
+            //log it
+            Con::errorf("Error! Import process of Material(%s) has failed due to issues discovered during validation!", matName);
+            return StringTable->EmptyString();
+         }
+         else
+         {
+            autoAssetImporter->importAssets();
+         }
+
+#if TORQUE_DEBUG
+         autoAssetImporter->dumpActivityLog();
+#endif
+
+         if (hasIssues)
+         {
+            return StringTable->EmptyString();
+         }
+         else
+         {
+            String assetId = autoAssetImporter->getTargetModuleId() + ":" + assetObj->assetName;
+            return StringTable->insert(assetId.c_str());
+         }
       }
    }
 
@@ -282,8 +361,8 @@ GuiControl* GuiInspectorTypeMaterialAssetPtr::constructEditControl()
 
    // Change filespec
    char szBuffer[512];
-   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"MaterialAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
-      mInspector->getInspectObject()->getIdString(), mCaption);
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"MaterialAsset\", \"AssetBrowser.changeAsset\", %s, \"\");",
+      getIdString());
    mBrowseButton->setField("Command", szBuffer);
 
    setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());

+ 88 - 6
Engine/source/T3D/assets/MaterialAsset.h

@@ -126,23 +126,87 @@ public:
 
 #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 initMaterialAsset(name) m##name##Name = ""; 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.));
+#define scriptBindMaterialAsset(name, consoleClass, docs)\
+   addProtectedField(assetText(name, File), TypeMaterialName, Offset(m##name##Name, consoleClass), consoleClass::_set##name##Name,  & defaultProtectedGetFn, assetText(name, docs), AbstractClassRep::FIELD_HideInInspectors); \
+   addProtectedField(assetText(name, Asset), TypeMaterialAssetId, Offset(m##name##AssetId, consoleClass), consoleClass::_set##name##Asset, & defaultProtectedGetFn, assetText(name, asset reference.));
+
+#define DECLARE_MATERIALASSET(className,name)      protected: \
+                                      String m##name##Name;\
+                                      StringTableEntry m##name##AssetId;\
+                                      AssetPtr<MaterialAsset>  m##name##Asset;\
+                                      public: \
+                                      const String& 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();\
+      \
+      return true;\
+   }\
+   return false;\
+}\
+\
+static bool set##name##Asset(const char* assetId)\
+{\
+   m##name##AssetId = StringTable->insert(assetId);\
+   if (m##name##AssetId != StringTable->EmptyString())\
+      m##name##Asset = m##name##AssetId;\
+}
 
 /// <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;\
+#define DECLARE_NET_MATERIALASSET(className,name,bitmask)      protected: \
+                                      String m##name##Name;\
                                       StringTableEntry m##name##AssetId;\
                                       AssetPtr<MaterialAsset>  m##name##Asset;\
                                       public: \
-                                      const StringTableEntry& get##name() const { return m##name##Name; }\
+                                      const String& 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; }\
@@ -189,11 +253,29 @@ static bool _set##name##Asset(void* obj, const char* index, const char* data)\
          shape->m##name##Name = StringTable->EmptyString();\
       \
       shape->setMaskBits(bitmask);\
+      shape->inspectPostApply();\
+      return true;\
+   }\
+   shape->inspectPostApply();\
+   return false;\
+}\
+\
+bool set##name##AssetId(const char* _assetId)\
+{\
+   m##name##AssetId = StringTable->insert(_assetId);\
+   if (m##name##AssetId != StringTable->EmptyString())\
+   {\
+      m##name##Asset = m##name##AssetId;\
+      \
+      setMaskBits(bitmask);\
+      inspectPostApply();\
       return true;\
    }\
+   \
    return false;\
 }
 
+
 #define packMaterialAsset(netconn, name)\
    if (stream->writeFlag(m##name##Asset.notNull()))\
    {\

+ 30 - 23
Engine/source/T3D/assets/assetImporter.cpp

@@ -2282,6 +2282,32 @@ void AssetImporter::resolveAssetItemIssues(AssetImportObject* assetItem)
    }
 }
 
+void AssetImporter::resetImportConfig()
+{
+   //use a default import config
+   if (activeImportConfig == nullptr)
+   {
+      activeImportConfig = new AssetImportConfig();
+      activeImportConfig->registerObject();
+   }
+
+   bool foundConfig = false;
+   Settings* editorSettings;
+   //See if we can get our editor settings
+   if (Sim::findObject("EditorSettings", editorSettings))
+   {
+      String defaultImportConfig = editorSettings->value("Assets/AssetImporDefaultConfig");
+
+      //If we found it, grab the import configs
+      Settings* importConfigs;
+      if (Sim::findObject("AssetImportSettings", importConfigs))
+      {
+         //Now load the editor setting-deigned config!
+         activeImportConfig->loadImportConfig(importConfigs, defaultImportConfig.c_str());
+      }
+   }
+}
+
 //
 // Importing
 //
@@ -2322,28 +2348,7 @@ StringTableEntry AssetImporter::autoImportFile(Torque::Path filePath)
    //set our path
    targetPath = filePath.getPath();
 
-   //use a default import config
-   if (activeImportConfig == nullptr)
-   {
-      activeImportConfig = new AssetImportConfig();
-      activeImportConfig->registerObject();
-   }
-
-   bool foundConfig = false;
-   Settings* editorSettings;
-   //See if we can get our editor settings
-   if (Sim::findObject("EditorSettings", editorSettings))
-   {
-      String defaultImportConfig = editorSettings->value("Assets/AssetImporDefaultConfig");
-
-      //If we found it, grab the import configs
-      Settings* importConfigs;
-      if (Sim::findObject("AssetImportSettings", importConfigs))
-      {
-         //Now load the editor setting-deigned config!
-         activeImportConfig->loadImportConfig(importConfigs, defaultImportConfig.c_str());
-      }
-   }
+   resetImportConfig();
 
    AssetImportObject* assetItem = addImportingAsset(assetType, filePath, nullptr, "");
 
@@ -2767,7 +2772,9 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
          assetFieldName = mapFieldName + "Asset[0]";
          mapFieldName += "[0]";
 
-         existingMat->writeField(mapFieldName.c_str(), path.c_str());
+         //If there's already an existing image map file on the material definition in this slot, don't override it
+         if(!path.isEmpty())
+            existingMat->writeField(mapFieldName.c_str(), path.c_str());
 
          String targetAsset = targetModuleId + ":" + childItem->assetName;
 

+ 10 - 0
Engine/source/T3D/assets/assetImporter.h

@@ -847,6 +847,12 @@ public:
          activeImportConfig = importConfig;
    }
 
+   /// <summary>
+   /// Resets the active import config to whatever the default is. Either a clean slate if one isn't defined
+   /// or loading one if defined via the editor config
+   /// </summary>
+   void resetImportConfig();
+
    //
    static String getTrueFilename(const String& fileName);
 
@@ -881,4 +887,8 @@ public:
 
       return qualifiedFilePath;
    }
+
+   //
+   void setTargetModuleId(const String& moduleId) { targetModuleId = moduleId; }
+   const String& getTargetModuleId() { return targetModuleId; }
 };

+ 1 - 1
Engine/source/T3D/examples/renderMeshExample.h

@@ -67,7 +67,7 @@ class RenderMeshExample : public SceneObject
    //--------------------------------------------------------------------------
    // Rendering variables
    //--------------------------------------------------------------------------
-   DECLARE_MATERIALASSET(RenderMeshExample, Material, UpdateMask);
+   DECLARE_NET_MATERIALASSET(RenderMeshExample, Material, UpdateMask);
 
    // The actual Material instance
    BaseMatInstance*  mMaterialInst;

+ 29 - 14
Engine/source/T3D/fx/groundCover.cpp

@@ -458,7 +458,8 @@ GroundCover::GroundCover()
 
    mRandomSeed = 1;
 
-   mMaterial = NULL;
+   initMaterialAsset(Material);
+
    mMatInst = NULL;
    mMatParams = NULL;
    mTypeRectsParam = NULL;
@@ -537,8 +538,8 @@ IMPLEMENT_CO_NETOBJECT_V1(GroundCover);
 void GroundCover::initPersistFields()
 {
    addGroup( "GroundCover General" );
-      
-      addField( "material",      TypeMaterialName, Offset( mMaterialName, GroundCover ),        "Material used by all GroundCover segments." );
+
+      scriptBindMaterialAsset(Material, GroundCover, "Material used by all GroundCover segments.");
 
       addField( "radius",        TypeF32,          Offset( mRadius, GroundCover ),              "Outer generation radius from the current camera position." );
       addField( "dissolveRadius",TypeF32,          Offset( mFadeRadius, GroundCover ),          "This is less than or equal to radius and defines when fading of cover elements begins." );
@@ -709,7 +710,7 @@ U32 GroundCover::packUpdate( NetConnection *connection, U32 mask, BitStream *str
       // TODO: We could probably optimize a few of these
       // based on reasonable units at some point.
 
-      stream->write( mMaterialName );
+      packMaterialAsset(connection, Material);
 
       stream->write( mRadius );
       stream->write( mZOffset );
@@ -780,7 +781,7 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream )
 
    if (stream->readFlag())
    {
-      stream->read( &mMaterialName );
+      unpackMaterialAsset(connection, Material);
 
       stream->read( &mRadius );
       stream->read( &mZOffset );
@@ -852,17 +853,29 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream )
 }
 
 void GroundCover::_initMaterial()
-{   
-   SAFE_DELETE( mMatInst );
-   
-   if ( mMaterialName.isNotEmpty() )
-      if ( !Sim::findObject( mMaterialName, mMaterial ) )
-         Con::errorf( "GroundCover::_initMaterial - Material %s was not found.", mMaterialName.c_str() );
+{
+   if (mMaterialAsset.notNull())
+   {
+      if (mMatInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMatInst->getMaterial()->getName(), String::NoCase))
+         return;
+
+      SAFE_DELETE(mMatInst);
 
-   if ( mMaterial )
-      mMatInst = mMaterial->createMatInstance();
+      if (!Sim::findObject(mMaterialAsset->getMaterialDefinitionName(), mMaterial))
+         Con::errorf("GroundCover::_initMaterial - Material %s was not found.", mMaterialAsset->getMaterialDefinitionName());
+
+      if (mMaterial)
+         mMatInst = mMaterial->createMatInstance();
+      else
+         mMatInst = MATMGR->createMatInstance("WarningMaterial");
+
+      if (!mMatInst)
+         Con::errorf("GroundCover::_initMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName());
+   }
    else
-      mMatInst = MATMGR->createMatInstance( "WarningMaterial" );
+   {
+      return;
+   }
    
    // Add our special feature that makes it all work...
    FeatureSet features = MATMGR->getDefaultFeatures();
@@ -1567,6 +1580,8 @@ void GroundCover::_updateCoverGrid( const Frustum &culler )
 void GroundCover::prepRenderImage( SceneRenderState *state )
 {
    // Reset stats each time we hit the diffuse pass.
+   if (mMatInst == nullptr)
+      return;
 
    if( state->isDiffusePass() )
    {

+ 4 - 2
Engine/source/T3D/fx/groundCover.h

@@ -45,6 +45,8 @@
 #include "shaderGen/shaderFeature.h"
 #endif
 
+#include "T3D/assets/MaterialAsset.h"
+
 class TerrainBlock;
 class GroundCoverCell;
 class TSShapeInstance;
@@ -264,8 +266,8 @@ protected:
    static F32 smDensityScale;   
    static F32 smFadeScale;
 
-   String mMaterialName;
-   Material *mMaterial;
+   DECLARE_NET_MATERIALASSET(GroundCover, Material, InitialUpdateMask);
+   Material* mMaterial;
    BaseMatInstance *mMatInst;
 
    GroundCoverShaderConstData mShaderConstData;

+ 1 - 1
Engine/source/T3D/groundPlane.h

@@ -106,7 +106,7 @@ private:
    F32               mScaleV;       ///< Scale factor for V texture coordinates.
    BaseMatInstance*  mMaterial;     ///< Instantiated material based on given material name.
 
-   DECLARE_MATERIALASSET(GroundPlane, Material, -1);
+   DECLARE_NET_MATERIALASSET(GroundPlane, Material, -1);
 
    PhysicsBody *mPhysicsRep;
 

+ 34 - 26
Engine/source/environment/decalRoad.cpp

@@ -287,7 +287,9 @@ DecalRoad::DecalRoad()
 {   
    // Setup NetObject.
    mTypeMask |= StaticObjectType | StaticShapeObjectType;
-   mNetFlags.set(Ghostable);      
+   mNetFlags.set(Ghostable);
+
+   initMaterialAsset(Material);
 }
 
 DecalRoad::~DecalRoad()
@@ -303,7 +305,8 @@ void DecalRoad::initPersistFields()
 {
    addGroup( "DecalRoad" );
 
-      addField( "material", TypeMaterialName, Offset( mMaterialName, DecalRoad ), "Material used for rendering." ); 
+      addProtectedField("materialAsset", TypeMaterialAssetId, Offset(mMaterialAssetId, DecalRoad), &DecalRoad::_setMaterialAsset, &defaultProtectedGetFn, "Material Asset used for rendering.");
+      addProtectedField( "material", TypeMaterialName, Offset( mMaterialName, DecalRoad ), &DecalRoad::_setMaterialName, &defaultProtectedGetFn, "Material used for rendering." );
 
       addProtectedField( "textureLength", TypeF32, Offset( mTextureLength, DecalRoad ), &DecalRoad::ptSetTextureLength, &defaultProtectedGetFn, 
          "The length in meters of textures mapped to the DecalRoad" );      
@@ -489,7 +492,7 @@ U32 DecalRoad::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
    if ( stream->writeFlag( mask & DecalRoadMask ) )
    {
       // Write Texture Name.
-      stream->write( mMaterialName );
+      packMaterialAsset(con, Material);
 
       stream->write( mBreakAngle );      
 
@@ -578,24 +581,10 @@ void DecalRoad::unpackUpdate( NetConnection *con, BitStream *stream )
    // DecalRoadMask
    if ( stream->readFlag() )
    {
-      String matName;
-      stream->read( &matName );
-      
-      if ( matName != mMaterialName )
-      {
-         mMaterialName = matName;
-         Material *pMat = NULL;
-         if ( !Sim::findObject( mMaterialName, pMat ) )
-         {
-            Con::printf( "DecalRoad::unpackUpdate, failed to find Material of name %s!", mMaterialName.c_str() );
-         }
-         else
-         {
-            mMaterial = pMat;
-            if ( isProperlyAdded() )
-               _initMaterial(); 
-         }
-      }
+      unpackMaterialAsset(con, Material);
+
+      if (isProperlyAdded())
+         _initMaterial();
 
       stream->read( &mBreakAngle );    
 
@@ -1056,12 +1045,31 @@ bool DecalRoad::addNodeFromField( void *object, const char *index, const char *d
 
 void DecalRoad::_initMaterial()
 {
-   SAFE_DELETE( mMatInst );
+   if (mMaterialAsset.notNull())
+   {
+      if (mMatInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMatInst->getMaterial()->getName(), String::NoCase))
+         return;
 
-   if ( mMaterial )
-      mMatInst = mMaterial->createMatInstance();
-   else
-      mMatInst = MATMGR->createMatInstance( "WarningMaterial" );
+      SAFE_DELETE(mMatInst);
+
+      Material* tMat = nullptr;
+
+      if (!Sim::findObject(mMaterialAsset->getMaterialDefinitionName(), tMat))
+         Con::errorf("DecalRoad::_initMaterial - Material %s was not found.", mMaterialAsset->getMaterialDefinitionName());
+
+      mMaterial = tMat;
+
+      if (mMaterial)
+         mMatInst = mMaterial->createMatInstance();
+      else
+         mMatInst = MATMGR->createMatInstance("WarningMaterial");
+
+      if (!mMatInst)
+         Con::errorf("DecalRoad::_initMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName());
+   }
+
+   if (!mMatInst)
+      return;
 
    GFXStateBlockDesc desc;
    desc.setZReadWrite( true, false );

+ 4 - 1
Engine/source/environment/decalRoad.h

@@ -36,6 +36,8 @@
 #include "collision/clippedPolyList.h"
 #endif
 
+#include "T3D/assets/MaterialAsset.h"
+
 class Path;
 class TerrainBlock;
 struct ObjectRenderInst;
@@ -237,7 +239,8 @@ protected:
    F32 mBreakAngle;
    U32 mSegmentsPerBatch;
    F32 mTextureLength;
-   String mMaterialName;
+
+   DECLARE_NET_MATERIALASSET(DecalRoad, Material, DecalRoadMask);
    U32 mRenderPriority;
 
    // Static ConsoleVars for editor

+ 20 - 14
Engine/source/environment/editors/guiMeshRoadEditorCtrl.cpp

@@ -96,10 +96,10 @@ GuiMeshRoadEditorCtrl::GuiMeshRoadEditorCtrl()
     mSelectedSplineColor( 0,255,0,255 ),
     mHoverNodeColor( 255,255,255,255 ),
 	 mHasCopied( false )
-{   
-	mMaterialName[Top] = StringTable->insert("DefaultRoadMaterialTop");
-	mMaterialName[Bottom] = StringTable->insert("DefaultRoadMaterialOther");
-	mMaterialName[Side] = StringTable->insert("DefaultRoadMaterialOther");
+{
+   mTopMaterialAssetId = Con::getVariable("$MeshRoadEditor::defaultTopMaterialAsset");
+   mBottomMaterialAssetId = Con::getVariable("$MeshRoadEditor::defaultBottomMaterialAsset");
+   mSideMaterialAssetId = Con::getVariable("$MeshRoadEditor::defaultSideMaterialAsset");
 }
 
 GuiMeshRoadEditorCtrl::~GuiMeshRoadEditorCtrl()
@@ -205,6 +205,10 @@ bool GuiMeshRoadEditorCtrl::onAdd()
    desc.zEnable = true;
    mZEnableSB = GFX->createStateBlock(desc);
 
+   bindMaterialAsset(TopMaterial);
+   bindMaterialAsset(BottomMaterial);
+   bindMaterialAsset(SideMaterial);
+
    return true;
 }
 
@@ -217,12 +221,11 @@ void GuiMeshRoadEditorCtrl::initPersistFields()
    addField( "SelectedSplineColor", TypeColorI, Offset( mSelectedSplineColor, GuiMeshRoadEditorCtrl ) );
    addField( "HoverNodeColor",      TypeColorI, Offset( mHoverNodeColor, GuiMeshRoadEditorCtrl ) );
    addField( "isDirty",             TypeBool,   Offset( mIsDirty, GuiMeshRoadEditorCtrl ) );
-	addField( "topMaterialName", TypeString, Offset( mMaterialName[Top], GuiMeshRoadEditorCtrl ),
-      "Default Material used by the Mesh Road Editor on upper surface road creation." );
-   addField( "bottomMaterialName", TypeString, Offset( mMaterialName[Bottom], GuiMeshRoadEditorCtrl ),
-		"Default Material used by the Mesh Road Editor on bottom surface road creation." );
-   addField( "sideMaterialName", TypeString, Offset( mMaterialName[Side], GuiMeshRoadEditorCtrl ),
-      "Default Material used by the Mesh Road Editor on side surface road creation." );
+
+   addField("topMaterial", TypeMaterialAssetId, Offset(mTopMaterialAssetId, GuiMeshRoadEditorCtrl), "Default Material used by the Mesh Road Editor on upper surface road creation.");
+   addField("bottomMaterial", TypeMaterialAssetId, Offset(mBottomMaterialAssetId, GuiMeshRoadEditorCtrl), "Default Material used by the Mesh Road Editor on bottom surface road creation.");
+   addField("sideMaterial", TypeMaterialAssetId, Offset(mSideMaterialAssetId, GuiMeshRoadEditorCtrl), "Default Material used by the Mesh Road Editor on side surface road creation.");
+
    //addField( "MoveNodeCursor", TYPEID< SimObject >(), Offset( mMoveNodeCursor, GuiMeshRoadEditorCtrl) );
    //addField( "AddNodeCursor", TYPEID< SimObject >(), Offset( mAddNodeCursor, GuiMeshRoadEditorCtrl) );
    //addField( "InsertNodeCursor", TYPEID< SimObject >(), Offset( mInsertNodeCursor, GuiMeshRoadEditorCtrl) );
@@ -622,10 +625,13 @@ void GuiMeshRoadEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
 		}
 
 		MeshRoad *newRoad = new MeshRoad;  
-		
-		newRoad->mMaterialName[Top] = mMaterialName[Top];
-		newRoad->mMaterialName[Bottom] = mMaterialName[Bottom];
-		newRoad->mMaterialName[Side] = mMaterialName[Side];
+
+      if(mTopMaterialAsset.notNull())
+		   newRoad->setTopMaterialAssetId(mTopMaterialAssetId);
+      if (mBottomMaterialAsset.notNull())
+		   newRoad->setBottomMaterialAssetId(mBottomMaterialAssetId);
+      if (mSideMaterialAsset.notNull())
+		   newRoad->setSideMaterialAssetId(mSideMaterialAssetId);
 			
       newRoad->registerObject();
 

+ 10 - 2
Engine/source/environment/editors/guiMeshRoadEditorCtrl.h

@@ -36,6 +36,8 @@
 #include "environment/meshRoad.h"
 #endif
 
+#include "T3D/assets/MaterialAsset.h"
+
 class GameBase;
 
 class GuiMeshRoadEditorCtrl : public EditTSCtrl
@@ -156,8 +158,14 @@ class GuiMeshRoadEditorCtrl : public EditTSCtrl
 
       bool mHasCopied;
 	public:
-		
-		StringTableEntry mMaterialName[SurfaceCount];
+
+      StringTableEntry mTopMaterialAssetId;
+      StringTableEntry mBottomMaterialAssetId;
+      StringTableEntry mSideMaterialAssetId;
+
+      AssetPtr<MaterialAsset> mTopMaterialAsset;
+      AssetPtr<MaterialAsset> mBottomMaterialAsset;
+      AssetPtr<MaterialAsset> mSideMaterialAsset;
 };
 
 class GuiMeshRoadEditorUndoAction : public UndoAction

+ 12 - 9
Engine/source/environment/editors/guiRoadEditorCtrl.cpp

@@ -85,7 +85,7 @@ GuiRoadEditorCtrl::GuiRoadEditorCtrl()
    mSavedDrag = false;
    mIsDirty = false;
 
-	mMaterialName = StringTable->insert("DefaultDecalRoadMaterial");
+   mMaterialAssetId = Con::getVariable("$DecalRoadEditor::defaultMaterialAsset");
 }
 
 GuiRoadEditorCtrl::~GuiRoadEditorCtrl()
@@ -100,7 +100,7 @@ void GuiRoadEditorUndoAction::undo()
       return;
 
    // Temporarily save the roads current data.
-   String materialName = road->mMaterialName;
+   String materialAssetId = road->mMaterialAssetId;
    F32 textureLength = road->mTextureLength;
    F32 breakAngle = road->mBreakAngle;
    F32 segmentsPerBatch = road->mSegmentsPerBatch;
@@ -108,7 +108,7 @@ void GuiRoadEditorUndoAction::undo()
    nodes.merge( road->mNodes );
 
    // Restore the Road properties saved in the UndoAction
-   road->mMaterialName = materialName;
+   road->setMaterialAssetId(materialAssetId);
    road->mBreakAngle = breakAngle;
    road->mSegmentsPerBatch = segmentsPerBatch;
    road->mTextureLength = textureLength;
@@ -130,7 +130,7 @@ void GuiRoadEditorUndoAction::undo()
 
    // Now save the previous Road data in this UndoAction
    // since an undo action must become a redo action and vice-versa
-   mMaterialName = materialName;
+   mMaterialAssetId = materialAssetId;
    mBreakAngle = breakAngle;
    mSegmentsPerBatch = segmentsPerBatch;
    mTextureLength = textureLength;
@@ -153,6 +153,8 @@ bool GuiRoadEditorCtrl::onAdd()
 
    mZDisableSB = GFX->createStateBlock(desc);
 
+   bindMaterialAsset(Material);
+
    return true;
 }
 
@@ -163,8 +165,9 @@ void GuiRoadEditorCtrl::initPersistFields()
    addField( "SelectedSplineColor", TypeColorI, Offset( mSelectedSplineColor, GuiRoadEditorCtrl ) );
    addField( "HoverNodeColor",      TypeColorI, Offset( mHoverNodeColor, GuiRoadEditorCtrl ) );
    addField( "isDirty",             TypeBool,   Offset( mIsDirty, GuiRoadEditorCtrl ) );
-	addField( "materialName",			TypeString, Offset( mMaterialName, GuiRoadEditorCtrl ),
-      "Default Material used by the Road Editor on road creation." );
+
+   addField("material", TypeMaterialAssetId, Offset(mMaterialAssetId, GuiRoadEditorCtrl), "Default Material used by the Road Editor on road creation.");
+
    //addField( "MoveNodeCursor", TYPEID< SimObject >(), Offset( mMoveNodeCursor, GuiRoadEditorCtrl) );
    //addField( "AddNodeCursor", TYPEID< SimObject >(), Offset( mAddNodeCursor, GuiRoadEditorCtrl) );
    //addField( "InsertNodeCursor", TYPEID< SimObject >(), Offset( mInsertNodeCursor, GuiRoadEditorCtrl) );
@@ -405,8 +408,8 @@ void GuiRoadEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
 
 		DecalRoad *newRoad = new DecalRoad;
 		
-
-		newRoad->mMaterialName = mMaterialName;
+      if (mMaterialAsset.notNull())
+         newRoad->setMaterialAssetId(mMaterialAssetId);
 
       newRoad->registerObject();
 
@@ -1027,7 +1030,7 @@ void GuiRoadEditorCtrl::submitUndo( const UTF8 *name )
 
    action->mObjId = mSelRoad->getId();
    action->mBreakAngle = mSelRoad->mBreakAngle;
-   action->mMaterialName = mSelRoad->mMaterialName;
+   action->mMaterialAssetId = mSelRoad->mMaterialAssetId;
    action->mSegmentsPerBatch = mSelRoad->mSegmentsPerBatch;   
    action->mTextureLength = mSelRoad->mTextureLength;
    action->mRoadEditor = this;

+ 3 - 2
Engine/source/environment/editors/guiRoadEditorCtrl.h

@@ -103,7 +103,8 @@ class GuiRoadEditorCtrl : public EditTSCtrl
 	
 	public:
 
-		StringTableEntry mMaterialName;
+		StringTableEntry mMaterialAssetId;
+      AssetPtr<MaterialAsset> mMaterialAsset;
    protected:
 
       void _drawRoadSpline( DecalRoad *road, const ColorI &color );
@@ -158,7 +159,7 @@ class GuiRoadEditorUndoAction : public UndoAction
       Vector<RoadNode> mNodes;
 
       SimObjectId mObjId;
-      String mMaterialName;
+      StringTableEntry mMaterialAssetId;
       F32 mBreakAngle;
       U32 mSegmentsPerBatch;
       F32 mTextureLength;

+ 76 - 30
Engine/source/environment/meshRoad.cpp

@@ -920,6 +920,10 @@ MeshRoad::MeshRoad()
       mTriangleCount[i] = 0;
    }
 
+   initMaterialAsset(TopMaterial);
+   initMaterialAsset(BottomMaterial);
+   initMaterialAsset(SideMaterial);
+
    mSideProfile.mRoad = this;
 }
 
@@ -933,14 +937,14 @@ void MeshRoad::initPersistFields()
 {
    addGroup( "MeshRoad" );
 
-      addField( "topMaterial", TypeMaterialName, Offset( mMaterialName[Top], MeshRoad ),
-         "Material for the upper surface of the road." );
+      addProtectedField("TopMaterial", TypeMaterialName, Offset(mTopMaterialName, MeshRoad), MeshRoad::_setTopMaterialName, & defaultProtectedGetFn, "Material for the upper surface of the road.", AbstractClassRep::FIELD_HideInInspectors); \
+      addProtectedField("TopMaterialAsset", TypeMaterialAssetId, Offset(mTopMaterialAssetId, MeshRoad), MeshRoad::_setTopMaterialAsset, & defaultProtectedGetFn, "Material for the upper surface of the road.");
 
-      addField( "bottomMaterial", TypeMaterialName, Offset( mMaterialName[Bottom], MeshRoad ),
-         "Material for the bottom surface of the road." );
+      addProtectedField("BottomMaterial", TypeMaterialName, Offset(mBottomMaterialName, MeshRoad), MeshRoad::_setBottomMaterialName, & defaultProtectedGetFn, "Material for the bottom surface of the road.", AbstractClassRep::FIELD_HideInInspectors); \
+      addProtectedField("BottomMaterialAsset", TypeMaterialAssetId, Offset(mBottomMaterialAssetId, MeshRoad), MeshRoad::_setBottomMaterialAsset, & defaultProtectedGetFn, "Material for the bottom surface of the road.");
 
-      addField( "sideMaterial", TypeMaterialName, Offset( mMaterialName[Side], MeshRoad ),
-         "Material for the left, right, front, and back surfaces of the road." );
+      addProtectedField("SideMaterial", TypeMaterialName, Offset(mSideMaterialName, MeshRoad), MeshRoad::_setSideMaterialName, & defaultProtectedGetFn, "Material for the left, right, front, and back surfaces of the road.", AbstractClassRep::FIELD_HideInInspectors); \
+      addProtectedField("SideMaterialAsset", TypeMaterialAssetId, Offset(mSideMaterialAssetId, MeshRoad), MeshRoad::_setSideMaterialAsset, & defaultProtectedGetFn, "Material for the left, right, front, and back surfaces of the road.");
 
       addField( "textureLength", TypeF32, Offset( mTextureLength, MeshRoad ), 
          "The length in meters of textures mapped to the MeshRoad." );      
@@ -1265,17 +1269,68 @@ void MeshRoad::prepRenderImage( SceneRenderState* state )
 
 void MeshRoad::_initMaterial()
 {
-   for ( U32 i = 0; i < SurfaceCount; i++ )
+   if (mTopMaterialAsset.notNull())
    {
-      if ( mMatInst[i] )
-         SAFE_DELETE( mMatInst[i] );
+      if (!mMatInst[Top] || !String(mTopMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Top]->getMaterial()->getName(), String::NoCase))
+      {
+         SAFE_DELETE(mMatInst[Top]);
 
-      if ( mMaterial[i] )
-         mMatInst[i] = mMaterial[i]->createMatInstance();
-      else
-         mMatInst[i] = MATMGR->createMatInstance( "WarningMaterial" );
+         Material* tMat = nullptr;
+         if (!Sim::findObject(mTopMaterialAsset->getMaterialDefinitionName(), tMat))
+            Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mTopMaterialAsset->getMaterialDefinitionName());
+
+         mMaterial[Top] = tMat;
 
-      mMatInst[i]->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>() );
+         if (mMaterial[Top])
+            mMatInst[Top] = mMaterial[Top]->createMatInstance();
+         else
+            mMatInst[Top] = MATMGR->createMatInstance("WarningMaterial");
+
+         mMatInst[Top]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
+      }
+   }
+
+   if (mBottomMaterialAsset.notNull())
+   {
+      if (!mMatInst[Bottom] || !String(mBottomMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Bottom]->getMaterial()->getName(), String::NoCase))
+      {
+
+         SAFE_DELETE(mMatInst[Bottom]);
+
+         Material* tMat = nullptr;
+         if (!Sim::findObject(mBottomMaterialAsset->getMaterialDefinitionName(), tMat))
+            Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mBottomMaterialAsset->getMaterialDefinitionName());
+
+         mMaterial[Bottom] = tMat;
+
+         if (mMaterial[Bottom])
+            mMatInst[Bottom] = mMaterial[Bottom]->createMatInstance();
+         else
+            mMatInst[Bottom] = MATMGR->createMatInstance("WarningMaterial");
+
+         mMatInst[Bottom]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
+      }
+   }
+
+   if (mSideMaterialAsset.notNull())
+   {
+      if (!mMatInst[Side] || !String(mSideMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Side]->getMaterial()->getName(), String::NoCase))
+      {
+         SAFE_DELETE(mMatInst[Side]);
+
+         Material* tMat = nullptr;
+         if (!Sim::findObject(mSideMaterialAsset->getMaterialDefinitionName(), tMat))
+            Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mSideMaterialAsset->getMaterialDefinitionName());
+
+         mMaterial[Side] = tMat;
+
+         if (mMaterial[Side])
+            mMatInst[Side] = mMaterial[Side]->createMatInstance();
+         else
+            mMatInst[Side] = MATMGR->createMatInstance("WarningMaterial");
+
+         mMatInst[Side]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
+      }
    }
 }
 
@@ -1365,10 +1420,10 @@ U32 MeshRoad::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
       // Write Object Transform.
       stream->writeAffineTransform( mObjToWorld );
 
-      // Write Materials      
-      stream->write( mMaterialName[0] );      
-      stream->write( mMaterialName[1] );
-      stream->write( mMaterialName[2] );
+      // Write Materials
+      packMaterialAsset(con, TopMaterial);
+      packMaterialAsset(con, BottomMaterial);
+      packMaterialAsset(con, SideMaterial);
 
       stream->write( mTextureLength );      
       stream->write( mBreakAngle );
@@ -1465,18 +1520,9 @@ void MeshRoad::unpackUpdate(NetConnection * con, BitStream * stream)
       stream->readAffineTransform(&ObjectMatrix);
       Parent::setTransform(ObjectMatrix);
 
-      // Read Materials...
-      Material *pMat = NULL;
-
-      for ( U32 i = 0; i < SurfaceCount; i++ )
-      {
-         stream->read( &mMaterialName[i] );
-        
-         if ( !Sim::findObject( mMaterialName[i], pMat ) )
-            Con::printf( "DecalRoad::unpackUpdate, failed to find Material of name %s", mMaterialName[i].c_str() );
-         else         
-            mMaterial[i] = pMat;         
-      }
+      unpackMaterialAsset(con, TopMaterial);
+      unpackMaterialAsset(con, BottomMaterial);
+      unpackMaterialAsset(con, SideMaterial);
 
       if ( isProperlyAdded() )
          _initMaterial(); 

+ 7 - 1
Engine/source/environment/meshRoad.h

@@ -52,6 +52,8 @@
 
 #include "math/util/decomposePoly.h"
 
+#include "T3D/assets/MaterialAsset.h"
+
 //extern U32 gIdxArray[6][2][3];
 
 struct MeshRoadHitSegment
@@ -619,7 +621,11 @@ protected:
    GFXVertexBufferHandle<GFXVertexPNTT> mVB[SurfaceCount];   
    GFXPrimitiveBufferHandle mPB[SurfaceCount];      
 
-   String mMaterialName[SurfaceCount];   
+   DECLARE_NET_MATERIALASSET(MeshRoad, TopMaterial, MeshRoadMask);
+   DECLARE_NET_MATERIALASSET(MeshRoad, BottomMaterial, MeshRoadMask);
+   DECLARE_NET_MATERIALASSET(MeshRoad, SideMaterial, MeshRoadMask);
+
+   //String mMaterialName[SurfaceCount];   
    SimObjectPtr<Material> mMaterial[SurfaceCount];
    BaseMatInstance *mMatInst[SurfaceCount];
 

+ 4 - 1
Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.cs

@@ -1058,7 +1058,10 @@ function AssetBrowser::toggleTagFilterPopup(%this)
 function AssetBrowser::changeAsset(%this)
 {
    //alright, we've selectd an asset for a field, so time to set it!
-   %cmd = %this.fieldTargetObject @ "." @ %this.fieldTargetName @ "=\"" @ %this.selectedAsset @ "\";";
+   if(%this.fieldTargetName $= "")
+      %cmd = %this.fieldTargetObject @ ".apply(\""@ %this.selectedAsset @ "\");";
+   else
+      %cmd = %this.fieldTargetObject @ "." @ %this.fieldTargetName @ "=\"" @ %this.selectedAsset @ "\";";
    echo("Changing asset via the " @ %cmd @ " command");
    eval(%cmd);
    

+ 4 - 0
Templates/BaseGame/game/tools/meshRoadEditor/main.cs

@@ -23,6 +23,10 @@
 function initializeMeshRoadEditor()
 {
    echo(" % - Initializing Mesh Road Editor");
+   
+   $MeshRoadEditor::defaultTopMaterialAsset = "Prototyping:FloorGray";
+   $MeshRoadEditor::defaultBottomMaterialAsset = "Prototyping:FloorGray";
+   $MeshRoadEditor::defaultSideMaterialAsset = "Prototyping:WallOrange";
      
    exec( "./meshRoadEditor.cs" );
    exec( "./meshRoadEditorGui.gui" );

+ 5 - 3
Templates/BaseGame/game/tools/roadEditor/main.cs

@@ -24,6 +24,8 @@ function initializeRoadEditor()
 {
    echo( " - Initializing Road and Path Editor" );
    
+   $DecalRoadEditor::defaultMaterialAsset = "Prototyping:FloorGray";
+   
    exec( "./roadEditor.cs" );
    exec( "./RoadEditorGui.gui" );
    exec( "./RoadEditorToolbar.gui");
@@ -183,7 +185,7 @@ function RoadEditorPlugin::initSettings( %this )
    EditorSettings.setDefaultValue(  "HoverSplineColor",     "255 0 0 255" );
    EditorSettings.setDefaultValue(  "SelectedSplineColor",  "0 255 0 255" );
    EditorSettings.setDefaultValue(  "HoverNodeColor",       "255 255 255 255" ); //<-- Not currently used
-   EditorSettings.setDefaultValue(  "MaterialName",         "DefaultDecalRoadMaterial" );
+   EditorSettings.setDefaultValue(  "materialAsset",         "Prototyping:FloorGray" );
    
    EditorSettings.endGroup();
 }
@@ -196,7 +198,7 @@ function RoadEditorPlugin::readSettings( %this )
    RoadEditorGui.HoverSplineColor     = EditorSettings.value("HoverSplineColor");
    RoadEditorGui.SelectedSplineColor  = EditorSettings.value("SelectedSplineColor");
    RoadEditorGui.HoverNodeColor       = EditorSettings.value("HoverNodeColor");
-   RoadEditorGui.materialName         = EditorSettings.value("MaterialName");   
+   RoadEditorGui.materialAsset        = EditorSettings.value("materialAsset");   
    
    EditorSettings.endGroup();  
 }
@@ -209,7 +211,7 @@ function RoadEditorPlugin::writeSettings( %this )
    EditorSettings.setValue( "HoverSplineColor",       RoadEditorGui.HoverSplineColor );
    EditorSettings.setValue( "SelectedSplineColor",    RoadEditorGui.SelectedSplineColor );
    EditorSettings.setValue( "HoverNodeColor",         RoadEditorGui.HoverNodeColor );
-   EditorSettings.setValue( "MaterialName",           RoadEditorGui.materialName );
+   EditorSettings.setValue( "materialAsset",          RoadEditorGui.materialAsset );
    
    EditorSettings.endGroup();
 }