diff --git a/Engine/source/gfx/gfxTextureArray.cpp b/Engine/source/gfx/gfxTextureArray.cpp index 0a1164c7a..099d54635 100644 --- a/Engine/source/gfx/gfxTextureArray.cpp +++ b/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(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& textureArray) +bool GFXTextureArray::fromTextureArray(const Vector& 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) + if (texObj.isValid()) { - found = true; - mFormat = texObj.getFormat(); - mWidth = texObj.getWidth(); - mHeight = texObj.getHeight(); - mMipLevels = texObj->getMipLevels(); - } + 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; + 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; + + + //--------------------------------------------------------------------------------------- + // 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); } - - // 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); - //--------------------------------------------------------------------------------------- @@ -64,7 +100,7 @@ bool GFXTextureArray::fromTextureArray(const Vector& 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()) { diff --git a/Engine/source/gfx/gfxTextureArray.h b/Engine/source/gfx/gfxTextureArray.h index 7b96009d0..7f8b144a1 100644 --- a/Engine/source/gfx/gfxTextureArray.h +++ b/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 &textureArray); + virtual void set(U32 width, U32 height, U32 size, GFXFormat format, U32 mipLevels = 0); + virtual bool fromTextureArray(const Vector &textureArray, U32 capacity = 0); virtual void setTexture(const GFXTexHandle &texture, U32 slot); virtual void setToTexUnit(U32 tuNum) = 0; diff --git a/Engine/source/gfx/gfxTextureManager.cpp b/Engine/source/gfx/gfxTextureManager.cpp index 53c252d07..8b5a2c9e4 100644 --- a/Engine/source/gfx/gfxTextureManager.cpp +++ b/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; } diff --git a/Engine/source/gfx/gfxTextureManager.h b/Engine/source/gfx/gfxTextureManager.h index b6eb658f2..5e4d7a070 100644 --- a/Engine/source/gfx/gfxTextureManager.h +++ b/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); diff --git a/Engine/source/terrain/terrData.cpp b/Engine/source/terrain/terrData.cpp index 3d035af62..8be5b7990 100644 --- a/Engine/source/terrain/terrData.cpp +++ b/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(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(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(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(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(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(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(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(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(mDetailTexFormat) ); + stream->write( mMacroTexSize ); + stream->write( static_cast(mMacroTexFormat) ); + stream->write( mNormalTexSize ); + stream->write( static_cast(mNormalTexFormat) ); + stream->write( mOrmTexSize ); + stream->write( static_cast(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(detailTexFormat); + updateMaterials = true; + } + + U32 macroTexSize; + stream->read(¯oTexSize); + if (mMacroTexSize != macroTexSize) + { + mMacroTexSize = macroTexSize; + updateMaterials = true; + } + S32 macroTexFormat; + stream->read(¯oTexFormat); + if (mMacroTexFormat != macroTexFormat) + { + mMacroTexFormat = static_cast(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(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(ormTexFormat); + updateMaterials = true; + } + + if (updateMaterials && isProperlyAdded()) + { + _updateMaterials(); + } } if ( stream->readFlag() && isProperlyAdded() ) // HeightMapChangeMask diff --git a/Engine/source/terrain/terrData.h b/Engine/source/terrain/terrData.h index cfef5c29d..3df260b7b 100644 --- a/Engine/source/terrain/terrData.h +++ b/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: diff --git a/Engine/source/terrain/terrRender.cpp b/Engine/source/terrain/terrRender.cpp index 745a06219..4d1524009 100644 --- a/Engine/source/terrain/terrRender.cpp +++ b/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(); + } - mDetailTextureArray = GFX->createTextureArray(); - mMacroTextureArray = GFX->createTextureArray(); - mNormalTextureArray = GFX->createTextureArray(); - mOrmTextureArray = GFX->createTextureArray(); + if (mNormalTextureArray.isNull()) + { + mNormalTextureArray = GFX->createTextureArray(); + } - if(!mDetailTextureArray->fromTextureArray(detailTexArray)) + if (mOrmTextureArray.isNull()) + { + 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, 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!"); }