Browse Source

Merge pull request #1340 from marauder2k9-torque/ImageAsset-NamedTexTarget

NamedTexTargets as ImageAssets
Brian Roberts 8 tháng trước cách đây
mục cha
commit
69fa4b389f

+ 54 - 11
Engine/source/T3D/assets/ImageAsset.cpp

@@ -274,6 +274,20 @@ U32 ImageAsset::load()
    if (mLoadedState == AssetErrCode::Ok) return mLoadedState;
    if (mImagePath)
    {
+      // this is a target.
+      if (mImageFileName[0] == '$' || mImageFileName[0] == '#')
+      {
+         NamedTexTargetRef namedTarget = NamedTexTarget::find(mImageFileName + 1);
+         if (namedTarget) {
+            mLoadedState = Ok;
+            mIsValidImage = true;
+            return mLoadedState;
+         }
+         else
+         {
+            Con::errorf("ImageAsset::initializeAsset: Attempted find named target %s failed.", mImageFileName);
+         }
+      }
       if (!Torque::FS::IsFile(mImagePath))
       {
          Con::errorf("ImageAsset::initializeAsset: Attempted to load file %s but it was not valid!", mImageFileName);
@@ -295,12 +309,26 @@ void ImageAsset::initializeAsset()
 {
    ResourceManager::get().getChangedSignal().notify(this, &ImageAsset::_onResourceChanged);
 
-   mImagePath = getOwned() ? expandAssetFilePath(mImageFileName) : mImagePath;
+   if (mImageFileName[0] != '$' && mImageFileName[0] != '#')
+   {
+      mImagePath = getOwned() ? expandAssetFilePath(mImageFileName) : mImagePath;
+   }
+   else
+   {
+      mImagePath = mImageFileName;
+   }
 }
 
 void ImageAsset::onAssetRefresh()
 {
-   mImagePath = getOwned() ? expandAssetFilePath(mImageFileName) : mImagePath;
+   if (mImageFileName[0] != '$' && mImageFileName[0] != '#')
+   {
+      mImagePath = getOwned() ? expandAssetFilePath(mImageFileName) : mImagePath;
+   }
+   else
+   {
+      mImagePath = mImageFileName;
+   }
 
    AssetManager::typeAssetDependsOnHash::Iterator assetDependenciesItr = mpOwningAssetManager->getDependedOnAssets()->find(mpAssetDefinition->mAssetId);
    // Iterate all dependencies.
@@ -334,6 +362,7 @@ void ImageAsset::setImageFileName(const char* pScriptFile)
 
 GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile)
 {
+   load();
    if (mResourceMap.contains(requestedProfile))
    {
       mLoadedState = Ok;
@@ -341,21 +370,35 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile)
    }
    else
    {
-      //If we don't have an existing map case to the requested format, we'll just create it and insert it in
-      GFXTexHandle newTex = TEXMGR->createTexture(mImagePath, requestedProfile);
-      if (newTex)
+      // this is a target.
+      if (mImageFileName[0] == '$' || mImageFileName[0] == '#')
       {
-         mResourceMap.insert(requestedProfile, newTex);
          mLoadedState = Ok;
-         return newTex;
+         NamedTexTargetRef namedTarget = NamedTexTarget::find(mImageFileName + 1);
+         if (namedTarget.isValid() && namedTarget->getTexture())
+         {
+            mNamedTarget = namedTarget;
+            mIsValidImage = true;
+            mResourceMap.insert(requestedProfile, mNamedTarget->getTexture());
+            mChangeSignal.trigger();
+            return mNamedTarget->getTexture();
+         }
       }
       else
-         mLoadedState = BadFileReference;
+      {
+         //If we don't have an existing map case to the requested format, we'll just create it and insert it in
+         GFXTexHandle newTex = TEXMGR->createTexture(mImagePath, requestedProfile);
+         if (newTex)
+         {
+            mResourceMap.insert(requestedProfile, newTex);
+            mLoadedState = Ok;
+            return newTex;
+         }
+         else
+            mLoadedState = BadFileReference;
+      }
    }
 
-   //if (mTexture.isValid())
-   //   return mTexture;
-
    return nullptr;
 }
 

+ 27 - 7
Engine/source/T3D/assets/ImageAsset.h

@@ -50,6 +50,11 @@
 #include "assetMacroHelpers.h"
 
 #include "gfx/gfxDevice.h"
+
+#ifndef _MATTEXTURETARGET_H_
+#include "materials/matTextureTarget.h"
+#endif
+
 //-----------------------------------------------------------------------------
 class ImageAsset : public AssetBase
 {
@@ -95,6 +100,7 @@ public:
 protected:
    StringTableEntry mImageFileName;
    StringTableEntry mImagePath;
+   NamedTexTargetRef mNamedTarget;
 
    bool mIsValidImage;
    bool mUseMips;
@@ -205,7 +211,7 @@ public: \
          }\
          else if(_in[0] == '$' || _in[0] == '#')\
          {\
-            m##name##Name = _in;\
+            m##name##Name =  _in;\
             m##name##AssetId = StringTable->EmptyString();\
             m##name##Asset = NULL;\
             m##name.free();\
@@ -250,7 +256,9 @@ public: \
             m##name##Asset->getChangedSignal().notify(this, &className::changeFunc);\
          }\
          \
-         m##name.set(get##name(), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
+         if (get##name()[0] != '$' && get##name()[0] != '#') {\
+            m##name.set(get##name(), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
+         }\
       }\
       else\
       {\
@@ -278,7 +286,10 @@ public: \
    const StringTableEntry get##name() const\
    {\
       if (m##name##Asset && (m##name##Asset->getImageFileName() != StringTable->EmptyString()))\
-         return  Platform::makeRelativePathName(m##name##Asset->getImagePath(), Platform::getMainDotCsDir());\
+         if (m##name##Asset->getImageFileName()[0] == '#' || m##name##Asset->getImageFileName()[0] == '$')\
+            return m##name##Asset->getImageFileName();\
+         else\
+            return  Platform::makeRelativePathName(m##name##Asset->getImagePath(), Platform::getMainDotCsDir());\
       else if (m##name##AssetId != StringTable->EmptyString())\
          return m##name##AssetId;\
       else if (m##name##Name != StringTable->EmptyString())\
@@ -288,6 +299,8 @@ public: \
    }\
    GFXTexHandle get##name##Resource() \
    {\
+      if (m##name##Asset && (m##name##Asset->getImageFileName() != StringTable->EmptyString()))\
+         return m##name##Asset->getTexture(m##name##Profile);\
       return m##name;\
    }\
    bool name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
@@ -323,7 +336,7 @@ if (m##name##AssetId != StringTable->EmptyString())\
 #pragma region Arrayed Asset Macros
 
 //Arrayed Assets
-#define DECLARE_IMAGEASSET_ARRAY(className, name, max) public: \
+#define DECLARE_IMAGEASSET_ARRAY(className, name, max, changeFunc) public: \
    static const U32 sm##name##Count = max;\
    GFXTexHandle m##name[max];\
    StringTableEntry m##name##Name[max]; \
@@ -353,7 +366,7 @@ public: \
          }\
          else if(_in[0] == '$' || _in[0] == '#')\
          {\
-            m##name##Name[index] = _in;\
+            m##name##Name[index] =  _in;\
             m##name##AssetId[index] = StringTable->EmptyString();\
             m##name##Asset[index] = NULL;\
             m##name[index].free();\
@@ -393,7 +406,9 @@ public: \
       }\
       if (get##name(index) != StringTable->EmptyString() && m##name##Name[index] != StringTable->insert("texhandle"))\
       {\
-         m##name[index].set(get##name(index), m##name##Profile[index], avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
+         m##name##Asset[index]->getChangedSignal().notify(this, &className::changeFunc);\
+         if (get##name(index)[0] != '$' && get##name(index)[0] != '#')\
+            m##name[index].set(get##name(index), m##name##Profile[index], avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
       }\
       else\
       {\
@@ -421,7 +436,10 @@ public: \
    const StringTableEntry get##name(const U32& index) const\
    {\
       if (m##name##Asset[index] && (m##name##Asset[index]->getImageFileName() != StringTable->EmptyString()))\
-         return  Platform::makeRelativePathName(m##name##Asset[index]->getImagePath(), Platform::getMainDotCsDir());\
+         if (m##name##Asset[index]->getImageFileName()[0] == '#' || m##name##Asset[index]->getImageFileName()[0] == '$')\
+            return m##name##Asset[index]->getImageFileName();\
+         else\
+            return  Platform::makeRelativePathName(m##name##Asset[index]->getImagePath(), Platform::getMainDotCsDir());\
       else if (m##name##AssetId[index] != StringTable->EmptyString())\
          return m##name##AssetId[index];\
       else if (m##name##Name[index] != StringTable->EmptyString())\
@@ -438,6 +456,8 @@ public: \
    {\
       if(index >= sm##name##Count || index < 0)\
          return nullptr;\
+      if (m##name##Asset[index] && (m##name##Asset[index]->getImageFileName() != StringTable->EmptyString()))\
+         return m##name##Asset[index]->getTexture(m##name##Profile[index]);\
       return m##name[index];\
    }\
    bool name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); }

+ 2 - 1
Engine/source/T3D/fx/splash.h

@@ -122,8 +122,9 @@ public:
    F32               times[ NUM_TIME_KEYS ];
    LinearColorF            colors[ NUM_TIME_KEYS ];
 
-   DECLARE_IMAGEASSET_ARRAY(SplashData, Texture, NUM_TEX);
+   DECLARE_IMAGEASSET_ARRAY(SplashData, Texture, NUM_TEX, onTextureChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(SplashData, Texture)
+   void onTextureChanged() {}
 
    ExplosionData*    explosion;
    S32               explosionId;

+ 2 - 2
Engine/source/environment/basicClouds.h

@@ -94,9 +94,9 @@ protected:
    static U32 smVertCount;
    static U32 smTriangleCount;
 
-   DECLARE_IMAGEASSET_ARRAY(BasicClouds, Texture, TEX_COUNT);
+   DECLARE_IMAGEASSET_ARRAY(BasicClouds, Texture, TEX_COUNT, onTextureChanged);
    DECLARE_IMAGEASSET_ARRAY_NET_SETGET(BasicClouds, Texture, -1);
-
+   void onTextureChanged() {}
    GFXStateBlockRef mStateblock;
 
    GFXShaderRef mShader;

+ 2 - 1
Engine/source/gfx/sim/cubemapData.h

@@ -76,9 +76,10 @@ protected:
    DECLARE_IMAGEASSET(CubemapData, CubeMap, onCubemapChanged, GFXStaticTextureSRGBProfile);
    DECLARE_ASSET_SETGET(CubemapData, CubeMap);
 
-   DECLARE_IMAGEASSET_ARRAY(CubemapData, CubeMapFace, 6);
+   DECLARE_IMAGEASSET_ARRAY(CubemapData, CubeMapFace, 6, onCubeMapFaceChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(CubemapData, CubeMapFace);
 
+   void onCubeMapFaceChanged() {}
    GFXTexHandle mDepthBuff;
    GFXTextureTargetRef mRenderTarget;
 

+ 2 - 2
Engine/source/gui/controls/guiPopUpCtrl.h

@@ -126,9 +126,9 @@ protected:
       NumBitmapModes = 2
    };
 
-   DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrl, Bitmap, NumBitmapModes);
+   DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrl, Bitmap, NumBitmapModes, onBitmapChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(GuiPopUpMenuCtrl, Bitmap);
-
+   void onBitmapChanged() {}
    Point2I mBitmapBounds; //  Added
 	S32 mIdMax;
 

+ 2 - 2
Engine/source/gui/controls/guiPopUpCtrlEx.h

@@ -131,9 +131,9 @@ class GuiPopUpMenuCtrlEx : public GuiTextCtrl
       NumBitmapModes = 2
    };
 
-   DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrlEx, Bitmap, NumBitmapModes);
+   DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrlEx, Bitmap, NumBitmapModes, onBitmapChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(GuiPopUpMenuCtrlEx, Bitmap);
-
+   void onBitmapChanged() {}
    Point2I mBitmapBounds; //  Added
 
 	S32 mIdMax;

+ 6 - 0
Engine/source/materials/materialDefinition.cpp

@@ -243,6 +243,11 @@ Material::Material()
    mReverbSoundOcclusion = 1.0;
 }
 
+void Material::onImageAssetChanged()
+{
+   flush();
+   reload();
+}
 
 void Material::initPersistFields()
 {
@@ -857,3 +862,4 @@ DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap);
 DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap);
 DEF_IMAGEASSET_ARRAY_BINDS(Material, GlowMap);
 DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailNormalMap);
+

+ 14 - 12
Engine/source/materials/materialDefinition.h

@@ -208,49 +208,51 @@ public:
    //-----------------------------------------------------------------------
    // Data
    //-----------------------------------------------------------------------
-   DECLARE_IMAGEASSET_ARRAY(Material, DiffuseMap, MAX_STAGES);
+   void onImageAssetChanged();
+
+   DECLARE_IMAGEASSET_ARRAY(Material, DiffuseMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DiffuseMap);
 
    bool     mDiffuseMapSRGB[MAX_STAGES];   // SRGB diffuse
-   DECLARE_IMAGEASSET_ARRAY(Material, OverlayMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, OverlayMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, OverlayMap);
 
-   DECLARE_IMAGEASSET_ARRAY(Material, LightMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, LightMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, LightMap);
 
-   DECLARE_IMAGEASSET_ARRAY(Material, ToneMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, ToneMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, ToneMap);
 
-   DECLARE_IMAGEASSET_ARRAY(Material, DetailMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, DetailMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DetailMap);
 
-   DECLARE_IMAGEASSET_ARRAY(Material, NormalMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, NormalMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, NormalMap);
 
-   DECLARE_IMAGEASSET_ARRAY(Material, ORMConfigMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, ORMConfigMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, ORMConfigMap);
 
    bool     mIsSRGb[MAX_STAGES];
-   DECLARE_IMAGEASSET_ARRAY(Material, AOMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, AOMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, AOMap);
    F32      mAOChan[MAX_STAGES];
 
-   DECLARE_IMAGEASSET_ARRAY(Material, RoughMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, RoughMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, RoughMap);
    bool     mInvertRoughness[MAX_STAGES];
    F32      mRoughnessChan[MAX_STAGES];
 
-   DECLARE_IMAGEASSET_ARRAY(Material, MetalMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, MetalMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, MetalMap);
 
    F32      mMetalChan[MAX_STAGES];
-   DECLARE_IMAGEASSET_ARRAY(Material, GlowMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, GlowMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, GlowMap);
 
    F32      mGlowMul[MAX_STAGES];
    /// A second normal map which repeats at the detail map
    /// scale and blended with the base normal map.
-   DECLARE_IMAGEASSET_ARRAY(Material, DetailNormalMap, MAX_STAGES);
+   DECLARE_IMAGEASSET_ARRAY(Material, DetailNormalMap, MAX_STAGES, onImageAssetChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DetailNormalMap);
 
    /// The strength scalar for the detail normal map.

+ 38 - 3
Engine/source/materials/materialManager.cpp

@@ -61,6 +61,8 @@ MaterialManager::MaterialManager()
    mLastTime = 0;
    mDampness = 0.0f;
    mWarningInst = NULL;
+   mMatDefToFlush = NULL;
+   mMatDefToReload = NULL;
    
    GFXDevice::getDeviceEventSignal().notify( this, &MaterialManager::_handleGFXEvent );
 
@@ -73,6 +75,8 @@ MaterialManager::MaterialManager()
    mUsingDeferred = false;
 
    mFlushAndReInit = false;
+   mMatDefShouldFlush = false;
+   mMatDefShouldReload = false;
 
    mDefaultAnisotropy = 1;
    Con::addVariable( "$pref::Video::defaultAnisotropy", TypeS32, &mDefaultAnisotropy, 
@@ -324,6 +328,12 @@ String MaterialManager::getMapEntry(const String & textureName) const
 }
 
 void MaterialManager::flushAndReInitInstances()
+{
+   // delay flushes and reinits until the start of the next frame.
+   mFlushAndReInit = true;
+}
+
+void MaterialManager::_flushAndReInitInstances()
 {
    // Clear the flag if its set.
    mFlushAndReInit = false;   
@@ -359,8 +369,15 @@ void MaterialManager::flushAndReInitInstances()
 }
 
 // Used in the materialEditor. This flushes the material preview object so it can be reloaded easily.
-void MaterialManager::flushInstance( BaseMaterialDefinition *target )
+void MaterialManager::flushInstance(BaseMaterialDefinition* target)
 {
+   mMatDefToFlush = target;
+   mMatDefShouldFlush = true;
+}
+
+void MaterialManager::_flushInstance( BaseMaterialDefinition *target )
+{
+   mMatDefShouldFlush = false;
    Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
    while ( iter != mMatInstanceList.end() )
    {
@@ -371,16 +388,26 @@ void MaterialManager::flushInstance( BaseMaterialDefinition *target )
       }
 	  iter++;
    }
+
+   mMatDefToFlush = NULL;
+}
+
+void MaterialManager::reInitInstance(BaseMaterialDefinition* target)
+{
+   mMatDefToReload = target;
+   mMatDefShouldReload = true;
 }
 
-void MaterialManager::reInitInstance( BaseMaterialDefinition *target )
+void MaterialManager::_reInitInstance( BaseMaterialDefinition *target )
 {
+   mMatDefShouldReload = false;
    Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
    for ( ; iter != mMatInstanceList.end(); iter++ )
    {
       if ( (*iter)->getMaterial() == target )
          (*iter)->reInit();
    }
+   mMatDefToReload = NULL;
 }
 
 void MaterialManager::updateTime()
@@ -499,7 +526,15 @@ bool MaterialManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ )
 
       case GFXDevice::deStartOfFrame:
          if ( mFlushAndReInit )
-            flushAndReInitInstances();
+            _flushAndReInitInstances();
+         if (mMatDefShouldFlush)
+         {
+            _flushInstance(mMatDefToFlush);
+         }
+         if (mMatDefShouldReload)
+         {
+            _reInitInstance(mMatDefToReload);
+         }
          break;
 
       default:

+ 11 - 4
Engine/source/materials/materialManager.h

@@ -116,11 +116,7 @@ public:
    /// Returns the signal used to notify systems that the 
    /// procedural shaders have been flushed.
    FlushSignal& getFlushSignal() { return mFlushSignal; }
-
-   /// Flushes all the procedural shaders and re-initializes all
-   /// the active materials instances immediately.
    void flushAndReInitInstances();
-
    // Flush the instance
    void flushInstance( BaseMaterialDefinition *target );
 
@@ -133,7 +129,14 @@ protected:
    friend class MatInstance;
    void _track(MatInstance*);
    void _untrack(MatInstance*);
+   /// Flushes all the procedural shaders and re-initializes all
+   /// the active materials instances immediately.
+   void _flushAndReInitInstances();
+   // Flush the instance
+   void _flushInstance(BaseMaterialDefinition* target);
 
+   /// Re-initializes the material instances for a specific target material.   
+   void _reInitInstance(BaseMaterialDefinition* target);
    /// @see LightManager::smActivateSignal
    void _onLMActivate( const char *lm, bool activate );
 
@@ -155,6 +158,8 @@ protected:
    /// If set we flush and reinitialize all materials at the
    /// start of the next rendered frame.
    bool mFlushAndReInit;
+   bool mMatDefShouldReload;
+   bool mMatDefShouldFlush;
 
    // material map
    typedef Map<String, String> MaterialMap;
@@ -169,6 +174,8 @@ protected:
    F32 mDampness;
 
    BaseMatInstance* mWarningInst;
+   BaseMaterialDefinition* mMatDefToFlush;
+   BaseMaterialDefinition* mMatDefToReload;
 
    /// The default max anisotropy used in texture filtering.
    S32 mDefaultAnisotropy;

+ 6 - 7
Engine/source/materials/processedMaterial.cpp

@@ -395,11 +395,12 @@ void ProcessedMaterial::_setStageData()
       if (mMaterial->mDiffuseMapAsset[i] && !mMaterial->mDiffuseMapAsset[i].isNull())
       {
          mStages[i].setTex(MFT_DiffuseMap, mMaterial->getDiffuseMapResource(i));
-         //mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->getDiffuseMap(i), &GFXStaticTextureSRGBProfile));
          if (!mStages[i].getTex(MFT_DiffuseMap))
          {
-            // Load a debug texture to make it clear to the user 
-            // that the texture for this stage was missing.
+            // If we start with a #, we're probably actually attempting to hit a named target and it may not get a hit on the first pass.
+            if (!String(mMaterial->mDiffuseMapAsset[i]->getImageFileName()).startsWith("#") && !String(mMaterial->mDiffuseMapAsset[i]->getImageFileName()).startsWith("$"))
+               mMaterial->logError("Failed to load diffuse map %s for stage %i", mMaterial->mDiffuseMapAsset[i]->getImageFileName(), i);
+
             mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
          }
       }
@@ -408,9 +409,8 @@ void ProcessedMaterial::_setStageData()
          mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->mDiffuseMapName[i], &GFXStaticTextureSRGBProfile));
          if (!mStages[i].getTex(MFT_DiffuseMap))
          {
-            //If we start with a #, we're probably actually attempting to hit a named target and it may not get a hit on the first pass. So we'll
-            //pass on the error rather than spamming the console
-            if (!String(mMaterial->mDiffuseMapName[i]).startsWith("#"))
+            //If we start with a #, we're probably actually attempting to hit a named target and it may not get a hit on the first pass.
+            if (!String(mMaterial->mDiffuseMapName[i]).startsWith("#") && !String(mMaterial->mDiffuseMapName[i]).startsWith("$"))
                mMaterial->logError("Failed to load diffuse map %s for stage %i", mMaterial->mDiffuseMapName[i], i);
 
             // Load a debug texture to make it clear to the user 
@@ -418,7 +418,6 @@ void ProcessedMaterial::_setStageData()
             mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
          }
       }
-
       // OverlayMap
       if (mMaterial->getOverlayMap(i) != StringTable->EmptyString())
       {

+ 2 - 1
Engine/source/postFx/postEffect.h

@@ -90,8 +90,9 @@ public:
 
 protected:
 
-   DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, NumTextures);
+   DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, NumTextures, onTextureChanged);
    DECLARE_IMAGEASSET_ARRAY_SETGET(PostEffect, Texture);
+   void onTextureChanged() {}
 
    bool mTexSRGB[NumTextures];