浏览代码

Add texture size fields to terrain textures and improve editor performance

Lukas Aldershaab 4 年之前
父节点
当前提交
d3996aec84

+ 63 - 27
Engine/source/gfx/gfxTextureArray.cpp

@@ -6,8 +6,35 @@
 #include "bitmap/imageUtils.h"
 #include "console/console.h"
 
+GFXTextureArray::GFXTextureArray()
+   : mFormat(GFXFormat_COUNT),
+     mIsCompressed(false),
+     mWidth(0),
+     mHeight(0),
+     mArraySize(0),
+     mMipLevels(0)
+{
+}
+
 void GFXTextureArray::set(U32 width, U32 height, U32 size, GFXFormat format, U32 mipLevels)
 {
+   if (mipLevels == 0 && width == height && isPow2(width))
+   {
+      mipLevels = mLog2(static_cast<F32>(width)) + 1;
+   }
+   if (
+      mWidth == width &&
+      mHeight == height &&
+      mArraySize == size &&
+      mFormat == format &&
+      mMipLevels == mipLevels
+      )
+   {
+      return;
+   }
+
+   Release();
+
    mWidth = width;
    mHeight = height;
    mArraySize = size;
@@ -20,43 +47,52 @@ void GFXTextureArray::set(U32 width, U32 height, U32 size, GFXFormat format, U32
    init();
 }
 
-bool GFXTextureArray::fromTextureArray(const Vector<GFXTexHandle>& textureArray)
+bool GFXTextureArray::fromTextureArray(const Vector<GFXTexHandle>& textureArray, U32 capacity)
 {
    bool success = true;
 
-   //---------------------------------------------------------------------------------------
-   //	Create the texture array.  Each element in the texture 
-   //		array has the same format/dimensions.
-   //---------------------------------------------------------------------------------------
-   bool found = false;
-   for (const GFXTexHandle& texObj : textureArray)
+   // Not initialized, infer it from the given array of textures
+   if (mArraySize == 0)
    {
-      if (texObj.isValid())
+      bool found = false;
+      for (const GFXTexHandle& texObj : textureArray)
       {
-         if (!found)
-         {
-            found = true;
-            mFormat = texObj.getFormat();
-            mWidth = texObj.getWidth();
-            mHeight = texObj.getHeight();
-            mMipLevels = texObj->getMipLevels();
-         }
-
-         if (mFormat != texObj.getFormat() || mWidth != texObj.getWidth() || mHeight != texObj.getHeight())
+         if (texObj.isValid())
          {
-            AssertWarn(true, "GFXTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format");
-            Con::warnf("GFXTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format");
-            success = false;
-            mFormat = GFXFormatR8G8B8A8;
+            if (!found)
+            {
+               found = true;
+               mFormat = texObj.getFormat();
+               mWidth = texObj.getWidth();
+               mHeight = texObj.getHeight();
+               mMipLevels = texObj->getMipLevels();
+            }
+
+            if (mFormat != texObj.getFormat() || mWidth != texObj.getWidth() || mHeight != texObj.getHeight())
+            {
+               AssertWarn(true, "GFXTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format");
+               Con::warnf("GFXTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format");
+               success = false;
+               mFormat = GFXFormatR8G8B8A8;
+            }
          }
       }
-   }
 
-   // One might think this should return false in this case, but the return value is mostly to highlight internal errors not input errors.
-   if (!found) return true;
+      // One might think this should return false in this case, but the return value is mostly to highlight internal errors not input errors.
+      if (!found) return true;
 
-   set(mWidth, mHeight, textureArray.size(), mFormat, mMipLevels);
 
+      //---------------------------------------------------------------------------------------
+      //	Create the texture array.  Each element in the texture 
+      //		array has the same format/dimensions.
+      //---------------------------------------------------------------------------------------
+      U32 size = capacity;
+      if (size == 0)
+      {
+         size = textureArray.size();
+      }
+      set(mWidth, mHeight, size, mFormat, mMipLevels);
+   }
    //---------------------------------------------------------------------------------------
 
 
@@ -64,7 +100,7 @@ bool GFXTextureArray::fromTextureArray(const Vector<GFXTexHandle>& textureArray)
    //	Copy individual texture elements into texture array.
    //---------------------------------------------------------------------------------------
    // for each texture element...
-   for (U32 i = 0; i < mArraySize; ++i)
+   for (U32 i = 0; i < textureArray.size(); ++i)
    {
       if (textureArray[i].isValid())
       {

+ 4 - 2
Engine/source/gfx/gfxTextureArray.h

@@ -44,9 +44,11 @@ class GFXTextureObject;
 class GFXTextureArray : public StrongRefBase, public GFXResource
 {
 public:
+   GFXTextureArray();
+
    virtual void init() = 0;
-   virtual void set(U32 width, U32 height, U32 size, GFXFormat format, U32 mipLevels);
-   virtual bool fromTextureArray(const Vector<GFXTexHandle> &textureArray);
+   virtual void set(U32 width, U32 height, U32 size, GFXFormat format, U32 mipLevels = 0);
+   virtual bool fromTextureArray(const Vector<GFXTexHandle> &textureArray, U32 capacity = 0);
    virtual void setTexture(const GFXTexHandle &texture, U32 slot);
    virtual void setToTexUnit(U32 tuNum) = 0;
 

+ 4 - 1
Engine/source/gfx/gfxTextureManager.cpp

@@ -894,7 +894,7 @@ Torque::Path GFXTextureManager::validatePath(const Torque::Path &path)
    return correctPath;
 }
 
-GBitmap *GFXTextureManager::loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile, U32 width, U32 height)
+GBitmap *GFXTextureManager::loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile, U32 width, U32 height, bool genMips)
 {
    GBitmap* inBitmap = loadUncompressedTexture(path, &GFXTexturePersistentProfile);
 
@@ -927,6 +927,9 @@ GBitmap *GFXTextureManager::loadUncompressedTexture(const Torque::Path &path, GF
       }
    }
 
+   if (genMips)
+      outBmp->extrudeMipLevels();
+
    return outBmp;
 }
 

+ 1 - 1
Engine/source/gfx/gfxTextureManager.h

@@ -132,7 +132,7 @@ public:
       S32 antialiasLevel);
 
    Torque::Path validatePath(const Torque::Path &path);
-   GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height);
+   GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height, bool genMips = false);
    GBitmap *loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile);
    virtual GFXTextureObject *createCompositeTexture(const Torque::Path &pathR, const Torque::Path &pathG, const Torque::Path &pathB, const Torque::Path &pathA, U32 inputKey[4],
       GFXTextureProfile *profile);

+ 253 - 0
Engine/source/terrain/terrData.cpp

@@ -47,6 +47,7 @@
 #include "materials/baseMatInstance.h"
 #include "gfx/gfxTextureManager.h"
 #include "gfx/gfxCardProfile.h"
+#include "gfx/gfxAPI.h"
 #include "core/resourceManager.h"
 #include "T3D/physics/physicsPlugin.h"
 #include "T3D/physics/physicsBody.h"
@@ -196,6 +197,14 @@ TerrainBlock::TerrainBlock()
    mLayerTexDirty( false ),
    mBaseTexSize( 1024 ),
    mBaseTexFormat( TerrainBlock::DDS ),
+   mDetailTexSize(0),
+   mDetailTexFormat(GFXFormat_COUNT),
+   mMacroTexSize(0),
+   mMacroTexFormat(GFXFormat_COUNT),
+   mNormalTexSize(0),
+   mNormalTexFormat(GFXFormat_COUNT),
+   mOrmTexSize(0),
+   mOrmTexFormat(GFXFormat_COUNT),
    mCell( NULL ),
    mBaseMaterial( NULL ),
    mDefaultMatInst( NULL ),
@@ -346,6 +355,142 @@ bool TerrainBlock::_setLightMapSize( void *obj, const char *index, const char *d
    return false;
 }
 
+bool TerrainBlock::_setDetailTexSize(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   S32 size;
+   castConsoleTypeFromString(size, data);
+
+   if (terrain->mDetailTexSize != size)
+   {
+      terrain->mDetailTexSize = size;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setDetailTexFormat(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   GFXFormat format;
+   castConsoleTypeFromString(format, data);
+
+   if (terrain->mDetailTexFormat != format)
+   {
+      terrain->mDetailTexFormat = format;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setMacroTexSize(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   S32 size;
+   castConsoleTypeFromString(size, data);
+
+   if (terrain->mMacroTexSize != size)
+   {
+      terrain->mMacroTexSize = size;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setMacroTexFormat(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   GFXFormat format;
+   castConsoleTypeFromString(format, data);
+
+   if (terrain->mMacroTexFormat != format)
+   {
+      terrain->mMacroTexFormat = format;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setNormalTexSize(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   S32 size;
+   castConsoleTypeFromString(size, data);
+
+   if (terrain->mNormalTexSize != size)
+   {
+      terrain->mNormalTexSize = size;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setNormalTexFormat(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   GFXFormat format;
+   castConsoleTypeFromString(format, data);
+
+   if (terrain->mNormalTexFormat != format)
+   {
+      terrain->mNormalTexFormat = format;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setOrmTexSize(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   S32 size;
+   castConsoleTypeFromString(size, data);
+
+   if (terrain->mOrmTexSize != size)
+   {
+      terrain->mOrmTexSize = size;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
+bool TerrainBlock::_setOrmTexFormat(void* obj, const char* index, const char* data)
+{
+   TerrainBlock* terrain = static_cast<TerrainBlock*>(obj);
+
+   GFXFormat format;
+   castConsoleTypeFromString(format, data);
+
+   if (terrain->mOrmTexFormat != format)
+   {
+      terrain->mOrmTexFormat = format;
+      terrain->_updateMaterials();
+      terrain->setMaskBits(MaterialMask);
+   }
+
+   return false;
+}
+
 bool TerrainBlock::setFile( const FileName &terrFileName )
 {
    if ( mTerrainAsset && mTerrainAsset->getTerrainFilePath() == terrFileName )
@@ -1295,6 +1440,38 @@ void TerrainBlock::initPersistFields()
          &TerrainBlock::_setLightMapSize, &defaultProtectedGetFn,
          "Light map dimensions in pixels." );
 
+      addProtectedField("detailTexSize", TypeS32, Offset(mDetailTexSize, TerrainBlock),
+         &TerrainBlock::_setDetailTexSize, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("detailTexFormat", TypeGFXFormat, Offset(mDetailTexFormat, TerrainBlock),
+         &TerrainBlock::_setDetailTexFormat, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("macroTexSize", TypeS32, Offset(mMacroTexSize, TerrainBlock),
+         &TerrainBlock::_setMacroTexSize, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("macroTexFormat", TypeGFXFormat, Offset(mMacroTexFormat, TerrainBlock),
+         &TerrainBlock::_setMacroTexFormat, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("normalTexSize", TypeS32, Offset(mNormalTexSize, TerrainBlock),
+         &TerrainBlock::_setNormalTexSize, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("normalTexFormat", TypeGFXFormat, Offset(mNormalTexFormat, TerrainBlock),
+         &TerrainBlock::_setNormalTexFormat, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("ormTexSize", TypeS32, Offset(mOrmTexSize, TerrainBlock),
+         &TerrainBlock::_setOrmTexSize, &defaultProtectedGetFn,
+         "");
+
+      addProtectedField("ormTexFormat", TypeGFXFormat, Offset(mOrmTexFormat, TerrainBlock),
+         &TerrainBlock::_setOrmTexFormat, &defaultProtectedGetFn,
+         "");
+
       addField( "screenError", TypeS32, Offset( mScreenError, TerrainBlock ), "Not yet implemented." );
 	
       addField( "updateBasetex", TypeBool, Offset( mUpdateBasetex, TerrainBlock ), "Whether or not to update the Base Texture" );
@@ -1347,6 +1524,15 @@ U32 TerrainBlock::packUpdate(NetConnection* con, U32 mask, BitStream *stream)
    {
       stream->write( mBaseTexSize );
       stream->write( mLightMapSize );
+
+      stream->write( mDetailTexSize );
+      stream->write( static_cast<S32>(mDetailTexFormat) );
+      stream->write( mMacroTexSize );
+      stream->write( static_cast<S32>(mMacroTexFormat) );
+      stream->write( mNormalTexSize );
+      stream->write( static_cast<S32>(mNormalTexFormat) );
+      stream->write( mOrmTexSize );
+      stream->write( static_cast<S32>(mOrmTexFormat) );
    }
 
    stream->writeFlag( mask & HeightMapChangeMask );
@@ -1409,6 +1595,73 @@ void TerrainBlock::unpackUpdate(NetConnection* con, BitStream *stream)
             clearLightMap();
          }
       }
+
+      bool updateMaterials = false;
+
+      U32 detailTexSize;
+      stream->read(&detailTexSize);
+      if (mDetailTexSize != detailTexSize)
+      {
+         mDetailTexSize = detailTexSize;
+         updateMaterials = true;
+      }
+      S32 detailTexFormat;
+      stream->read(&detailTexFormat);
+      if (mDetailTexFormat != detailTexFormat)
+      {
+         mDetailTexFormat = static_cast<GFXFormat>(detailTexFormat);
+         updateMaterials = true;
+      }
+
+      U32 macroTexSize;
+      stream->read(&macroTexSize);
+      if (mMacroTexSize != macroTexSize)
+      {
+         mMacroTexSize = macroTexSize;
+         updateMaterials = true;
+      }
+      S32 macroTexFormat;
+      stream->read(&macroTexFormat);
+      if (mMacroTexFormat != macroTexFormat)
+      {
+         mMacroTexFormat = static_cast<GFXFormat>(macroTexFormat);
+         updateMaterials = true;
+      }
+
+      U32 normalTexSize;
+      stream->read(&normalTexSize);
+      if (mNormalTexSize != normalTexSize)
+      {
+         mNormalTexSize = normalTexSize;
+         updateMaterials = true;
+      }
+      S32 normalTexFormat;
+      stream->read(&normalTexFormat);
+      if (mNormalTexFormat != normalTexFormat)
+      {
+         mNormalTexFormat = static_cast<GFXFormat>(normalTexFormat);
+         updateMaterials = true;
+      }
+
+      U32 ormTexSize;
+      stream->read(&ormTexSize);
+      if (mOrmTexSize != ormTexSize)
+      {
+         mOrmTexSize = ormTexSize;
+         updateMaterials = true;
+      }
+      S32 ormTexFormat;
+      stream->read(&ormTexFormat);
+      if (mOrmTexFormat != ormTexFormat)
+      {
+         mOrmTexFormat = static_cast<GFXFormat>(ormTexFormat);
+         updateMaterials = true;
+      }
+
+      if (updateMaterials && isProperlyAdded())
+      {
+         _updateMaterials();
+      }
    }
 
    if ( stream->readFlag() && isProperlyAdded() ) // HeightMapChangeMask

+ 17 - 0
Engine/source/terrain/terrData.h

@@ -174,6 +174,15 @@ protected:
 
    BaseTexFormat mBaseTexFormat;
 
+   U32 mDetailTexSize;
+   GFXFormat mDetailTexFormat;
+   U32 mMacroTexSize;
+   GFXFormat mMacroTexFormat;
+   U32 mNormalTexSize;
+   GFXFormat mNormalTexFormat;
+   U32 mOrmTexSize;
+   GFXFormat mOrmTexFormat;
+
    ///
    TerrCell *mCell;
 
@@ -258,6 +267,14 @@ protected:
    static bool _setSquareSize( void *obj, const char *index, const char *data );
    static bool _setBaseTexSize(void *obj, const char *index, const char *data);
    static bool _setBaseTexFormat(void *obj, const char *index, const char *data);
+   static bool _setDetailTexSize(void *obj, const char *index, const char *data);
+   static bool _setDetailTexFormat(void *obj, const char *index, const char *data);
+   static bool _setMacroTexSize(void *obj, const char *index, const char *data);
+   static bool _setMacroTexFormat(void *obj, const char *index, const char *data);
+   static bool _setNormalTexSize(void *obj, const char *index, const char *data);
+   static bool _setNormalTexFormat(void *obj, const char *index, const char *data);
+   static bool _setOrmTexSize(void *obj, const char *index, const char *data);
+   static bool _setOrmTexFormat(void *obj, const char *index, const char *data);
    static bool _setLightMapSize( void *obj, const char *index, const char *data );
 
 public:

+ 71 - 12
Engine/source/terrain/terrRender.cpp

@@ -140,33 +140,92 @@ void TerrainBlock::_updateMaterials()
          ormTexArray[i] = TEXMGR->createTexture(mat->getORMConfigMap(), profile);
    }
 
-   mDetailTextureArray = NULL;
-   mMacroTextureArray = NULL;
-   mNormalTextureArray = NULL;
-   mOrmTextureArray = NULL;
+   if (mDetailTextureArray.isNull())
+   {
+      mDetailTextureArray = GFX->createTextureArray();
+   }
+
+   if (mMacroTextureArray.isNull())
+   {
+      mMacroTextureArray = GFX->createTextureArray();
+   }
+
+   if (mNormalTextureArray.isNull())
+   {
+      mNormalTextureArray = GFX->createTextureArray();
+   }
 
+   if (mOrmTextureArray.isNull())
+   {
+      mOrmTextureArray = GFX->createTextureArray();
+   }
 
-   mDetailTextureArray = GFX->createTextureArray();
-   mMacroTextureArray = GFX->createTextureArray();
-   mNormalTextureArray = GFX->createTextureArray();
-   mOrmTextureArray = GFX->createTextureArray();
+   U32 detailTexArraySize = detailTexArray.size();
+   U32 macroTexArraySize = macroTexArray.size();
+   U32 normalTexArraySize = normalTexArray.size();
+   U32 ormTexArraySize = ormTexArray.size();
+#ifdef TORQUE_TOOLS
+   // For performance improvement when adding terrain layers, we always allocate at least 32 textures to the arrays in tool builds
+   detailTexArraySize = mMax(32, detailTexArraySize);
+   macroTexArraySize = mMax(32, macroTexArraySize);
+   normalTexArraySize = mMax(32, normalTexArraySize);
+   ormTexArraySize = mMax(32, ormTexArraySize);
+#endif
+
+   // Format has been explicitly set
+   if (mDetailTexSize != 0)
+   {
+      GFXFormat format = GFXFormatR8G8B8A8;
+      if (mDetailTexFormat < GFXFormat_COUNT)
+      {
+         format = mDetailTexFormat;
+      }
+      mDetailTextureArray->set(mDetailTexSize, mDetailTexSize, detailTexArraySize, format);
+   }
+   if (mMacroTexSize != 0)
+   {
+      GFXFormat format = GFXFormatR8G8B8A8;
+      if (mMacroTexFormat < GFXFormat_COUNT)
+      {
+         format = mMacroTexFormat;
+      }
+      mMacroTextureArray->set(mMacroTexSize, mMacroTexSize, macroTexArraySize, format);
+   }
+   if (mNormalTexSize != 0)
+   {
+      GFXFormat format = GFXFormatR8G8B8A8;
+      if (mNormalTexFormat < GFXFormat_COUNT)
+      {
+         format = mNormalTexFormat;
+      }
+      mNormalTextureArray->set(mNormalTexSize, mNormalTexSize, normalTexArraySize, format);
+   }
+   if (mOrmTexSize != 0)
+   {
+      GFXFormat format = GFXFormatR8G8B8A8;
+      if (mOrmTexFormat < GFXFormat_COUNT)
+      {
+         format = mOrmTexFormat;
+      }
+      mOrmTextureArray->set(mOrmTexSize, mOrmTexSize, ormTexArraySize, format);
+   }
 
-   if(!mDetailTextureArray->fromTextureArray(detailTexArray))
+   if (!mDetailTextureArray->fromTextureArray(detailTexArray, detailTexArraySize))
    {
       Con::errorf("TerrainBlock::_updateMaterials - an issue with the diffuse terrain materials was detected. Please ensure they are all of the same size and format!");
    }
 
-   if(!mMacroTextureArray->fromTextureArray(macroTexArray))
+   if (!mMacroTextureArray->fromTextureArray(macroTexArray, macroTexArraySize))
    {
       Con::errorf("TerrainBlock::_updateMaterials - an issue with the detail terrain materials was detected. Please ensure they are all of the same size and format!");
    }
 
-   if(!mNormalTextureArray->fromTextureArray(normalTexArray))
+   if (!mNormalTextureArray->fromTextureArray(normalTexArray, normalTexArraySize))
    {
       Con::errorf("TerrainBlock::_updateMaterials - an issue with the normal terrain materials was detected. Please ensure they are all of the same size and format!");
    }
 
-   if(!mOrmTextureArray->fromTextureArray(ormTexArray))
+   if (!mOrmTextureArray->fromTextureArray(ormTexArray, ormTexArraySize))
    {
       Con::errorf("TerrainBlock::_updateMaterials - an issue with the orm terrain materials was detected. Please ensure they are all of the same size and format!");
    }