From eca0820134376a23fce3458598ea0eef9300ccd7 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 21 Dec 2024 11:16:55 +0000 Subject: [PATCH 01/47] init commit start of attempt 3 --- Engine/source/T3D/assets/ImageAsset.cpp | 391 +++++++++++------- Engine/source/T3D/assets/ImageAsset.h | 163 +++++--- Engine/source/T3D/assets/LevelAsset.cpp | 2 +- Engine/source/T3D/assets/assetImporter.cpp | 6 +- Engine/source/afx/ce/afxZodiac.cpp | 5 - .../gui/buttons/guiBitmapButtonCtrl.cpp | 10 +- Engine/source/gui/core/guiTypes.cpp | 4 +- Engine/source/gui/core/guiTypes.h | 12 +- .../source/materials/materialDefinition.cpp | 2 +- Engine/source/math/mMathFn.h | 2 + 10 files changed, 374 insertions(+), 223 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 162626b84..a13d8c422 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -106,6 +106,56 @@ ConsoleSetType(TypeImageAssetId) // Warn. Con::warnf("(TypeImageAssetId) - Cannot set multiple args to a single asset."); } + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// REFACTOR +//----------------------------------------------------------------------------- + +IMPLEMENT_STRUCT(AssetPtr, AssetPtrImageAsset,, "") +END_IMPLEMENT_STRUCT + +ConsoleType(ImageAssetPtr, TypeImageAssetPtrRefactor, AssetPtr, "") + + +ConsoleGetType(TypeImageAssetPtrRefactor) +{ + // Fetch asset Id. + return (*((AssetPtr*)dptr)).getAssetId(); +} + +ConsoleSetType(TypeImageAssetPtrRefactor) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + const char* pFieldValue = argv[0]; + + // Fetch asset pointer. + AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); + + // Is the asset pointer the correct type? + if (pAssetPtr == NULL) + { + // No, so fail. + Con::warnf("(TypeImageAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); + + return; + } + + // Warn. + Con::warnf("(TypeImageAssetPtr) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- +// REFACTOR END //----------------------------------------------------------------------------- ImplementEnumType(ImageAssetType, @@ -131,14 +181,6 @@ const String ImageAsset::mErrCodeStrings[] = "UnKnown" }; //----------------------------------------------------------------------------- -ImageAsset::ImageAsset() : AssetBase(), mIsValidImage(false), mUseMips(true), mIsHDRImage(false), mImageType(Albedo) -{ - mImageFileName = StringTable->EmptyString(); - mImagePath = StringTable->EmptyString(); - mLoadedState = AssetErrCode::NotLoaded; - mChangeSignal.notify(this, &ImageAsset::onAssetRefresh); -} - //----------------------------------------------------------------------------- ImageAsset::~ImageAsset() @@ -164,17 +206,28 @@ void ImageAsset::initPersistFields() // Call parent. Parent::initPersistFields(); - addProtectedField("imageFile", TypeAssetLooseFilePath, Offset(mImageFileName, ImageAsset), - &setImageFileName, &getImageFileName, "Path to the image file."); + addProtectedField("imageFile", TypeAssetLooseFilePath, Offset(mImageFile, ImageAsset), &setImageFile, &getImageFile, &writeImageFile, "Path to the image file."); - addField("useMips", TypeBool, Offset(mUseMips, ImageAsset), "Should the image use mips? (Currently unused)."); - addField("isHDRImage", TypeBool, Offset(mIsHDRImage, ImageAsset), "Is the image in an HDR format? (Currently unused)"); + addProtectedField("useMips", TypeBool, Offset(mUseMips, ImageAsset), &setGenMips, &defaultProtectedGetFn, &writeGenMips, "Generate mip maps?"); + addProtectedField("isHDRImage", TypeBool, Offset(mIsHDRImage, ImageAsset), &setTextureHDR, &defaultProtectedGetFn, &writeTextureHDR, "HDR Image?"); addField("imageType", TypeImageAssetType, Offset(mImageType, ImageAsset), "What the main use-case for the image is for."); } +bool ImageAsset::onAdd() +{ + // Call Parent. + if (!Parent::onAdd()) + return false; + + return true; +} + +void ImageAsset::onRemove() +{ + // Call Parent. + Parent::onRemove(); +} -//------------------------------------------------------------------------------ -//Utility function to 'fill out' bindings and resources with a matching asset if one exists U32 ImageAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr* imageAsset) { AssetQuery query; @@ -262,168 +315,162 @@ U32 ImageAsset::getAssetById(StringTableEntry assetId, AssetPtr* ima } } +void ImageAsset::initializeAsset(void) +{ + // Call parent. + Parent::initializeAsset(); + + // Ensure the image-file is expanded. + mImageFile = expandAssetFilePath(mImageFile); +} + +void ImageAsset::onAssetRefresh(void) +{ + // Ignore if not yet added to the sim. + if (!isProperlyAdded()) + return; + + // Call parent. + Parent::onAssetRefresh(); + + //mLoadedState = NotLoaded; +} + //------------------------------------------------------------------------------ + void ImageAsset::copyTo(SimObject* object) { // Call to parent. Parent::copyTo(object); + + ImageAsset* pAsset = static_cast(object); + + // Sanity! + AssertFatal(pAsset != NULL, "ImageAsset::copyTo() - Object is not the correct type."); + + pAsset->setImageFile(getImageFile()); + pAsset->setGenMips(getGenMips()); + pAsset->setTextureHDR(getTextureHDR()); +} + +void ImageAsset::setImageFile(StringTableEntry pImageFile) +{ + // Sanity! + AssertFatal(pImageFile != NULL, "Cannot use a NULL image file."); + + pImageFile = StringTable->insert(pImageFile); + + if (pImageFile == mImageFile) + return; + + // if we previously loaded, remove the listener for the file. + if (mLoadedState == Ok) + Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); + + mImageFile = getOwned() ? expandAssetFilePath(pImageFile) : StringTable->insert(pImageFile); + + refreshAsset(); +} + +void ImageAsset::setGenMips(const bool pGenMips) +{ + if (pGenMips == mUseMips) + return; + + mUseMips = pGenMips; + + refreshAsset(); +} + + +void ImageAsset::setTextureHDR(const bool pIsHDR) +{ + if (pIsHDR == mIsHDRImage) + return; + + mIsHDRImage = pIsHDR; + + refreshAsset(); } 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); - mLoadedState = BadFileReference; - return mLoadedState; - } + if (mLoadedState == Ok) + return mLoadedState; - mLoadedState = Ok; - mIsValidImage = true; + if (!Torque::FS::IsFile(mImageFile)) + { + Con::errorf("ImageAsset::initializeAsset: Attempted to load file %s but it was not valid!", mImageFile); + mLoadedState = BadFileReference; return mLoadedState; } - mLoadedState = BadFileReference; + else + { + Torque::FS::AddChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); + mLoadedState = Ok; + } - mIsValidImage = false; return mLoadedState; } -void ImageAsset::initializeAsset() -{ - ResourceManager::get().getChangedSignal().notify(this, &ImageAsset::_onResourceChanged); - - if (mImageFileName[0] != '$' && mImageFileName[0] != '#') - { - mImagePath = getOwned() ? expandAssetFilePath(mImageFileName) : mImagePath; - } - else - { - mImagePath = mImageFileName; - } -} - -void ImageAsset::onAssetRefresh() -{ - 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. - while (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end() && assetDependenciesItr->key == mpAssetDefinition->mAssetId) - { - StringTableEntry assetId = assetDependenciesItr->value; - AssetBase* dependent = AssetDatabase.acquireAsset(assetId); - dependent->refreshAsset(); - } -} - -void ImageAsset::_onResourceChanged(const Torque::Path& path) -{ - if (path != Torque::Path(mImagePath)) - return; - - refreshAsset(); -} - -void ImageAsset::setImageFileName(const char* pScriptFile) -{ - // Sanity! - AssertFatal(pScriptFile != NULL, "Cannot use a NULL image file."); - - // Update. - mImageFileName = StringTable->insert(pScriptFile, true); - - // Refresh the asset. - refreshAsset(); -} - GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) { load(); - if (mResourceMap.contains(requestedProfile)) + + if (mLoadedState == Ok) { - mLoadedState = Ok; - return mResourceMap.find(requestedProfile)->value; - } - else - { - // this is a target. - if (mImageFileName[0] == '$' || mImageFileName[0] == '#') + if (mResourceMap.contains(requestedProfile)) { - mLoadedState = Ok; - 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(); - } + return mResourceMap.find(requestedProfile)->value; } 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); + GFXTexHandle newTex; + newTex.set(mImageFile, requestedProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); if (newTex) { + mLoadedState = AssetErrCode::Ok; mResourceMap.insert(requestedProfile, newTex); - mLoadedState = Ok; return newTex; } - else - mLoadedState = BadFileReference; } } + mLoadedState = AssetErrCode::Failed; + return nullptr; } -const char* ImageAsset::getImageInfo() +void ImageAsset::generateTexture(void) { - if (mIsValidImage) + // implement some defaults, eventually SRGB should be optional. + U32 flags = GFXTextureProfile::Static | GFXTextureProfile::SRGB; + + // dont want mips? + if (!mUseMips) { - static const U32 bufSize = 2048; - char* returnBuffer = Con::getReturnBuffer(bufSize); - - GFXTexHandle newTex = TEXMGR->createTexture(mImagePath, &GFXStaticTextureSRGBProfile); - if (newTex) - { - dSprintf(returnBuffer, bufSize, "%s %d %d %d", GFXStringTextureFormat[newTex->getFormat()], newTex->getHeight(), newTex->getWidth(), newTex->getDepth()); - newTex = nullptr; - } - else - { - dSprintf(returnBuffer, bufSize, "ImageAsset::getImageInfo() - Failed to get image info for %s", getAssetId()); - } - - return returnBuffer; + flags |= GFXTextureProfile::NoMipmap; } - return ""; + GFXTextureProfile::Types type = GFXTextureProfile::Types::DiffuseMap; + + if (mImageType == ImageTypes::Normal) { + type = GFXTextureProfile::Types::NormalMap; + } + + GFXTextureProfile* genProfile = new GFXTextureProfile("ImageAssetGennedProfile", type, flags); + + mTextureHandle.set(mImageFile, genProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + mResourceMap.insert(genProfile, mTextureHandle); + + if (mTextureHandle.isValid()) + mLoadedState = AssetErrCode::Ok; + else + mLoadedState = AssetErrCode::Failed; + + ResourceManager::get().getChangedSignal().notify(this, &ImageAsset::_onResourceChanged); } const char* ImageAsset::getImageTypeNameFromType(ImageAsset::ImageTypes type) @@ -452,7 +499,7 @@ const char* ImageAsset::getImageTypeNameFromType(ImageAsset::ImageTypes type) return _names[type]; } -ImageAsset::ImageTypes ImageAsset::getImageTypeFromName(const char* name) +ImageAsset::ImageTypes ImageAsset::getImageTypeFromName(StringTableEntry name) { if (dStrIsEmpty(name)) { @@ -475,11 +522,69 @@ ImageAsset::ImageTypes ImageAsset::getImageTypeFromName(const char* name) return (ImageTypes)ret; } -DefineEngineMethod(ImageAsset, getImagePath, const char*, (), , +void ImageAsset::_onFileChanged(const Torque::Path& path) +{ + if (path != Torque::Path(mImageFile)) + return; + + refreshAsset(); +} + +void ImageAsset::_onResourceChanged(const Torque::Path& path) +{ + if (path != Torque::Path(mImageFile)) + return; + + refreshAsset(); +} + +void ImageAsset::onTamlPreWrite(void) +{ + // Call parent. + Parent::onTamlPreWrite(); + + // Ensure the image-file is collapsed. + mImageFile = getOwned() ? collapseAssetFilePath(mImageFile) : mImageFile; +} + +void ImageAsset::onTamlPostWrite(void) +{ + // Call parent. + Parent::onTamlPostWrite(); + + // Ensure the image-file is expanded. + mImageFile = getOwned() ? expandAssetFilePath(mImageFile) : mImageFile; +} + +const char* ImageAsset::getImageInfo() +{ + if (isAssetValid()) + { + static const U32 bufSize = 2048; + char* returnBuffer = Con::getReturnBuffer(bufSize); + + GFXTexHandle newTex = TEXMGR->createTexture(mImageFile, &GFXStaticTextureSRGBProfile); + if (newTex) + { + dSprintf(returnBuffer, bufSize, "%s %d %d %d", GFXStringTextureFormat[newTex->getFormat()], newTex->getHeight(), newTex->getWidth(), newTex->getDepth()); + newTex = nullptr; + } + else + { + dSprintf(returnBuffer, bufSize, "ImageAsset::getImageInfo() - Failed to get image info for %s", getAssetId()); + } + + return returnBuffer; + } + + return ""; +} + +DefineEngineMethod(ImageAsset, getImageFile, const char*, (), , "Gets the image filepath of this asset.\n" "@return File path of the image file.") { - return object->getImagePath(); + return object->getImageFile(); } DefineEngineMethod(ImageAsset, getImageInfo, const char*, (), , @@ -496,7 +601,7 @@ DefineEngineStaticMethod(ImageAsset, getAssetIdByFilename, const char*, (const c { return ImageAsset::getAssetIdByFilename(StringTable->insert(filePath)); } - +#endif //----------------------------------------------------------------------------- // GuiInspectorTypeAssetId //----------------------------------------------------------------------------- @@ -652,7 +757,7 @@ bool GuiInspectorTypeImageAssetPtr::renderTooltip(const Point2I& hoverPos, const if (imgAsset == NULL || assetState == ImageAsset::Failed) return false; - StringTableEntry filename = imgAsset->getImagePath(); + StringTableEntry filename = imgAsset->getImageFile(); if (!filename || !filename[0]) return false; @@ -665,7 +770,7 @@ bool GuiInspectorTypeImageAssetPtr::renderTooltip(const Point2I& hoverPos, const if (AssetDatabase.isDeclaredAsset(previewFilename)) { ImageAsset* previewAsset = AssetDatabase.acquireAsset(previewFilename); - previewFilename = previewAsset->getImagePath(); + previewFilename = previewAsset->getImageFile(); } } @@ -802,5 +907,3 @@ void GuiInspectorTypeImageAssetId::consoleInit() ConsoleBaseType::getType(TypeImageAssetId)->setInspectorFieldType("GuiInspectorTypeImageAssetId"); } - -#endif diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 027dfbac1..75ea87803 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -79,6 +79,39 @@ public: ImageTypeCount = 11 }; + class Frame + { + public: + Frame(const S32 pixelOffsetX, const S32 pixelOffsetY, + const U32 pixelWidth, const U32 pixelHeight, + const F32 texelWidthScale, const F32 texelHeightScale, + StringTableEntry inRegionName = StringTable->EmptyString()) + : regionName(inRegionName) + { + pixelOffset.set(pixelOffsetY, pixelOffsetY); + pixelSize.set(pixelWidth, pixelHeight); + + texelLower.set(pixelOffsetX * texelWidthScale, pixelOffsetY * texelHeightScale); + texelSize.set(pixelWidth * texelWidthScale, pixelHeight * texelHeightScale); + texelUpper.set(texelLower.x + texelSize.x, texelLower.y + texelSize.y); + } + + void setFlip(bool flipX, bool flipY) + { + if (flipX) mSwap(texelLower.x, texelUpper.x); + if (flipY) mSwap(texelLower.y, texelUpper.y); + } + + Point2I pixelOffset; + Point2I pixelSize; + + Point2F texelLower; + Point2F texelUpper; + Point2F texelSize; + + StringTableEntry regionName; + }; + static StringTableEntry smNoImageAssetFallback; enum ImageAssetErrCode @@ -96,26 +129,16 @@ public: if (errCode > ImageAssetErrCode::Extended) return "undefined error"; return mErrCodeStrings[errCode - Parent::Extended]; }; +private: -protected: - StringTableEntry mImageFileName; - StringTableEntry mImagePath; - NamedTexTargetRef mNamedTarget; - - bool mIsValidImage; - bool mUseMips; - bool mIsHDRImage; - - ImageTypes mImageType; - + StringTableEntry mImageFile; + bool mUseMips; + bool mIsHDRImage; + GFXTexHandle mTextureHandle; + ImageTypes mImageType; HashMap mResourceMap; - typedef Signal ImageAssetChanged; - ImageAssetChanged mChangeSignal; - - typedef Signal ImageAssetArrayChanged; - ImageAssetArrayChanged mChangeArraySignal; - + void generateTexture(void); public: ImageAsset(); virtual ~ImageAsset(); @@ -125,6 +148,10 @@ public: /// Engine. static void initPersistFields(); + + /// Sim + bool onAdd() override; + void onRemove() override; void copyTo(SimObject* object) override; /// Declare Console Object. @@ -132,44 +159,75 @@ public: void _onResourceChanged(const Torque::Path& path); - ImageAssetChanged& getChangedSignal() { return mChangeSignal; } - ImageAssetArrayChanged& getChangedArraySignal() { return mChangeArraySignal; } + // asset Base load + U32 load() override; - void setImageFileName(StringTableEntry pScriptFile); - inline StringTableEntry getImageFileName(void) const { return mImageFileName; }; + void setImageFile(StringTableEntry pImageFile); + inline StringTableEntry getImageFile(void) const { return mImageFile; }; - inline StringTableEntry getImagePath(void) const { return mImagePath; }; + void setGenMips(const bool pGenMips); + inline bool getGenMips(void) const { return mUseMips; }; - bool isValid() { return mIsValidImage; } + void setTextureHDR(const bool pIsHDR); + inline bool getTextureHDR(void) const { return mIsHDRImage; }; - GFXTexHandle getTexture(GFXTextureProfile* requestedProfile); - - StringTableEntry getImageInfo(); + inline GFXTexHandle& getTexture(void) { load(); generateTexture(); return mTextureHandle; } + GFXTexHandle getTexture(GFXTextureProfile* requestedProfile); static StringTableEntry getImageTypeNameFromType(ImageTypes type); - static ImageTypes getImageTypeFromName(StringTableEntry name); + static ImageTypes getImageTypeFromName(StringTableEntry name); - void setImageType(ImageTypes type) { mImageType = type; } - ImageTypes getImageType() { return mImageType; } + void setImageType(ImageTypes type) { mImageType = type; } + ImageTypes getImageType() { return mImageType; } + + inline U32 getTextureWidth(void) const { return mTextureHandle->getWidth(); } + inline U32 getTextureHeight(void) const { return mTextureHandle->getHeight(); } + inline U32 getTextureDepth(void) const { return mTextureHandle->getDepth(); } + + inline U32 getTextureBitmapWidth(void) const { return mTextureHandle->getBitmapWidth(); } + inline U32 getTextureBitmapHeight(void) const { return mTextureHandle->getBitmapHeight(); } + inline U32 getTextureBitmapDepth(void) const { return mTextureHandle->getBitmapDepth(); } + bool isAssetValid(void) const override { return !mTextureHandle.isNull(); } static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* imageAsset); static StringTableEntry getAssetIdByFilename(StringTableEntry fileName); static U32 getAssetById(StringTableEntry assetId, AssetPtr* imageAsset); static U32 getAssetById(String assetId, AssetPtr* imageAsset) { return getAssetById(assetId.c_str(), imageAsset); }; - U32 load() override; + + const char* getImageInfo(); protected: - void initializeAsset(void) override; - void onAssetRefresh(void) override; + // Asset Base callback + void initializeAsset(void) override; + void onAssetRefresh(void) override; + void _onFileChanged(const Torque::Path& path); - static bool setImageFileName(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setImageFileName(data); return false; } - static StringTableEntry getImageFileName(void* obj, StringTableEntry data) { return static_cast(obj)->getImageFileName(); } + /// Taml callbacks. + void onTamlPreWrite(void) override; + void onTamlPostWrite(void) override; + +protected: + // Texture file + static bool setImageFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setImageFile(data); return false; } + static const char* getImageFile(void* obj, StringTableEntry data) { return static_cast(obj)->getImageFile(); } + static bool writeImageFile(void* obj, StringTableEntry pFieldName) { return static_cast(obj)->getImageFile() != StringTable->EmptyString(); } + + // Gen mips? + static bool setGenMips(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setGenMips(dAtob(data)); return false; } + static bool writeGenMips(void* obj, StringTableEntry pFieldName) { return static_cast(obj)->getGenMips() == true; } + + // Texture Is Hdr? + static bool setTextureHDR(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setTextureHDR(dAtob(data)); return false; } + static bool writeTextureHDR(void* obj, StringTableEntry pFieldName) { return static_cast(obj)->getTextureHDR() == true; } }; DefineConsoleType(TypeImageAssetPtr, ImageAsset) DefineConsoleType(TypeImageAssetId, String) +DECLARE_STRUCT(AssetPtr) +DefineConsoleType(TypeImageAssetPtrRefactor, AssetPtr ) + typedef ImageAsset::ImageTypes ImageAssetType; DefineEnumType(ImageAssetType); @@ -196,10 +254,6 @@ public: \ {\ if(m##name##AssetId != _in || m##name##Name != _in)\ {\ - if (m##name##Asset.notNull())\ - {\ - m##name##Asset->getChangedSignal().remove(this, &className::changeFunc);\ - }\ if (_in == NULL || _in == StringTable->EmptyString())\ {\ m##name##Name = StringTable->EmptyString();\ @@ -251,10 +305,6 @@ public: \ }\ if (get##name() != StringTable->EmptyString() && m##name##Name != StringTable->insert("texhandle"))\ {\ - if (m##name##Asset.notNull())\ - {\ - m##name##Asset->getChangedSignal().notify(this, &className::changeFunc);\ - }\ \ if (get##name()[0] != '$' && get##name()[0] != '#') {\ m##name.set(get##name(), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\ @@ -285,11 +335,8 @@ public: \ \ const StringTableEntry get##name() const\ {\ - if (m##name##Asset && (m##name##Asset->getImageFileName() != StringTable->EmptyString()))\ - 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());\ + if (m##name##Asset && (m##name##Asset->getImageFile() != StringTable->EmptyString()))\ + return Platform::makeRelativePathName(m##name##Asset->getImageFile(), Platform::getMainDotCsDir());\ else if (m##name##AssetId != StringTable->EmptyString())\ return m##name##AssetId;\ else if (m##name##Name != StringTable->EmptyString())\ @@ -435,11 +482,8 @@ public: \ \ const StringTableEntry get##name(const U32& index) const\ {\ - if (m##name##Asset[index] && (m##name##Asset[index]->getImageFileName() != StringTable->EmptyString()))\ - 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());\ + if (m##name##Asset[index] && (m##name##Asset[index]->getImageFile() != StringTable->EmptyString()))\ + return Platform::makeRelativePathName(m##name##Asset[index]->getImageFile(), Platform::getMainDotCsDir());\ else if (m##name##AssetId[index] != StringTable->EmptyString())\ return m##name##AssetId[index];\ else if (m##name##Name[index] != StringTable->EmptyString())\ @@ -542,4 +586,19 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ #pragma endregion +#pragma region Refactor Asset Macros +#define DECLARE_IMAGEASSET_REFACTOR(className, name, profile) \ +private: \ + AssetPtr m##name##Asset; \ +public: \ + void _set##name(StringTableEntry _in); \ + inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ + GFXTexHandle get##name() { return m##name##Asset.notNull() ? m##name##Asset->getTexture(&profile) : NULL; } \ + AssetPtr get##name##Asset(void) { return m##name##Asset; } \ + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} + +#define INITPERSISTFIELD_IMAGEASSET_REFACTOR(name, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); + +#pragma endregion diff --git a/Engine/source/T3D/assets/LevelAsset.cpp b/Engine/source/T3D/assets/LevelAsset.cpp index 98bb2cc5c..1bfee7394 100644 --- a/Engine/source/T3D/assets/LevelAsset.cpp +++ b/Engine/source/T3D/assets/LevelAsset.cpp @@ -230,7 +230,7 @@ StringTableEntry LevelAsset::getPreviewImagePath(void) const { if (mPreviewImageAsset.notNull() && mPreviewImageAsset->isAssetValid()) { - return mPreviewImageAsset->getImagePath(); + return mPreviewImageAsset->getImageFile(); } return StringTable->EmptyString(); diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 58d956ef5..3f0e514df 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -1877,7 +1877,7 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem) { //got a match! ImageAsset* foundImageAsset = AssetDatabase.acquireAsset(testAssetId.c_str()); - imagePath = foundImageAsset->getImagePath(); + imagePath = foundImageAsset->getImageFile(); AssetImportObject* newImageAssetObj = addImportingAsset("ImageAsset", imagePath, assetItem, ""); @@ -1921,7 +1921,7 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem) { //got a match! ImageAsset* foundImageAsset = AssetDatabase.acquireAsset(testAssetId.c_str()); - imagePath = foundImageAsset->getImagePath(); + imagePath = foundImageAsset->getImageFile(); AssetImportObject* newImageAssetObj = addImportingAsset("ImageAsset", imagePath, assetItem, ""); @@ -2834,7 +2834,7 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) #endif newAsset->setAssetName(assetName); - newAsset->setImageFileName(imageFileName.c_str()); + newAsset->setImageFile(imageFileName.c_str()); //If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original //file path for reimporting support later diff --git a/Engine/source/afx/ce/afxZodiac.cpp b/Engine/source/afx/ce/afxZodiac.cpp index 5d9f310ef..383bbcc15 100644 --- a/Engine/source/afx/ce/afxZodiac.cpp +++ b/Engine/source/afx/ce/afxZodiac.cpp @@ -349,11 +349,6 @@ void afxZodiacData::onPerformSubstitutions() { if (getTexture() != StringTable->EmptyString() && mTextureName != StringTable->insert("texhandle")) { - if (mTextureAsset.notNull()) - { - mTextureAsset->getChangedSignal().notify(this, &afxZodiacData::onImageChanged); - } - mTexture.set(getTexture(), mTextureProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); } } diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp index e2ef9d344..9738cc25c 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp @@ -301,7 +301,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) if( mUseModifiers ) baseName += modifiers[ i ]; - mTextures[ i ].mTextureNormal = GFXTexHandle( mBitmapAsset->getImagePath(), &GFXDefaultGUIProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__)); + mTextures[ i ].mTextureNormal = GFXTexHandle( mBitmapAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__)); if( mUseStates ) { @@ -323,7 +323,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureNormalAsset->load(); if (mTextures[i].mTextureNormalAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureNormal = GFXTexHandle(mTextures[i].mTextureNormalAsset->getImagePath(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureNormal = GFXTexHandle(mTextures[i].mTextureNormalAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); break; } } @@ -345,7 +345,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureHilightAsset->load(); if (mTextures[i].mTextureHilightAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureHilight = GFXTexHandle(mTextures[i].mTextureHilightAsset->getImagePath(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureHilight = GFXTexHandle(mTextures[i].mTextureHilightAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); break; } } @@ -369,7 +369,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureDepressedAsset->load(); if (mTextures[i].mTextureDepressedAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureDepressed = GFXTexHandle(mTextures[i].mTextureDepressedAsset->getImagePath(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureDepressed = GFXTexHandle(mTextures[i].mTextureDepressedAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); break; } } @@ -393,7 +393,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureInactiveAsset->load(); if (mTextures[i].mTextureInactiveAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureInactive = GFXTexHandle(mTextures[i].mTextureInactiveAsset->getImagePath(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureInactive = GFXTexHandle(mTextures[i].mTextureInactiveAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); break; } } diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index 528ea5425..5c1e11359 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -203,7 +203,7 @@ bool GuiControlProfile::protectedSetBitmap( void *object, const char *index, con { if (profile->mBitmapAsset.notNull() && profile->getBitmap() != StringTable->insert("texHandle")) { - profile->mBitmap.set(profile->mBitmapAsset->getImagePath(), profile->mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + profile->mBitmap.set(profile->mBitmapAsset->getImageFile(), profile->mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); } //verify the bitmap @@ -648,7 +648,7 @@ void GuiControlProfile::incLoadCount() { if (mBitmapAsset.notNull() && getBitmap() != StringTable->insert("texHandle")) { - mBitmap.set(mBitmapAsset->getImagePath(), mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + mBitmap.set(mBitmapAsset->getImageFile(), mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); } //verify the bitmap diff --git a/Engine/source/gui/core/guiTypes.h b/Engine/source/gui/core/guiTypes.h index a96dd92f1..759b857bc 100644 --- a/Engine/source/gui/core/guiTypes.h +++ b/Engine/source/gui/core/guiTypes.h @@ -475,10 +475,6 @@ public: { if (mBitmapAssetId != _in || mBitmapName != _in) { - if (mBitmapAsset.notNull()) - { - mBitmapAsset->getChangedSignal().remove(this, &GuiControlProfile::onBitmapChanged); - } if (_in == StringTable->EmptyString()) { mBitmapName = StringTable->EmptyString(); @@ -530,10 +526,6 @@ public: } if (getBitmap() != StringTable->EmptyString() && mBitmapName != StringTable->insert("texhandle")) { - if (mBitmapAsset.notNull()) - { - mBitmapAsset->getChangedSignal().notify(this, &GuiControlProfile::onBitmapChanged); - } } else { @@ -551,8 +543,8 @@ public: const StringTableEntry getBitmap() const { - if (mBitmapAsset && (mBitmapAsset->getImageFileName() != StringTable->EmptyString())) - return Platform::makeRelativePathName(mBitmapAsset->getImagePath(), Platform::getMainDotCsDir()); + if (mBitmapAsset && (mBitmapAsset->getImageFile() != StringTable->EmptyString())) + return Platform::makeRelativePathName(mBitmapAsset->getImageFile(), Platform::getMainDotCsDir()); else if (mBitmapAssetId != StringTable->EmptyString()) return mBitmapAssetId; else if (mBitmapName != StringTable->EmptyString()) diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index c9a09bd0d..3084ce2f4 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -674,7 +674,7 @@ void Material::_mapMaterial() } else if (!mDiffuseMapAsset->isNull()) { - mMapTo = mDiffuseMapAsset[0]->getImageFileName(); + mMapTo = mDiffuseMapAsset[0]->getImageFile(); } } } diff --git a/Engine/source/math/mMathFn.h b/Engine/source/math/mMathFn.h index 1c65604a1..9f84b37df 100644 --- a/Engine/source/math/mMathFn.h +++ b/Engine/source/math/mMathFn.h @@ -531,5 +531,7 @@ inline F64 mSquared( F64 n ) return n * n; } +template< typename T > +inline void mSwap(T& a, T& b) { T temp = b; b = a; a = temp; } #endif //_MMATHFN_H_ From 24b374f5459a68aa6c0eaef92ebd8a25dbe61fcd Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 21 Dec 2024 12:23:57 +0000 Subject: [PATCH 02/47] cloud layer example --- Engine/source/T3D/assets/ImageAsset.cpp | 13 ++++++++++++- Engine/source/T3D/assets/ImageAsset.h | 21 ++++++++++++++++++++- Engine/source/environment/cloudLayer.cpp | 23 ++++++++++------------- Engine/source/environment/cloudLayer.h | 6 +++--- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index a13d8c422..a0055df9b 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -181,6 +181,17 @@ const String ImageAsset::mErrCodeStrings[] = "UnKnown" }; //----------------------------------------------------------------------------- + +ImageAsset::ImageAsset() : + mImageFile(StringTable->EmptyString()), + mUseMips(true), + mIsHDRImage(false), + mImageType(Albedo), + mTextureHandle(NULL) +{ + mLoadedState = AssetErrCode::NotLoaded; +} + //----------------------------------------------------------------------------- ImageAsset::~ImageAsset() @@ -618,7 +629,7 @@ void GuiInspectorTypeImageAssetPtr::consoleInit() { Parent::consoleInit(); - ConsoleBaseType::getType(TypeImageAssetPtr)->setInspectorFieldType("GuiInspectorTypeImageAssetPtr"); + ConsoleBaseType::getType(TypeImageAssetPtrRefactor)->setInspectorFieldType("GuiInspectorTypeImageAssetPtr"); } GuiControl* GuiInspectorTypeImageAssetPtr::constructEditControl() diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 75ea87803..b41b4469c 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -592,7 +592,26 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ private: \ AssetPtr m##name##Asset; \ public: \ - void _set##name(StringTableEntry _in); \ + void _set##name(StringTableEntry _in){ \ + if(m##name##Asset.getAssetId() == _in) \ + return; \ + \ + if(!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + } \ + }; \ inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ GFXTexHandle get##name() { return m##name##Asset.notNull() ? m##name##Asset->getTexture(&profile) : NULL; } \ AssetPtr get##name##Asset(void) { return m##name##Asset; } \ diff --git a/Engine/source/environment/cloudLayer.cpp b/Engine/source/environment/cloudLayer.cpp index d6de0c055..ebc503a8c 100644 --- a/Engine/source/environment/cloudLayer.cpp +++ b/Engine/source/environment/cloudLayer.cpp @@ -112,8 +112,6 @@ CloudLayer::CloudLayer() mTexOffset[0] = mTexOffset[1] = mTexOffset[2] = Point2F::Zero; mHeight = 4.0f; - - INIT_ASSET(Texture); } IMPLEMENT_CO_NETOBJECT_V1( CloudLayer ); @@ -131,8 +129,6 @@ bool CloudLayer::onAdd() addToScene(); - LOAD_IMAGEASSET(Texture); - if ( isClientObject() ) { _initBuffers(); @@ -194,8 +190,8 @@ void CloudLayer::initPersistFields() docsURL; addGroup( "CloudLayer" ); - INITPERSISTFIELD_IMAGEASSET(Texture, CloudLayer, "An RGBA texture which should contain normals and opacity (density)."); - + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, CloudLayer, "An RGBA texture which should contain normals and opacity (density).") + addArray( "Textures", TEX_COUNT ); addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT, @@ -243,7 +239,9 @@ U32 CloudLayer::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) { U32 retMask = Parent::packUpdate( conn, mask, stream ); - PACK_ASSET(conn, Texture); + if (stream->writeFlag(mTextureAsset.notNull())) { + NetStringHandle assetIdStr = mTextureAsset.getAssetId(); conn->packNetStringHandleU(stream, assetIdStr); + } for ( U32 i = 0; i < TEX_COUNT; i++ ) { @@ -265,10 +263,9 @@ void CloudLayer::unpackUpdate( NetConnection *conn, BitStream *stream ) { Parent::unpackUpdate( conn, stream ); - UNPACK_ASSET(conn, Texture); - - if(mTextureAssetId != StringTable->EmptyString()) - mTextureAsset = mTextureAssetId; + if (stream->readFlag()) { + mTextureAsset.setAssetId(_getStringTable()->insert(conn->unpackNetStringHandleU(stream).getString())); + } for ( U32 i = 0; i < TEX_COUNT; i++ ) { @@ -334,7 +331,7 @@ void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, Ba { GFXTransformSaver saver; - if (!mTextureAsset || !mTextureAsset->isAssetValid()) + if (!mTextureAsset) return; const Point3F &camPos = state->getCameraPosition(); @@ -385,7 +382,7 @@ void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, Ba mShaderConsts->setSafe( mExposureSC, mExposure ); - GFX->setTexture( mNormalHeightMapSC->getSamplerRegister(), getTextureResource()); + GFX->setTexture( mNormalHeightMapSC->getSamplerRegister(), mTextureAsset->getTexture(&GFXStaticTextureSRGBProfile)); GFX->setVertexBuffer( mVB ); GFX->setPrimitiveBuffer( mPB ); diff --git a/Engine/source/environment/cloudLayer.h b/Engine/source/environment/cloudLayer.h index ba8110c39..675b3b78b 100644 --- a/Engine/source/environment/cloudLayer.h +++ b/Engine/source/environment/cloudLayer.h @@ -61,7 +61,6 @@ class CloudLayer : public SceneObject }; #define TEX_COUNT 3 - public: CloudLayer(); @@ -97,8 +96,9 @@ protected: static U32 smVertCount; static U32 smTriangleCount; - DECLARE_IMAGEASSET(CloudLayer, Texture, onImageChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_NET_SETGET(CloudLayer, Texture, CloudLayerMask); +public: + + DECLARE_IMAGEASSET_REFACTOR(CloudLayer,Texture, GFXStaticTextureSRGBProfile) GFXShaderRef mShader; From fa8110ce8f87367f7a60db6fbb963ee64cfd39e4 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 21 Dec 2024 17:34:16 +0000 Subject: [PATCH 03/47] all DECLARE_IMAGEASSET refactored --- Engine/source/T3D/accumulationVolume.cpp | 17 ++----- Engine/source/T3D/accumulationVolume.h | 5 +- Engine/source/T3D/assets/ImageAsset.cpp | 2 +- Engine/source/T3D/assets/ImageAsset.h | 32 +++++++++++++ Engine/source/T3D/assets/assetMacroHelpers.h | 46 +++++++++++++++++++ Engine/source/T3D/fx/particle.cpp | 34 ++++---------- Engine/source/T3D/fx/particle.h | 8 +--- Engine/source/T3D/fx/particleEmitter.cpp | 6 +-- Engine/source/T3D/fx/precipitation.cpp | 40 +++++----------- Engine/source/T3D/fx/precipitation.h | 9 +--- Engine/source/T3D/gameMode.cpp | 3 +- Engine/source/T3D/gameMode.h | 5 +- Engine/source/T3D/levelInfo.cpp | 33 ++++--------- Engine/source/T3D/levelInfo.h | 8 +--- Engine/source/T3D/lightFlareData.cpp | 12 ++--- Engine/source/T3D/lightFlareData.h | 5 +- .../afx/afxZodiacGroundPlaneRenderer_T3D.cpp | 2 +- .../afx/afxZodiacMeshRoadRenderer_T3D.cpp | 2 +- .../afx/afxZodiacPolysoupRenderer_T3D.cpp | 2 +- .../afx/afxZodiacTerrainRenderer_T3D.cpp | 2 +- Engine/source/afx/ce/afxBillboard.cpp | 9 ++-- Engine/source/afx/ce/afxBillboard.h | 5 +- Engine/source/afx/ce/afxBillboard_T3D.cpp | 2 +- Engine/source/afx/ce/afxZodiac.cpp | 21 +++------ Engine/source/afx/ce/afxZodiac.h | 5 +- Engine/source/afx/ce/afxZodiacMgr.cpp | 4 +- Engine/source/afx/ce/afxZodiacMgr.h | 2 +- Engine/source/afx/ce/afxZodiacPlane.cpp | 10 ++-- Engine/source/afx/ce/afxZodiacPlane.h | 5 +- Engine/source/afx/ce/afxZodiacPlane_T3D.cpp | 2 +- .../source/afx/util/afxParticlePool_T3D.cpp | 6 +-- Engine/source/environment/VolumetricFog.cpp | 34 +++++++------- Engine/source/environment/VolumetricFog.h | 5 +- Engine/source/environment/cloudLayer.h | 2 +- Engine/source/environment/waterObject.cpp | 32 ++++++------- Engine/source/environment/waterObject.h | 13 ++---- Engine/source/terrain/terrCellMaterial.cpp | 16 +++---- Engine/source/terrain/terrMaterial.cpp | 25 ++++------ Engine/source/terrain/terrMaterial.h | 26 +++-------- Engine/source/terrain/terrRender.cpp | 24 +++++----- .../game/tools/gui/profiles.ed.tscript | 19 ++++---- .../tools/riverEditor/riverEditorGui.tscript | 6 +-- .../tools/worldEditor/gui/EditorGui.ed.gui | 2 +- .../worldEditor/gui/objectBuilderGui.ed.gui | 6 +-- 44 files changed, 248 insertions(+), 306 deletions(-) diff --git a/Engine/source/T3D/accumulationVolume.cpp b/Engine/source/T3D/accumulationVolume.cpp index f7f98774d..dfada6d06 100644 --- a/Engine/source/T3D/accumulationVolume.cpp +++ b/Engine/source/T3D/accumulationVolume.cpp @@ -83,24 +83,17 @@ AccumulationVolume::AccumulationVolume() mObjToWorld.identity(); mWorldToObj.identity(); - // Accumulation Texture. - INIT_ASSET(Texture); - resetWorldBox(); } AccumulationVolume::~AccumulationVolume() { - mTexture = nullptr; } void AccumulationVolume::initPersistFields() { docsURL; - addProtectedField("textureAsset", TypeImageAssetId, Offset(mTextureAssetId, AccumulationVolume), - &_setTexture, &defaultProtectedGetFn, "Accumulation texture."); - addProtectedField( "texture", TypeStringFilename, Offset( mTextureName, AccumulationVolume ), - &_setTexture, &defaultProtectedGetFn, "Accumulation texture." ); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, AccumulationVolume, "Accumulation texture.") Parent::initPersistFields(); } @@ -236,7 +229,7 @@ U32 AccumulationVolume::packUpdate( NetConnection *connection, U32 mask, BitStre if (stream->writeFlag(mask & InitialUpdateMask)) { - PACK_ASSET(connection, Texture); + PACK_ASSET_REFACTOR(connection, Texture); } return retMask; @@ -248,7 +241,7 @@ void AccumulationVolume::unpackUpdate( NetConnection *connection, BitStream *str if (stream->readFlag()) { - UNPACK_ASSET(connection, Texture); + UNPACK_ASSET_REFACTOR(connection, Texture); //setTexture(mTextureName); } } @@ -307,7 +300,7 @@ void AccumulationVolume::refreshVolumes() if ( object.isNull() ) continue; if ( volume->containsPoint(object->getPosition()) ) - object->mAccuTex = volume->getTextureResource(); + object->mAccuTex = volume->getTexture(); } } } @@ -341,6 +334,6 @@ void AccumulationVolume::updateObject(SceneObject* object) if ( volume.isNull() ) continue; if ( volume->containsPoint(object->getPosition()) ) - object->mAccuTex = volume->getTextureResource(); + object->mAccuTex = volume->getTexture(); } } diff --git a/Engine/source/T3D/accumulationVolume.h b/Engine/source/T3D/accumulationVolume.h index 66b2c8a31..53c24843c 100644 --- a/Engine/source/T3D/accumulationVolume.h +++ b/Engine/source/T3D/accumulationVolume.h @@ -61,10 +61,7 @@ class AccumulationVolume : public ScenePolyhedralSpace // SceneSpace. void _renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat ) override; - DECLARE_IMAGEASSET(AccumulationVolume, Texture, onTextureChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_NET_SETGET(AccumulationVolume, Texture, -1); - - void onTextureChanged() {} + DECLARE_IMAGEASSET_NET_REFACTOR(AccumulationVolume, Texture, GFXStaticTextureSRGBProfile, -1) public: diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index a0055df9b..b249cdb56 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -591,7 +591,7 @@ const char* ImageAsset::getImageInfo() return ""; } -DefineEngineMethod(ImageAsset, getImageFile, const char*, (), , +DefineEngineMethod(ImageAsset, getImagePath, const char*, (), , "Gets the image filepath of this asset.\n" "@return File path of the image file.") { diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index b41b4469c..894edc58f 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -612,6 +612,38 @@ public: m##name##Asset = _in; \ } \ }; \ + \ + inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ + GFXTexHandle get##name() { return m##name##Asset.notNull() ? m##name##Asset->getTexture(&profile) : NULL; } \ + AssetPtr get##name##Asset(void) { return m##name##Asset; } \ + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} + +#define DECLARE_IMAGEASSET_NET_REFACTOR(className, name, profile, mask) \ +private: \ + AssetPtr m##name##Asset; \ +public: \ + void _set##name(StringTableEntry _in){ \ + if(m##name##Asset.getAssetId() == _in) \ + return; \ + \ + if(!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + } \ + setMaskBits(mask); \ + }; \ + \ inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ GFXTexHandle get##name() { return m##name##Asset.notNull() ? m##name##Asset->getTexture(&profile) : NULL; } \ AssetPtr get##name##Asset(void) { return m##name##Asset; } \ diff --git a/Engine/source/T3D/assets/assetMacroHelpers.h b/Engine/source/T3D/assets/assetMacroHelpers.h index ef37cd7d5..4facaed5d 100644 --- a/Engine/source/T3D/assets/assetMacroHelpers.h +++ b/Engine/source/T3D/assets/assetMacroHelpers.h @@ -53,6 +53,52 @@ if (m##name##AssetId != StringTable->EmptyString())\ m##name##Asset = other.m##name##Asset;\ m##name = other.m##name +// copy constructor refactor +#define CLONE_ASSET_REFACTOR(name) \ + m##name##Asset = other.m##name##Asset;\ + +//network send - datablock refactor +#define PACKDATA_ASSET_REFACTOR(name)\ + if (stream->writeFlag(m##name##Asset.notNull()))\ + {\ + stream->writeString(m##name##Asset.getAssetId());\ + } + +//network recieve - datablock +#define UNPACKDATA_ASSET_REFACTOR(name)\ + if (stream->readFlag())\ + {\ + _set##name(stream->readSTString());\ + } + +//network send - object-instance +#define PACK_ASSET_REFACTOR(netconn, name)\ + if (stream->writeFlag(m##name##Asset.notNull()))\ + {\ + NetStringHandle assetIdStr = m##name##Asset.getAssetId();\ + netconn->packNetStringHandleU(stream, assetIdStr);\ + } + +//network recieve - object-instance +#define UNPACK_ASSET_REFACTOR(netconn, name)\ + if (stream->readFlag())\ + {\ + _set##name(netconn->unpackNetStringHandleU(stream).getString());\ + } + +#define DEF_ASSET_BINDS_REFACTOR(className,name)\ +DefineEngineMethod(className, get##name, StringTableEntry, (), , "get name")\ +{\ + return object->get##name##Asset()->getImageFile(); \ +}\ +DefineEngineMethod(className, get##name##Asset, StringTableEntry, (), , assetText(name, asset reference))\ +{\ + return object->_get##name(); \ +}\ +DefineEngineMethod(className, set##name, void, (const char* assetName), , assetText(name,assignment. first tries asset then flat file.))\ +{\ + object->_set##name(StringTable->insert(assetName));\ +} // addProtectedField acessors #define DECLARE_ASSET_SETGET(className, name)\ static bool _set##name##Data(void* obj, const char* index, const char* data)\ diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index d091133ba..f552af71a 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -122,9 +122,6 @@ ParticleData::ParticleData() animTexFramesString = NULL; // string of animation frame indices animTexUVs = NULL; // array of tile vertex UVs - INIT_ASSET(Texture); - INIT_ASSET(TextureExt); - constrain_pos = false; start_angle = 0.0f; angle_variance = 0.0f; @@ -149,12 +146,7 @@ void ParticleData::initPersistFields() { docsURL; addGroup("Basic"); - addProtectedField("textureName", TYPEID< StringTableEntry >(), Offset(mTextureName, ParticleData), _setTextureData, defaultProtectedGetFn, - "Texture file to use for this particle.", AbstractClassRep::FIELD_HideInInspectors); - addField("animTexName", TYPEID< StringTableEntry >(), Offset(mTextureName, ParticleData), - "@brief Texture file to use for this particle if animateTexture is true.\n\n" - "Deprecated. Use textureName instead.", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_IMAGEASSET(Texture, ParticleData, "Texture to use for this particle."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, ParticleData, "Texture to use for this particle."); addField("useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData), "@brief Controls how particles blend with the scene.\n\n" "If true, particles blend like ParticleBlendStyle NORMAL, if false, " @@ -239,8 +231,7 @@ void ParticleData::initPersistFields() endGroup("Over Time"); addGroup("AFX"); - addProtectedField("textureExtName", TypeFilename, Offset(mTextureExtName, ParticleData), _setTextureExtData, &defaultProtectedGetFn, "", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_IMAGEASSET(TextureExt, ParticleData, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(TextureExt, ParticleData, ""); addField("constrainPos", TypeBool, Offset(constrain_pos, ParticleData)); addField("angle", TypeF32, Offset(start_angle, ParticleData)); addField("angleVariance", TypeF32, Offset(angle_variance, ParticleData)); @@ -305,7 +296,7 @@ void ParticleData::packData(BitStream* stream) stream->writeFloat( times[i], 8); } - PACKDATA_ASSET(Texture); + PACKDATA_ASSET_REFACTOR(Texture); for (i = 0; i < 4; i++) mathWrite(*stream, texCoords[i]); @@ -319,7 +310,7 @@ void ParticleData::packData(BitStream* stream) stream->writeInt(framesPerSec, 8); } - PACKDATA_ASSET(TextureExt); + PACKDATA_ASSET_REFACTOR(TextureExt); stream->writeFlag(constrain_pos); stream->writeFloat(start_angle/360.0f, 11); @@ -390,7 +381,7 @@ void ParticleData::unpackData(BitStream* stream) times[i] = stream->readFloat(8); } - UNPACKDATA_ASSET(Texture); + UNPACKDATA_ASSET_REFACTOR(Texture); for (i = 0; i < 4; i++) mathRead(*stream, &texCoords[i]); @@ -403,7 +394,7 @@ void ParticleData::unpackData(BitStream* stream) framesPerSec = stream->readInt(8); } - UNPACKDATA_ASSET(TextureExt); + UNPACKDATA_ASSET_REFACTOR(TextureExt); constrain_pos = stream->readFlag(); start_angle = 360.0f*stream->readFloat(11); @@ -698,13 +689,6 @@ bool ParticleData::reload(char errorBuffer[256]) { bool error = false; - StringTableEntry particleTex = getTexture(); - - if (!_setTexture(particleTex)) - { - dSprintf(errorBuffer, 256, "Missing particle texture: %s", particleTex); - } - /* numFrames = 0; for( S32 i=0; i animTexFrames; - DECLARE_IMAGEASSET(ParticleData, Texture, onImageChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(ParticleData, Texture); + DECLARE_IMAGEASSET_REFACTOR(ParticleData, Texture, GFXStaticTextureSRGBProfile) static bool protectedSetSizes(void* object, const char* index, const char* data); static bool protectedSetTimes(void* object, const char* index, const char* data); - void onImageChanged() {} - public: ParticleData(); ~ParticleData(); @@ -117,8 +114,7 @@ public: F32 spinBias; bool randomizeSpinDir; public: - DECLARE_IMAGEASSET(ParticleData, TextureExt, onImageChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(ParticleData, TextureExt); + DECLARE_IMAGEASSET_REFACTOR(ParticleData, TextureExt,GFXStaticTextureSRGBProfile) bool constrain_pos; F32 start_angle; diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index a512e893c..5f135345b 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -742,11 +742,11 @@ bool ParticleEmitterData::preload(bool server, String &errorStr) // otherwise, check that all particles refer to the same texture else if (particleDataBlocks.size() > 1) { - StringTableEntry txr_name = particleDataBlocks[0]->getTexture(); + StringTableEntry txr_name = particleDataBlocks[0]->getTextureAsset()->getImageFile(); for (S32 i = 1; i < particleDataBlocks.size(); i++) { // warn if particle textures are inconsistent - if (particleDataBlocks[i]->getTexture() != txr_name) + if (particleDataBlocks[i]->getTextureAsset()->getImageFile() != txr_name) { Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) particles reference different textures.", getName()); break; @@ -1227,7 +1227,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state) if (mDataBlock->textureHandle) ri->diffuseTex = &*(mDataBlock->textureHandle); else - ri->diffuseTex = &*(part_list_head.next->dataBlock->getTextureResource()); + ri->diffuseTex = &*(part_list_head.next->dataBlock->getTexture()); ri->softnessDistance = mDataBlock->softnessDistance; diff --git a/Engine/source/T3D/fx/precipitation.cpp b/Engine/source/T3D/fx/precipitation.cpp index d57ef3bd6..aaeb434e0 100644 --- a/Engine/source/T3D/fx/precipitation.cpp +++ b/Engine/source/T3D/fx/precipitation.cpp @@ -129,12 +129,8 @@ PrecipitationData::PrecipitationData() { INIT_ASSET(Sound); - INIT_ASSET(Drop); - mDropShaderName = StringTable->EmptyString(); - INIT_ASSET(Splash); - mSplashShaderName = StringTable->EmptyString(); mDropsPerSide = 4; @@ -145,14 +141,8 @@ void PrecipitationData::initPersistFields() { docsURL; INITPERSISTFIELD_SOUNDASSET(Sound, PrecipitationData, "Looping SFXProfile effect to play while Precipitation is active."); - - addProtectedField( "dropTexture", TypeFilename, Offset(mDropName, PrecipitationData), &_setDropData, &defaultProtectedGetFn, - "@brief Texture filename for drop particles.\n\n" - "The drop texture can contain several different drop sub-textures " - "arranged in a grid. There must be the same number of rows as columns. A " - "random frame will be chosen for each drop.", AbstractClassRep::FIELD_HideInInspectors ); - INITPERSISTFIELD_IMAGEASSET(Drop, PrecipitationData, "@brief Texture for drop particles.\n\n" + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Drop, PrecipitationData, "@brief Texture for drop particles.\n\n" "The drop texture can contain several different drop sub-textures " "arranged in a grid. There must be the same number of rows as columns. A " "random frame will be chosen for each drop."); @@ -160,13 +150,7 @@ void PrecipitationData::initPersistFields() addField( "dropShader", TypeString, Offset(mDropShaderName, PrecipitationData), "The name of the shader used for raindrops." ); - addProtectedField("splashTexture", TypeFilename, Offset(mSplashName, PrecipitationData), &_setSplashData, &defaultProtectedGetFn, - "@brief Texture filename for splash particles.\n\n" - "The splash texture can contain several different splash sub-textures " - "arranged in a grid. There must be the same number of rows as columns. A " - "random frame will be chosen for each splash.", AbstractClassRep::FIELD_HideInInspectors); - - INITPERSISTFIELD_IMAGEASSET(Splash, PrecipitationData, "@brief Texture for splash particles.\n\n" + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Splash, PrecipitationData, "@brief Texture for splash particles.\n\n" "The splash texture can contain several different splash sub-textures " "arranged in a grid. There must be the same number of rows as columns. A " "random frame will be chosen for each splash."); @@ -206,11 +190,11 @@ void PrecipitationData::packData(BitStream* stream) PACKDATA_ASSET(Sound); - PACKDATA_ASSET(Drop); + PACKDATA_ASSET_REFACTOR(Drop); stream->writeString(mDropShaderName); - PACKDATA_ASSET(Splash); + PACKDATA_ASSET_REFACTOR(Splash); stream->writeString(mSplashShaderName); stream->write(mDropsPerSide); @@ -223,11 +207,11 @@ void PrecipitationData::unpackData(BitStream* stream) UNPACKDATA_ASSET(Sound); - UNPACKDATA_ASSET(Drop); + UNPACKDATA_ASSET_REFACTOR(Drop); mDropShaderName = stream->readSTString(); - UNPACKDATA_ASSET(Splash); + UNPACKDATA_ASSET_REFACTOR(Splash); mSplashShaderName = stream->readSTString(); stream->read(&mDropsPerSide); @@ -632,10 +616,10 @@ void Precipitation::initMaterials() mDropShader = NULL; mSplashShader = NULL; - if(pd->mDrop.isNull()) - Con::warnf("Precipitation::initMaterials - failed to locate texture '%s'!", pd->getDrop()); + if(pd->getDropAsset().isNull()) + Con::warnf("Precipitation::initMaterials - failed to locate texture '%s'!", pd->getDropAsset().getAssetId()); else - mDropHandle = pd->mDrop; + mDropHandle = pd->getDrop(); if ( dStrlen(pd->mDropShaderName) > 0 ) { @@ -655,10 +639,10 @@ void Precipitation::initMaterials() } } - if (pd->mSplash.isNull()) - Con::warnf("Precipitation::initMaterials - failed to locate texture '%s'!", pd->getSplash()); + if (pd->getSplashAsset().isNull()) + Con::warnf("Precipitation::initMaterials - failed to locate texture '%s'!", pd->getSplashAsset().getAssetId()); else - mSplashHandle = pd->mSplash; + mSplashHandle = pd->getSplash(); if ( dStrlen(pd->mSplashShaderName) > 0 ) { diff --git a/Engine/source/T3D/fx/precipitation.h b/Engine/source/T3D/fx/precipitation.h index 25aad8e60..676f7df31 100644 --- a/Engine/source/T3D/fx/precipitation.h +++ b/Engine/source/T3D/fx/precipitation.h @@ -49,13 +49,11 @@ class PrecipitationData : public GameBaseData DECLARE_SOUNDASSET(PrecipitationData, Sound); DECLARE_ASSET_SETGET(PrecipitationData, Sound); - DECLARE_IMAGEASSET(PrecipitationData, Drop, onDropChanged, GFXStaticTextureSRGBProfile); ///< Texture for drop particles - DECLARE_ASSET_SETGET(PrecipitationData, Drop); + DECLARE_IMAGEASSET_REFACTOR(PrecipitationData, Drop, GFXStaticTextureSRGBProfile) ///< Texture for drop particles StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops - DECLARE_IMAGEASSET(PrecipitationData, Splash, onSplashChanged, GFXStaticTextureSRGBProfile); ///< Texture for splash particles - DECLARE_ASSET_SETGET(PrecipitationData, Splash); + DECLARE_IMAGEASSET_REFACTOR(PrecipitationData, Splash, GFXStaticTextureSRGBProfile) ///< Texture for splash particles StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops @@ -68,9 +66,6 @@ class PrecipitationData : public GameBaseData static void initPersistFields(); void packData(BitStream* stream) override; void unpackData(BitStream* stream) override; - - void onDropChanged() {} - void onSplashChanged() {} }; struct Raindrop diff --git a/Engine/source/T3D/gameMode.cpp b/Engine/source/T3D/gameMode.cpp index 32253cca5..b87c51696 100644 --- a/Engine/source/T3D/gameMode.cpp +++ b/Engine/source/T3D/gameMode.cpp @@ -53,7 +53,6 @@ GameMode::GameMode() : mIsActive(false), mIsAlwaysActive(false) { - INIT_ASSET(PreviewImage); } void GameMode::initPersistFields() @@ -63,7 +62,7 @@ void GameMode::initPersistFields() addField("gameModeName", TypeString, Offset(mGameModeName, GameMode), "Human-readable name of the gamemode"); addField("description", TypeString, Offset(mGameModeDesc, GameMode), "Description of the gamemode"); - INITPERSISTFIELD_IMAGEASSET(PreviewImage, GameMode, "Preview Image"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(PreviewImage, GameMode, "Preview Image"); addField("active", TypeBool, Offset(mIsActive, GameMode), "Is the gamemode active"); addField("alwaysActive", TypeBool, Offset(mIsAlwaysActive, GameMode), "Is the gamemode always active"); diff --git a/Engine/source/T3D/gameMode.h b/Engine/source/T3D/gameMode.h index d28deecc0..1efa9602c 100644 --- a/Engine/source/T3D/gameMode.h +++ b/Engine/source/T3D/gameMode.h @@ -21,8 +21,7 @@ private: StringTableEntry mGameModeName; StringTableEntry mGameModeDesc; - DECLARE_IMAGEASSET(GameMode, PreviewImage, previewChange, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(GameMode, PreviewImage); + DECLARE_IMAGEASSET_REFACTOR(GameMode, PreviewImage, GFXStaticTextureSRGBProfile) bool mIsActive; bool mIsAlwaysActive; @@ -45,8 +44,6 @@ public: static void findGameModes(const char* gameModeList, Vector* outGameModes); - void previewChange() {} - DECLARE_CALLBACK(void, onActivated, ()); DECLARE_CALLBACK(void, onDeactivated, ()); DECLARE_CALLBACK(void, onSceneLoaded, ()); diff --git a/Engine/source/T3D/levelInfo.cpp b/Engine/source/T3D/levelInfo.cpp index 74280ffaf..94353a46c 100644 --- a/Engine/source/T3D/levelInfo.cpp +++ b/Engine/source/T3D/levelInfo.cpp @@ -102,8 +102,6 @@ LevelInfo::LevelInfo() mAdvancedLightmapSupport = true; - INIT_ASSET(AccuTexture); - // Register with the light manager activation signal, and we need to do it first // so the advanced light bin manager can be instructed about MRT lightmaps LightManager::smActivateSignal.notify(this, &LevelInfo::_onLMActivate, 0.01f); @@ -114,9 +112,8 @@ LevelInfo::LevelInfo() LevelInfo::~LevelInfo() { LightManager::smActivateSignal.remove(this, &LevelInfo::_onLMActivate); - if (!mAccuTexture.isNull()) + if (!mAccuTextureAsset.isNull()) { - mAccuTexture.free(); gLevelAccuMap.free(); } } @@ -174,7 +171,7 @@ void LevelInfo::initPersistFields() //addField( "advancedLightmapSupport", TypeBool, Offset( mAdvancedLightmapSupport, LevelInfo ), // "Enable expanded support for mixing static and dynamic lighting (more costly)" ); - INITPERSISTFIELD_IMAGEASSET(AccuTexture, LevelInfo, "Accumulation texture."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(AccuTexture, LevelInfo, "Accumulation texture."); endGroup( "Lighting" ); @@ -224,7 +221,7 @@ U32 LevelInfo::packUpdate(NetConnection *conn, U32 mask, BitStream *stream) sfxWrite( stream, mSoundAmbience ); stream->writeInt( mSoundDistanceModel, 1 ); - PACK_ASSET(conn, AccuTexture); + PACK_ASSET_REFACTOR(conn, AccuTexture); return retMask; } @@ -273,8 +270,8 @@ void LevelInfo::unpackUpdate(NetConnection *conn, BitStream *stream) SFX->setDistanceModel( mSoundDistanceModel ); } - UNPACK_ASSET(conn, AccuTexture); - setLevelAccuTexture(getAccuTexture()); + UNPACK_ASSET_REFACTOR(conn, AccuTexture); + setLevelAccuTexture(); } //----------------------------------------------------------------------------- @@ -370,24 +367,12 @@ void LevelInfo::_onLMActivate(const char *lm, bool enable) #endif } -bool LevelInfo::_setLevelAccuTexture(void *object, const char *index, const char *data) +void LevelInfo::setLevelAccuTexture() { - LevelInfo* volume = reinterpret_cast< LevelInfo* >(object); - volume->setLevelAccuTexture(StringTable->insert(data)); - return false; -} - - -void LevelInfo::setLevelAccuTexture(StringTableEntry name) -{ - _setAccuTexture(name); - - if (isClientObject() && getAccuTexture() != StringTable->EmptyString()) + if (isClientObject() && mAccuTextureAsset.notNull()) { - if (mAccuTexture.isNull()) - Con::warnf("AccumulationVolume::setTexture - Unable to load texture: %s", getAccuTexture()); - else - gLevelAccuMap = mAccuTexture; + gLevelAccuMap = getAccuTexture(); } + AccumulationVolume::refreshVolumes(); } diff --git a/Engine/source/T3D/levelInfo.h b/Engine/source/T3D/levelInfo.h index 91da71791..d6a28155e 100644 --- a/Engine/source/T3D/levelInfo.h +++ b/Engine/source/T3D/levelInfo.h @@ -106,10 +106,7 @@ class LevelInfo : public NetObject void _onLMActivate(const char *lm, bool enable); protected: - DECLARE_IMAGEASSET(LevelInfo, AccuTexture, onAccuTextureChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(LevelInfo, AccuTexture); - - void onAccuTextureChanged() {} + DECLARE_IMAGEASSET_REFACTOR(LevelInfo, AccuTexture, GFXStaticTextureSRGBProfile) public: @@ -146,8 +143,7 @@ class LevelInfo : public NetObject U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) override; void unpackUpdate( NetConnection *conn, BitStream *stream ) override; - static bool _setLevelAccuTexture(void *object, const char *index, const char *data); - void setLevelAccuTexture(StringTableEntry name); + void setLevelAccuTexture(); /// @} }; diff --git a/Engine/source/T3D/lightFlareData.cpp b/Engine/source/T3D/lightFlareData.cpp index fa4477ff9..47fdd2855 100644 --- a/Engine/source/T3D/lightFlareData.cpp +++ b/Engine/source/T3D/lightFlareData.cpp @@ -132,8 +132,6 @@ LightFlareData::LightFlareData() for ( U32 i = 0; i < MAX_ELEMENTS; i++ ) mElementDist[i] = -1.0f; - - INIT_ASSET(FlareTexture); } LightFlareData::~LightFlareData() @@ -161,7 +159,7 @@ void LightFlareData::initPersistFields() addField( "flareEnabled", TypeBool, Offset( mFlareEnabled, LightFlareData ), "Allows the user to disable this flare globally for any lights referencing it." ); - INITPERSISTFIELD_IMAGEASSET(FlareTexture, LightFlareData, "The texture / sprite sheet for this flare."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(FlareTexture, LightFlareData, "The texture / sprite sheet for this flare."); addArray( "Elements", MAX_ELEMENTS ); @@ -220,7 +218,7 @@ void LightFlareData::packData( BitStream *stream ) stream->writeFlag( mFlareEnabled ); - PACKDATA_ASSET(FlareTexture); + PACKDATA_ASSET_REFACTOR(FlareTexture); stream->write( mScale ); stream->write( mOcclusionRadius ); @@ -245,7 +243,7 @@ void LightFlareData::unpackData( BitStream *stream ) mFlareEnabled = stream->readFlag(); - UNPACKDATA_ASSET(FlareTexture); + UNPACKDATA_ASSET_REFACTOR(FlareTexture); stream->read( &mScale ); stream->read( &mOcclusionRadius ); @@ -540,7 +538,7 @@ void LightFlareData::prepRender(SceneRenderState *state, LightFlareState *flareS GFXVertexPCT *vert = flareState->vertBuffer.lock(); - const Point2F oneOverTexSize( 1.0f / (F32)mFlareTexture.getWidth(), 1.0f / (F32)mFlareTexture.getHeight() ); + const Point2F oneOverTexSize( 1.0f / (F32)getFlareTexture().getWidth(), 1.0f / (F32)getFlareTexture().getHeight()); for ( U32 i = 0; i < mElementCount; i++ ) { @@ -614,7 +612,7 @@ void LightFlareData::prepRender(SceneRenderState *state, LightFlareState *flareS ri->bbModelViewProj = &MatrixF::Identity; ri->count = elementCount; ri->blendStyle = ParticleRenderInst::BlendGreyscale; - ri->diffuseTex = mFlareTexture; + ri->diffuseTex = getFlareTexture(); ri->softnessDistance = 1.0f; ri->defaultKey = ri->diffuseTex ? (uintptr_t)ri->diffuseTex : (uintptr_t)ri->vertBuff; // Sort by texture too. diff --git a/Engine/source/T3D/lightFlareData.h b/Engine/source/T3D/lightFlareData.h index 5239bf3c1..952d8f56a 100644 --- a/Engine/source/T3D/lightFlareData.h +++ b/Engine/source/T3D/lightFlareData.h @@ -106,8 +106,6 @@ protected: void _makePrimBuffer( GFXPrimitiveBufferHandle *pb, U32 count ); void _renderCorona( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); - void onImageChanged() {} - protected: static const U32 LosMask; @@ -120,8 +118,7 @@ protected: F32 mScale; bool mFlareEnabled; - DECLARE_IMAGEASSET(LightFlareData, FlareTexture, onImageChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(LightFlareData, FlareTexture); + DECLARE_IMAGEASSET_REFACTOR(LightFlareData, FlareTexture, GFXStaticTextureSRGBProfile) F32 mOcclusionRadius; bool mRenderReflectPass; diff --git a/Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp b/Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp index 9dd7d018d..4e8595adc 100644 --- a/Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp +++ b/Engine/source/afx/afxZodiacGroundPlaneRenderer_T3D.cpp @@ -264,7 +264,7 @@ void afxZodiacGroundPlaneRenderer::render(SceneRenderState* state) GFX->setShaderConstBuffer(shader_consts); // set the texture - GFX->setTexture(0, *zode->txr); + GFX->setTexture(0, zode->txr); LinearColorF zode_color = (LinearColorF)zode->color; zode_color.alpha *= fadebias; shader_consts->set(color_sc, zode_color); diff --git a/Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp b/Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp index 5d754084b..da1aa2d6c 100644 --- a/Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp +++ b/Engine/source/afx/afxZodiacMeshRoadRenderer_T3D.cpp @@ -268,7 +268,7 @@ void afxZodiacMeshRoadRenderer::render(SceneRenderState* state) GFX->setShaderConstBuffer(shader_consts); // set the texture - GFX->setTexture(0, *zode->txr); + GFX->setTexture(0, zode->txr); LinearColorF zode_color = (LinearColorF)zode->color; zode_color.alpha *= fadebias; shader_consts->set(color_sc, zode_color); diff --git a/Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp b/Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp index d34da0f03..c2572614d 100644 --- a/Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp +++ b/Engine/source/afx/afxZodiacPolysoupRenderer_T3D.cpp @@ -268,7 +268,7 @@ void afxZodiacPolysoupRenderer::render(SceneRenderState* state) GFX->setShaderConstBuffer(shader_consts); // set the texture - GFX->setTexture(0, *zode->txr); + GFX->setTexture(0, zode->txr); LinearColorF zode_color = (LinearColorF)zode->color; zode_color.alpha *= fadebias; shader_consts->set(color_sc, zode_color); diff --git a/Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp b/Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp index 6e82b97a3..b01abb4b1 100644 --- a/Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp +++ b/Engine/source/afx/afxZodiacTerrainRenderer_T3D.cpp @@ -281,7 +281,7 @@ void afxZodiacTerrainRenderer::render(SceneRenderState* state) GFX->setShaderConstBuffer(shader_consts); // set the texture - GFX->setTexture(0, *zode->txr); + GFX->setTexture(0, zode->txr); LinearColorF zode_color = (LinearColorF)zode->color; zode_color.alpha *= fadebias; shader_consts->set(color_sc, zode_color); diff --git a/Engine/source/afx/ce/afxBillboard.cpp b/Engine/source/afx/ce/afxBillboard.cpp index ce541f4b1..9e07ab51d 100644 --- a/Engine/source/afx/ce/afxBillboard.cpp +++ b/Engine/source/afx/ce/afxBillboard.cpp @@ -51,7 +51,6 @@ ConsoleDocClass( afxBillboardData, afxBillboardData::afxBillboardData() { color.set(1.0f, 1.0f, 1.0f, 1.0f); - INIT_ASSET(Texture); dimensions.set(1.0f, 1.0f); texCoords[0].set(0.0f, 0.0f); texCoords[1].set(0.0f, 1.0f); @@ -66,7 +65,7 @@ afxBillboardData::afxBillboardData(const afxBillboardData& other, bool temp_clon : GameBaseData(other, temp_clone) { color = other.color; - CLONE_ASSET(Texture); + CLONE_ASSET_REFACTOR(Texture); dimensions = other.dimensions; texCoords[0] = other.texCoords[0]; texCoords[1] = other.texCoords[1]; @@ -96,7 +95,7 @@ void afxBillboardData::initPersistFields() "The color assigned to the quadrangle geometry. The way it combines with the given " "texture varies according to the setting of the textureFunction field."); - INITPERSISTFIELD_IMAGEASSET(Texture, afxBillboardData, "An image to use as the billboard's texture."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxBillboardData, "An image to use as the billboard's texture."); addField("dimensions", TypePoint2F, myOffset(dimensions), "A value-pair that specifies the horizontal and vertical dimensions of the billboard " @@ -124,7 +123,7 @@ void afxBillboardData::packData(BitStream* stream) Parent::packData(stream); stream->write(color); - PACKDATA_ASSET(Texture); + PACKDATA_ASSET_REFACTOR(Texture); mathWrite(*stream, dimensions); mathWrite(*stream, texCoords[0]); @@ -141,7 +140,7 @@ void afxBillboardData::unpackData(BitStream* stream) Parent::unpackData(stream); stream->read(&color); - UNPACKDATA_ASSET(Texture); + UNPACKDATA_ASSET_REFACTOR(Texture); mathRead(*stream, &dimensions); mathRead(*stream, &texCoords[0]); mathRead(*stream, &texCoords[1]); diff --git a/Engine/source/afx/ce/afxBillboard.h b/Engine/source/afx/ce/afxBillboard.h index 8918e2f26..1884e6800 100644 --- a/Engine/source/afx/ce/afxBillboard.h +++ b/Engine/source/afx/ce/afxBillboard.h @@ -47,8 +47,7 @@ public: }; public: - DECLARE_IMAGEASSET(afxBillboardData, Texture, onChangeTexture, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(afxBillboardData, Texture); + DECLARE_IMAGEASSET_REFACTOR(afxBillboardData, Texture, GFXStaticTextureSRGBProfile) LinearColorF color; @@ -71,8 +70,6 @@ public: static void initPersistFields(); - void onChangeTexture() {} - DECLARE_CONOBJECT(afxBillboardData); }; diff --git a/Engine/source/afx/ce/afxBillboard_T3D.cpp b/Engine/source/afx/ce/afxBillboard_T3D.cpp index 81d84ebc4..0c8f523e2 100644 --- a/Engine/source/afx/ce/afxBillboard_T3D.cpp +++ b/Engine/source/afx/ce/afxBillboard_T3D.cpp @@ -87,7 +87,7 @@ void afxBillboard::_renderBillboard(ObjectRenderInst *ri, SceneRenderState* stat GFXTransformSaver saver; GFX->multWorld(getRenderTransform()); - GFX->setTexture(0, mDataBlock->mTexture); + GFX->setTexture(0, mDataBlock->getTexture()); MatrixF worldmod = GFX->getWorldMatrix(); MatrixF viewmod = GFX->getViewMatrix(); diff --git a/Engine/source/afx/ce/afxZodiac.cpp b/Engine/source/afx/ce/afxZodiac.cpp index 383bbcc15..93baff545 100644 --- a/Engine/source/afx/ce/afxZodiac.cpp +++ b/Engine/source/afx/ce/afxZodiac.cpp @@ -78,8 +78,6 @@ bool afxZodiacData::sPreferDestinationGradients = false; afxZodiacData::afxZodiacData() { - INIT_ASSET(Texture); - radius_xy = 1; vert_range.set(0.0f, 0.0f); start_ang = 0; @@ -120,7 +118,7 @@ afxZodiacData::afxZodiacData() afxZodiacData::afxZodiacData(const afxZodiacData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - CLONE_ASSET(Texture); + CLONE_ASSET_REFACTOR(Texture); radius_xy = other.radius_xy; vert_range = other.vert_range; @@ -157,7 +155,7 @@ EndImplementEnumType; void afxZodiacData::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacData, "An image to use as the zodiac's texture."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxZodiacData, "An image to use as the zodiac's texture."); addField("radius", TypeF32, Offset(radius_xy, afxZodiacData), "The zodiac's radius in scene units."); addField("verticalRange", TypePoint2F, Offset(vert_range, afxZodiacData), @@ -270,7 +268,7 @@ void afxZodiacData::packData(BitStream* stream) merge_zflags(); - PACKDATA_ASSET(Texture); + PACKDATA_ASSET_REFACTOR(Texture); stream->write(radius_xy); stream->write(vert_range.x); stream->write(vert_range.y); @@ -295,7 +293,7 @@ void afxZodiacData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(Texture); + UNPACKDATA_ASSET_REFACTOR(Texture); stream->read(&radius_xy); stream->read(&vert_range.x); stream->read(&vert_range.y); @@ -342,16 +340,9 @@ void afxZodiacData::onStaticModified(const char* slot, const char* newValue) void afxZodiacData::onPerformSubstitutions() { - if (mTextureAssetId != StringTable->EmptyString()) + if (mTextureAsset.notNull()) { - mTextureAsset = mTextureAssetId; - if (mTextureAsset.notNull()) - { - if (getTexture() != StringTable->EmptyString() && mTextureName != StringTable->insert("texhandle")) - { - mTexture.set(getTexture(), mTextureProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); - } - } + getTexture(); } } diff --git a/Engine/source/afx/ce/afxZodiac.h b/Engine/source/afx/ce/afxZodiac.h index a7d14c2f1..9163f2d4b 100644 --- a/Engine/source/afx/ce/afxZodiac.h +++ b/Engine/source/afx/ce/afxZodiac.h @@ -56,11 +56,8 @@ public: static void convertGradientRangeFromDegrees(Point2F& gradrange, const Point2F& gradrange_deg); - void onImageChanged() {} - public: - DECLARE_IMAGEASSET(afxZodiacData, Texture, onImageChanged, AFX_GFXZodiacTextureProfile); - DECLARE_ASSET_SETGET(afxZodiacData, Texture); + DECLARE_IMAGEASSET_REFACTOR(afxZodiacData, Texture, AFX_GFXZodiacTextureProfile) F32 radius_xy; Point2F vert_range; diff --git a/Engine/source/afx/ce/afxZodiacMgr.cpp b/Engine/source/afx/ce/afxZodiacMgr.cpp index fe9924128..ecac36afa 100644 --- a/Engine/source/afx/ce/afxZodiacMgr.cpp +++ b/Engine/source/afx/ce/afxZodiacMgr.cpp @@ -61,7 +61,7 @@ void afxZodiacMgr::addTerrainZodiac(Point3F& pos, F32 radius, LinearColorF& colo z.color = color.toColorI(); z.angle = mDegToRad(angle); z.zflags = zode->zflags; - z.txr = &zode->mTexture; + z.txr = zode->getTexture(); z.distance_max = zode->distance_max*zode->distance_max; z.distance_falloff = zode->distance_falloff*zode->distance_falloff; @@ -84,7 +84,7 @@ void afxZodiacMgr::addInteriorZodiac(Point3F& pos, F32 radius, Point2F& vert_ran z.color = color.toColorI(); z.angle = mDegToRad(angle); z.zflags = zode->zflags; - z.txr = &zode->mTexture; + z.txr = zode->getTexture(); z.distance_max = zode->distance_max*zode->distance_max; z.distance_falloff = zode->distance_falloff*zode->distance_falloff; diff --git a/Engine/source/afx/ce/afxZodiacMgr.h b/Engine/source/afx/ce/afxZodiacMgr.h index 0141b3ed4..a243482ba 100644 --- a/Engine/source/afx/ce/afxZodiacMgr.h +++ b/Engine/source/afx/ce/afxZodiacMgr.h @@ -67,7 +67,7 @@ private: ColorI color; // 4// color of zodiac F32 angle; // 4// angle in radians U32 zflags; // 4// 0=normal,1=additive,2=subtractive - GFXTexHandle* txr; // 4// zodiac texture + GFXTexHandle txr; // 4// zodiac texture F32 distance_max; F32 distance_falloff; diff --git a/Engine/source/afx/ce/afxZodiacPlane.cpp b/Engine/source/afx/ce/afxZodiacPlane.cpp index be645c091..e3bc6ede0 100644 --- a/Engine/source/afx/ce/afxZodiacPlane.cpp +++ b/Engine/source/afx/ce/afxZodiacPlane.cpp @@ -51,8 +51,6 @@ ConsoleDocClass( afxZodiacPlaneData, afxZodiacPlaneData::afxZodiacPlaneData() { - INIT_ASSET(Texture); - radius_xy = 1; start_ang = 0; ang_per_sec = 0; @@ -71,7 +69,7 @@ afxZodiacPlaneData::afxZodiacPlaneData() afxZodiacPlaneData::afxZodiacPlaneData(const afxZodiacPlaneData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - CLONE_ASSET(Texture); + CLONE_ASSET_REFACTOR(Texture); radius_xy = other.radius_xy; start_ang = other.start_ang; @@ -112,7 +110,7 @@ EndImplementEnumType; void afxZodiacPlaneData::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacPlaneData, "An image to use as the zodiac's texture."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxZodiacPlaneData, "An image to use as the zodiac's texture."); addField("radius", TypeF32, myOffset(radius_xy), "The zodiac's radius in scene units."); @@ -166,7 +164,7 @@ void afxZodiacPlaneData::packData(BitStream* stream) merge_zflags(); - PACKDATA_ASSET(Texture); + PACKDATA_ASSET_REFACTOR(Texture); stream->write(radius_xy); stream->write(start_ang); @@ -185,7 +183,7 @@ void afxZodiacPlaneData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(Texture); + UNPACKDATA_ASSET_REFACTOR(Texture); stream->read(&radius_xy); stream->read(&start_ang); diff --git a/Engine/source/afx/ce/afxZodiacPlane.h b/Engine/source/afx/ce/afxZodiacPlane.h index 13c9879b5..0ce187d89 100644 --- a/Engine/source/afx/ce/afxZodiacPlane.h +++ b/Engine/source/afx/ce/afxZodiacPlane.h @@ -56,11 +56,8 @@ public: FACES_BITS = 3 }; - void onImageChanged() {} - public: - DECLARE_IMAGEASSET(afxZodiacPlaneData, Texture, onImageChanged, AFX_GFXZodiacTextureProfile); - DECLARE_ASSET_SETGET(afxZodiacPlaneData, Texture); + DECLARE_IMAGEASSET_REFACTOR(afxZodiacPlaneData, Texture, AFX_GFXZodiacTextureProfile) F32 radius_xy; F32 start_ang; diff --git a/Engine/source/afx/ce/afxZodiacPlane_T3D.cpp b/Engine/source/afx/ce/afxZodiacPlane_T3D.cpp index 59ea81763..99ac19d6b 100644 --- a/Engine/source/afx/ce/afxZodiacPlane_T3D.cpp +++ b/Engine/source/afx/ce/afxZodiacPlane_T3D.cpp @@ -207,7 +207,7 @@ void afxZodiacPlane::_renderZodiacPlane(ObjectRenderInst *ri, SceneRenderState* GFXTransformSaver saver; GFX->multWorld(getRenderTransform()); - GFX->setTexture(0, mDataBlock->mTexture); + GFX->setTexture(0, mDataBlock->getTexture()); PrimBuild::begin(GFXTriangleStrip, 4); { diff --git a/Engine/source/afx/util/afxParticlePool_T3D.cpp b/Engine/source/afx/util/afxParticlePool_T3D.cpp index c8cc7c9ed..4ad24e68a 100644 --- a/Engine/source/afx/util/afxParticlePool_T3D.cpp +++ b/Engine/source/afx/util/afxParticlePool_T3D.cpp @@ -146,7 +146,7 @@ void afxParticlePool::pool_renderObject_Normal(RenderPassManager *renderManager, if (main_emitter_data->textureHandle) ri->diffuseTex = &*(main_emitter_data->textureHandle); else - ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource()); + ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTexture()); ri->softnessDistance = main_emitter_data->softnessDistance; @@ -277,7 +277,7 @@ void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager //if (main_emitter_data->textureHandle) // ri->diffuseTex = &*(main_emitter_data->textureHandle); //else - ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureExtResource()); + ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureExt()); F32 save_sort_dist = ri->sortDistSq; @@ -481,7 +481,7 @@ void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager if (main_emitter_data->textureHandle) ri->diffuseTex = &*(main_emitter_data->textureHandle); else - ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource()); + ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTexture()); ri->softnessDistance = main_emitter_data->softnessDistance; diff --git a/Engine/source/environment/VolumetricFog.cpp b/Engine/source/environment/VolumetricFog.cpp index a4065c8ad..7462bd2c3 100644 --- a/Engine/source/environment/VolumetricFog.cpp +++ b/Engine/source/environment/VolumetricFog.cpp @@ -105,7 +105,6 @@ VolumetricFog::VolumetricFog() mFrontBufferTarget = NULL; z_buf = NULL; - mTexture = NULL; mIsVBDirty = false; mIsPBDirty = false; @@ -138,7 +137,6 @@ VolumetricFog::VolumetricFog() mSpeed2.set(0.1f, 0.1f); INIT_ASSET(Shape); - INIT_ASSET(Texture); } VolumetricFog::~VolumetricFog() @@ -159,8 +157,6 @@ VolumetricFog::~VolumetricFog() z_buf = NULL; - if (!mTexture.isNull()) - mTexture.free(); } void VolumetricFog::initPersistFields() @@ -185,7 +181,7 @@ void VolumetricFog::initPersistFields() endGroup("VolumetricFogData"); addGroup("VolumetricFogModulation"); - INITPERSISTFIELD_IMAGEASSET(Texture, VolumetricFog, "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, VolumetricFog, "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation."); addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), "How many times the texture is mapped to the object."); @@ -330,8 +326,10 @@ void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize) F32 width = (F32)mPlatformWindow->getClientExtent().x; F32 height = (F32)mPlatformWindow->getClientExtent().y; - mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width); - mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height); + // load texture. + getTexture(); + mTexScale.x = 2.0f - ((F32)mTextureAsset->getTextureWidth() / width); + mTexScale.y = 2.0f - ((F32)mTextureAsset->getTextureHeight() / height); } UpdateBuffers(0,true); @@ -545,7 +543,7 @@ U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream) stream->write(mFogDensity); if (stream->writeFlag(mask & FogModulationMask)) { - PACK_ASSET(con, Texture); + PACK_ASSET_REFACTOR(con, Texture); mTexTiles = mFabs(mTexTiles); stream->write(mTexTiles); stream->write(mStrength); @@ -597,7 +595,7 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) MatrixF mat; VectorF scale; VectorF mOldScale = getScale(); - StringTableEntry oldTextureName = mTextureAssetId; + StringTableEntry oldTextureName = mTextureAsset.getAssetId(); StringTableEntry oldShapeAsset = mShapeAssetId; StringTableEntry oldShape = mShapeName; @@ -615,7 +613,7 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) } if (stream->readFlag())// Fog Modulation { - UNPACK_ASSET(con, Texture); + UNPACK_ASSET_REFACTOR(con, Texture); stream->read(&mTexTiles); mTexTiles = mFabs(mTexTiles); stream->read(&mStrength); @@ -625,12 +623,11 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) if (isProperlyAdded()) { - if (oldTextureName != mTextureAssetId) + if (oldTextureName != mTextureAsset.getAssetId()) InitTexture(); - if (oldTextureName != StringTable->EmptyString() && mTextureAssetId == StringTable->EmptyString()) + if (oldTextureName != StringTable->EmptyString() && mTextureAsset.isNull()) { mIsTextured = false; - mTexture.free(); } } } @@ -1149,7 +1146,7 @@ void VolumetricFog::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMa if (mIsTextured && mStrength > 0.0f) { - GFX->setTexture(3, mTexture); + GFX->setTexture(3, getTexture()); mShaderConsts->setSafe(mIsTexturedSC, 1.0f); } else @@ -1222,15 +1219,16 @@ void VolumetricFog::InitTexture() { return; } - if (!mTexture.isNull()) + if (!mTextureAsset.isNull()) { mIsTextured = true; - + // load asset. + getTexture(); F32 width = (F32)mPlatformWindow->getClientExtent().x; F32 height = (F32)mPlatformWindow->getClientExtent().y; - mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width); - mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height); + mTexScale.x = 2.0f - ((F32)mTextureAsset->getTextureWidth() / width); + mTexScale.y = 2.0f - ((F32)mTextureAsset->getTextureHeight() / height); } } diff --git a/Engine/source/environment/VolumetricFog.h b/Engine/source/environment/VolumetricFog.h index a85ef1665..80a349cb6 100644 --- a/Engine/source/environment/VolumetricFog.h +++ b/Engine/source/environment/VolumetricFog.h @@ -162,8 +162,7 @@ class VolumetricFog : public SceneObject F32 mInvScale; // Fog Modulation data - DECLARE_IMAGEASSET(VolumetricFog, Texture, onImageChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_NET_SETGET(VolumetricFog, Texture, FogModulationMask); + DECLARE_IMAGEASSET_NET_REFACTOR(VolumetricFog, Texture, GFXStaticTextureSRGBProfile, FogModulationMask) bool mIsTextured; F32 mTexTiles; @@ -221,8 +220,6 @@ class VolumetricFog : public SceneObject static bool _setShapeAsset(void* obj, const char* index, const char* data); - void onImageChanged() {} - public: // Public methods VolumetricFog(); diff --git a/Engine/source/environment/cloudLayer.h b/Engine/source/environment/cloudLayer.h index 675b3b78b..a07e00c14 100644 --- a/Engine/source/environment/cloudLayer.h +++ b/Engine/source/environment/cloudLayer.h @@ -98,7 +98,7 @@ protected: public: - DECLARE_IMAGEASSET_REFACTOR(CloudLayer,Texture, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET_NET_REFACTOR(CloudLayer,Texture, GFXStaticTextureSRGBProfile, CloudLayerMask) GFXShaderRef mShader; diff --git a/Engine/source/environment/waterObject.cpp b/Engine/source/environment/waterObject.cpp index c2074446d..fe3f5dc59 100644 --- a/Engine/source/environment/waterObject.cpp +++ b/Engine/source/environment/waterObject.cpp @@ -260,10 +260,6 @@ WaterObject::WaterObject() mMatrixSet = reinterpret_cast(dMalloc_aligned(sizeof(MatrixSet), 16)); constructInPlace(mMatrixSet); - INIT_ASSET(RippleTex); - INIT_ASSET(FoamTex); - INIT_ASSET(DepthGradientTex); - mCubemapName = StringTable->EmptyString(); } @@ -300,7 +296,7 @@ void WaterObject::initPersistFields() addField( "overallWaveMagnitude", TypeF32, Offset( mOverallWaveMagnitude, WaterObject ), "Master variable affecting entire body" " of water's undulation" ); - INITPERSISTFIELD_IMAGEASSET(RippleTex, WaterObject, "Normal map used to simulate small surface ripples"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(RippleTex, WaterObject, "Normal map used to simulate small surface ripples"); addArray( "Ripples (texture animation)", MAX_WAVES ); @@ -314,7 +310,7 @@ void WaterObject::initPersistFields() addField( "overallRippleMagnitude", TypeF32, Offset( mOverallRippleMagnitude, WaterObject ), "Master variable affecting entire surface"); - INITPERSISTFIELD_IMAGEASSET(FoamTex, WaterObject, "Diffuse texture for foam in shallow water (advanced lighting only)"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(FoamTex, WaterObject, "Diffuse texture for foam in shallow water (advanced lighting only)"); addArray( "Foam", MAX_FOAM ); @@ -366,7 +362,7 @@ void WaterObject::initPersistFields() addGroup( "Misc" ); - INITPERSISTFIELD_IMAGEASSET(DepthGradientTex, WaterObject, "1D texture defining the base water color by depth"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(DepthGradientTex, WaterObject, "1D texture defining the base water color by depth"); addField( "depthGradientMax", TypeF32, Offset( mDepthGradientMax, WaterObject ), "Depth in world units, the max range of the color gradient texture." ); @@ -547,9 +543,9 @@ U32 WaterObject::packUpdate( NetConnection * conn, U32 mask, BitStream *stream ) if ( stream->writeFlag( mask & TextureMask ) ) { - PACK_ASSET(conn, RippleTex); - PACK_ASSET(conn, DepthGradientTex); - PACK_ASSET(conn, FoamTex); + PACK_ASSET_REFACTOR(conn, RippleTex); + PACK_ASSET_REFACTOR(conn, DepthGradientTex); + PACK_ASSET_REFACTOR(conn, FoamTex); stream->writeString( mCubemapName ); } @@ -669,9 +665,9 @@ void WaterObject::unpackUpdate( NetConnection * conn, BitStream *stream ) // TextureMask if ( stream->readFlag() ) { - UNPACK_ASSET(conn, RippleTex); - UNPACK_ASSET(conn, DepthGradientTex); - UNPACK_ASSET(conn, FoamTex); + UNPACK_ASSET_REFACTOR(conn, RippleTex); + UNPACK_ASSET_REFACTOR(conn, DepthGradientTex); + UNPACK_ASSET_REFACTOR(conn, FoamTex); mCubemapName = stream->readSTString(); @@ -767,13 +763,13 @@ void WaterObject::renderObject( ObjectRenderInst *ri, SceneRenderState *state, B void WaterObject::setCustomTextures( S32 matIdx, U32 pass, const WaterMatParams ¶mHandles ) { // Always use the ripple texture. - GFX->setTexture( paramHandles.mRippleSamplerSC->getSamplerRegister(pass), mRippleTex ); + GFX->setTexture( paramHandles.mRippleSamplerSC->getSamplerRegister(pass), getRippleTex() ); // Only above-water in advanced-lighting uses the foam texture. if ( matIdx == WaterMat ) { - GFX->setTexture( paramHandles.mFoamSamplerSC->getSamplerRegister(pass), mFoamTex ); - GFX->setTexture( paramHandles.mDepthGradSamplerSC->getSamplerRegister(pass), mDepthGradientTex ); + GFX->setTexture( paramHandles.mFoamSamplerSC->getSamplerRegister(pass), getFoamTex() ); + GFX->setTexture( paramHandles.mDepthGradSamplerSC->getSamplerRegister(pass), getDepthGradientTex() ); } if ( ( matIdx == WaterMat || matIdx == BasicWaterMat ) && mCubemap ) @@ -1118,7 +1114,7 @@ void WaterObject::updateUnderwaterEffect( SceneRenderState *state ) // be fetched by the effect when it renders. if ( !mNamedDepthGradTex.isRegistered() ) mNamedDepthGradTex.registerWithName( "waterDepthGradMap" ); - mNamedDepthGradTex.setTexture( mDepthGradientTex ); + mNamedDepthGradTex.setTexture( getDepthGradientTex() ); } else effect->disable(); @@ -1172,7 +1168,7 @@ bool WaterObject::initMaterial( S32 idx ) void WaterObject::initTextures() { if ( mNamedDepthGradTex.isRegistered() ) - mNamedDepthGradTex.setTexture( mDepthGradientTex ); + mNamedDepthGradTex.setTexture( getDepthGradientTex() ); if ( mCubemapName != StringTable->EmptyString() ) Sim::findObject( mCubemapName, mCubemap ); diff --git a/Engine/source/environment/waterObject.h b/Engine/source/environment/waterObject.h index 09f3e1eaa..ceb490bdf 100644 --- a/Engine/source/environment/waterObject.h +++ b/Engine/source/environment/waterObject.h @@ -203,10 +203,6 @@ protected: /// Callback used internally when smEnableTrueReflections changes. void _onEnableTrueReflections(); - void onRippleTexChanged() {} - void onFoamTexChanged() {} - void onDepthGradientTexChanged() {} - protected: static bool _setFullReflect( void *object, const char *index, const char *data ); @@ -273,12 +269,9 @@ protected: F32 mDepthGradientMax; // Other textures - DECLARE_IMAGEASSET(WaterObject, RippleTex, onRippleTexChanged, GFXStaticTextureProfile); - DECLARE_ASSET_NET_SETGET(WaterObject, RippleTex, TextureMask); - DECLARE_IMAGEASSET(WaterObject, FoamTex, onFoamTexChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_NET_SETGET(WaterObject, FoamTex, TextureMask); - DECLARE_IMAGEASSET(WaterObject, DepthGradientTex, onDepthGradientTexChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_NET_SETGET(WaterObject, DepthGradientTex, TextureMask); + DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, RippleTex, GFXStaticTextureProfile, TextureMask) + DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, FoamTex, GFXStaticTextureSRGBProfile, TextureMask) + DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, DepthGradientTex, GFXStaticTextureSRGBProfile, TextureMask) StringTableEntry mCubemapName; diff --git a/Engine/source/terrain/terrCellMaterial.cpp b/Engine/source/terrain/terrCellMaterial.cpp index 5c7756c00..7ea7ea69c 100644 --- a/Engine/source/terrain/terrCellMaterial.cpp +++ b/Engine/source/terrain/terrCellMaterial.cpp @@ -374,7 +374,7 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, // We only include materials that // have more than a base texture. - if (!(mat->DetailMapValid() && mat->getDetailSize() > 0 && mat->getDetailDistance()>0)) + if (!(mat->getDetailMap() && mat->getDetailSize() > 0 && mat->getDetailDistance()>0)) continue; if (deferredMat) @@ -382,12 +382,12 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, features.addFeature(MFT_TerrainDetailMap, featureIndex); // check for macro detail texture - if (mat->MacroMapValid() && mat->getMacroSize() > 0 && mat->getMacroDistance() > 0) + if (mat->getMacroMap() && mat->getMacroSize() > 0 && mat->getMacroDistance() > 0) { features.addFeature(MFT_TerrainMacroMap, featureIndex); } - if (mat->ORMConfigMapValid()) + if (mat->getORMConfigMap()) { features.addFeature(MFT_TerrainORMMap, featureIndex); } @@ -401,12 +401,12 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, // Skip normal maps if we need to. - if (!disableNormalMaps && mat->NormalMapValid()) + if (!disableNormalMaps && mat->getNormalMap()) { normalMaps.increment(); features.addFeature(MFT_TerrainNormalMap, featureIndex); - normalMaps.last() = mat->getNormalMapResource(); + normalMaps.last() = mat->getNormalMap(); GFXFormat normalFmt = normalMaps.last().getFormat(); if (normalFmt == GFXFormatBC3) @@ -632,7 +632,7 @@ bool TerrainCellMaterial::_initShader(bool deferredMat, // We only include materials that // have more than a base texture. - if (!(mat->DetailMapValid() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) + if (!(mat->getDetailMap() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) continue; mMaterialInfos[i]->mBlendDepthConst = mShader->getShaderConstHandle(avar("$blendDepth%d", i)); @@ -676,7 +676,7 @@ void TerrainCellMaterial::_updateMaterialConsts( ) if (mat == NULL) continue; - if (!(mat->DetailMapValid() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) + if (!(mat->getDetailMap() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) continue; detailMatCount++; @@ -704,7 +704,7 @@ void TerrainCellMaterial::_updateMaterialConsts( ) if (mat == NULL) continue; - if (!(mat->DetailMapValid() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) + if (!(mat->getDetailMap() && mat->getDetailSize() > 0 && mat->getDetailDistance() > 0)) continue; F32 detailSize = matInfo->mat->getDetailSize(); diff --git a/Engine/source/terrain/terrMaterial.cpp b/Engine/source/terrain/terrMaterial.cpp index 8c13861b4..1c8abbbbe 100644 --- a/Engine/source/terrain/terrMaterial.cpp +++ b/Engine/source/terrain/terrMaterial.cpp @@ -81,11 +81,6 @@ TerrainMaterial::TerrainMaterial() mIsSRGB(false), mInvertRoughness(false) { - INIT_ASSET(DiffuseMap); - INIT_ASSET(NormalMap); - INIT_ASSET(DetailMap); - INIT_ASSET(ORMConfigMap); - INIT_ASSET(MacroMap); } TerrainMaterial::~TerrainMaterial() @@ -97,10 +92,10 @@ FRangeValidator hardnessValidator(0.0f, 0.999f); void TerrainMaterial::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(DiffuseMap, TerrainMaterial,"Base Albedo stretched over the whole map"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(DiffuseMap, TerrainMaterial,"Base Albedo stretched over the whole map"); addField( "diffuseSize", TypeF32, Offset( mDiffuseSize, TerrainMaterial ), "Used to scale the diffuse map to the material square" ); - INITPERSISTFIELD_IMAGEASSET(NormalMap, TerrainMaterial,"NormalMap"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(NormalMap, TerrainMaterial,"NormalMap"); addField( "parallaxScale", TypeF32, Offset( mParallaxScale, TerrainMaterial ), "Used to scale the height from the normal map to give some self " "occlusion effect (aka parallax) to the terrain material" ); @@ -113,7 +108,7 @@ void TerrainMaterial::initPersistFields() addFieldV("blendHeightHardness", TypeF32, Offset(mBlendHardness, TerrainMaterial), &hardnessValidator, "How sharply this layer blends with other textures." "0->1, soft->hard."); - INITPERSISTFIELD_IMAGEASSET(DetailMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo up close."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(DetailMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo up close."); addField( "detailSize", TypeF32, Offset( mDetailSize, TerrainMaterial ), "Used to scale the detail map to the material square" ); addField( "detailStrength", TypeF32, Offset( mDetailStrength, TerrainMaterial ), "Exponentially sharpens or lightens the detail map rendering on the material" ); addField( "detailDistance", TypeF32, Offset( mDetailDistance, TerrainMaterial ), "Changes how far camera can see the detail map rendering on the material" ); @@ -121,12 +116,12 @@ void TerrainMaterial::initPersistFields() addField( "useSideProjection", TypeBool, Offset( mSideProjection, TerrainMaterial ),"Makes that terrain material project along the sides of steep " "slopes instead of projected downwards"); - INITPERSISTFIELD_IMAGEASSET(ORMConfigMap, TerrainMaterial, "AO|Roughness|metalness map (uses DetailMap UV Coords)"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(ORMConfigMap, TerrainMaterial, "AO|Roughness|metalness map (uses DetailMap UV Coords)"); addField("isSRGB", TypeBool, Offset(mIsSRGB, TerrainMaterial), "Is the PBR Config map's image in sRGB format?"); addField("invertRoughness", TypeBool, Offset(mInvertRoughness, TerrainMaterial), "Should the roughness channel of the PBR Config map be inverted?"); //Macro maps additions - INITPERSISTFIELD_IMAGEASSET(MacroMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo at a distance."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(MacroMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo at a distance."); addField( "macroSize", TypeF32, Offset( mMacroSize, TerrainMaterial ), "Used to scale the Macro map to the material square" ); addField( "macroStrength", TypeF32, Offset( mMacroStrength, TerrainMaterial ), "Exponentially sharpens or lightens the Macro map rendering on the material" ); addField( "macroDistance", TypeF32, Offset( mMacroDistance, TerrainMaterial ), "Changes how far camera can see the Macro map rendering on the material" ); @@ -228,8 +223,8 @@ TerrainMaterial* TerrainMaterial::findOrCreate( const char *nameOrPath ) //material.getDiffuseMap(); //returns the raw file referenced //material.getDiffuseMapAsset(); //returns the asset id //material.setDiffuseMap(%texture); //tries to set the asset and failing that attempts a flat file reference -DEF_ASSET_BINDS(TerrainMaterial, DiffuseMap); -DEF_ASSET_BINDS(TerrainMaterial, NormalMap); -DEF_ASSET_BINDS(TerrainMaterial, DetailMap); -DEF_ASSET_BINDS(TerrainMaterial, ORMConfigMap); -DEF_ASSET_BINDS(TerrainMaterial, MacroMap); +DEF_ASSET_BINDS_REFACTOR(TerrainMaterial, DiffuseMap) +DEF_ASSET_BINDS_REFACTOR(TerrainMaterial, NormalMap) +DEF_ASSET_BINDS_REFACTOR(TerrainMaterial, DetailMap) +DEF_ASSET_BINDS_REFACTOR(TerrainMaterial, ORMConfigMap) +DEF_ASSET_BINDS_REFACTOR(TerrainMaterial, MacroMap) diff --git a/Engine/source/terrain/terrMaterial.h b/Engine/source/terrain/terrMaterial.h index 501ab29d3..c119f57b1 100644 --- a/Engine/source/terrain/terrMaterial.h +++ b/Engine/source/terrain/terrMaterial.h @@ -38,24 +38,17 @@ class TerrainMaterial : public SimObject protected: /// - //FileName mDiffuseMap; - - //AssetPtr mDiffuseAsset; - - DECLARE_IMAGEASSET(TerrainMaterial, DiffuseMap, onDiffuseMapChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(TerrainMaterial, DiffuseMap); + DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, DiffuseMap, GFXStaticTextureSRGBProfile) /// The size of the diffuse base map in meters /// used to generate its texture coordinates. F32 mDiffuseSize; /// - DECLARE_IMAGEASSET(TerrainMaterial, NormalMap, onNormalMapChanged, GFXNormalMapProfile); - DECLARE_ASSET_SETGET(TerrainMaterial, NormalMap); + DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, NormalMap, GFXNormalMapProfile) /// - DECLARE_IMAGEASSET(TerrainMaterial, DetailMap, onDetailMapChanged, GFXStaticTextureProfile); - DECLARE_ASSET_SETGET(TerrainMaterial, DetailMap); + DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, DetailMap, GFXStaticTextureProfile) /// The size of the detail map in meters used /// to generate the texture coordinates for the @@ -69,8 +62,7 @@ protected: F32 mDetailDistance; /// - DECLARE_IMAGEASSET(TerrainMaterial, ORMConfigMap, onORMConfigMapChanged, GFXStaticTextureProfile); - DECLARE_ASSET_SETGET(TerrainMaterial, ORMConfigMap); + DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, ORMConfigMap, GFXStaticTextureProfile) bool mIsSRGB; bool mInvertRoughness; @@ -81,8 +73,8 @@ protected: /// planes. bool mSideProjection; - DECLARE_IMAGEASSET(TerrainMaterial, MacroMap, onMacroMapChanged, GFXStaticTextureProfile); - DECLARE_ASSET_SETGET(TerrainMaterial, MacroMap); + DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, MacroMap, GFXStaticTextureProfile) + F32 mMacroSize; F32 mMacroStrength; F32 mMacroDistance; @@ -146,12 +138,6 @@ public: bool getInvertRoughness() const { return mInvertRoughness; } - void onDiffuseMapChanged() {} - void onNormalMapChanged() {} - void onDetailMapChanged() {} - void onORMConfigMapChanged() {} - void onMacroMapChanged() {} - }; #endif // _TERRMATERIAL_H_ diff --git a/Engine/source/terrain/terrRender.cpp b/Engine/source/terrain/terrRender.cpp index 45d61fbff..0fc77aafc 100644 --- a/Engine/source/terrain/terrRender.cpp +++ b/Engine/source/terrain/terrRender.cpp @@ -96,19 +96,19 @@ void TerrainBlock::_updateMaterials() { TerrainMaterial *mat = mFile->mMaterials[i]; - if (mat->getDiffuseMap() != StringTable->EmptyString()) + if (mat->getDiffuseMapAsset().notNull()) { - mBaseTextures[i] = mat->getDiffuseMapResource(); + mBaseTextures[i] = mat->getDiffuseMap(); } else mBaseTextures[ i ] = GFXTexHandle(); // Find the maximum detail distance. - if ( mat->getDetailMap() != StringTable->EmptyString() && + if ( mat->getDetailMapAsset().notNull() && mat->getDetailDistance() > mMaxDetailDistance ) mMaxDetailDistance = mat->getDetailDistance(); - if ( mat->getMacroMap() != StringTable->EmptyString() && + if ( mat->getMacroMapAsset().notNull() && mat->getMacroDistance() > mMaxDetailDistance ) mMaxDetailDistance = mat->getMacroDistance(); } @@ -126,19 +126,19 @@ void TerrainBlock::_updateMaterials() { TerrainMaterial* mat = mFile->mMaterials[i]; - if (mat->getDetailMap() != StringTable->EmptyString()) - detailTexArray[i] = mat->getDetailMapResource(); - if (mat->getMacroMap() != StringTable->EmptyString()) - macroTexArray[i] = mat->getMacroMapResource(); - if (mat->getNormalMap() != StringTable->EmptyString()) - normalTexArray[i] = mat->getNormalMapResource(); + if (mat->getDetailMapAsset().notNull()) + detailTexArray[i] = mat->getDetailMap(); + if (mat->getMacroMapAsset().notNull()) + macroTexArray[i] = mat->getMacroMap(); + if (mat->getNormalMapAsset().notNull()) + normalTexArray[i] = mat->getNormalMap(); //depending on creation method this may or may not have been shoved into srgb space eroneously GFXTextureProfile* profile = &GFXStaticTextureProfile; if (mat->getIsSRGB()) profile = &GFXStaticTextureSRGBProfile; - if (mat->getORMConfigMap() != StringTable->EmptyString()) - ormTexArray[i] = TEXMGR->createTexture(mat->getORMConfigMap(), profile); + if (mat->getORMConfigMapAsset().notNull()) + ormTexArray[i] = mat->getORMConfigMapAsset()->getTexture(profile); } if (mDetailTextureArray.isNull()) diff --git a/Templates/BaseGame/game/tools/gui/profiles.ed.tscript b/Templates/BaseGame/game/tools/gui/profiles.ed.tscript index 17390ad0f..6bbac1cea 100644 --- a/Templates/BaseGame/game/tools/gui/profiles.ed.tscript +++ b/Templates/BaseGame/game/tools/gui/profiles.ed.tscript @@ -1415,7 +1415,7 @@ singleton GuiControlProfile( ToolsGuiMenuBarProfile ) singleton GuiControlProfile( ToolsMenubarProfile : ToolsGuiDefaultProfile ) { - bitmap = "./menubar"; + bitmaAsset = "ToolsModule:menubar_image"; category = "Editor"; opaque = true; @@ -1433,7 +1433,7 @@ singleton GuiControlProfile (menubarProfile) border = -2; category = "Editor"; - bitmap = "./menubar"; + bitmaAsset = "ToolsModule:menubar_image"; category = "Editor"; fillColor = EditorSettings.value("Theme/windowBackgroundColor"); @@ -1447,35 +1447,35 @@ singleton GuiControlProfile (editorMenubarProfile) { border = -2; category = "Editor"; - bitmap = "./editor-menubar"; + bitmaAsset = "ToolsModule:editor_menubar_image"; category = "Editor"; }; singleton GuiControlProfile (editorMenu_wBorderProfile) { border = -2; category = "Editor"; - bitmap = "./menu-fullborder"; + bitmaAsset = "ToolsModule:menu_fullborder_image"; category = "Editor"; }; singleton GuiControlProfile (inspectorStyleRolloutProfile) { border = -2; category = "Editor"; - bitmap = "./inspector-style-rollout"; + bitmaAsset = "ToolsModule:inspector_style_rollout_image"; category = "Editor"; }; singleton GuiControlProfile (inspectorStyleRolloutListProfile) { border = -2; category = "Editor"; - bitmap = "./inspector-style-rollout-list"; + bitmaAsset = "ToolsModule:inspector_style_rollout_list_image"; category = "Editor"; }; singleton GuiControlProfile (inspectorStyleRolloutDarkProfile) { border = -2; category = "Editor"; - bitmap = "./inspector-style-rollout-dark"; + bitmaAsset = "ToolsModule:inspector_style_rollout_dark_image"; fillColor = EditorSettings.value("Theme/windowBackgroundColor"); fontColor = EditorSettings.value("Theme/headerTextColor"); @@ -1486,14 +1486,14 @@ singleton GuiControlProfile (inspectorStyleRolloutInnerProfile) { border = -2; category = "Editor"; - bitmap = "./inspector-style-rollout_inner"; + bitmaAsset = "ToolsModule:inspector_style_rollout_inner_image"; category = "Editor"; }; singleton GuiControlProfile (inspectorStyleRolloutNoHeaderProfile) { border = -2; category = "Editor"; - bitmap = "./inspector-style-rollout-noheader"; + bitmaAsset = "ToolsModule:inspector_style_rollout_noheader_image"; category = "Editor"; }; singleton GuiControlProfile (IconDropdownProfile) @@ -1502,7 +1502,6 @@ singleton GuiControlProfile (IconDropdownProfile) opaque = true; border = true; category = "Editor"; - //bitmap = "./icon-dropdownbar"; fillColor = EditorSettings.value("Theme/headerColor"); }; diff --git a/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript b/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript index e0093acd1..f38f3b877 100644 --- a/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript +++ b/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript @@ -338,9 +338,9 @@ function RiverEditorGui::createRiver( %this ) baseColor = "45 108 171 255"; - rippleTex = "Core_Rendering:ripple_image"; - foamTex = "Core_Rendering:foam_image"; - depthGradientTex = "Core_Rendering:depthcolor_ramp_image"; + RippleTexAsset = "Core_Rendering:ripple_image"; + FoamTexAsset = "Core_Rendering:foam_image"; + DepthGradientTexAsset = "Core_Rendering:depthcolor_ramp_image"; }; return %river; diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui index 1e932ba7f..002f4b4fa 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui @@ -1534,7 +1534,7 @@ $guiContent = new GuiContainer(EditorGui,EditorGuiGroup) { internalName = "slider"; position = "9 17"; extent = "129 15"; - bitmap = "tools/gui/images/separator-h.png"; + bitmapAsset = "ToolsModule:separator_h_image"; HorizSizing = "width"; VertSizing = "bottom"; range = "1 200"; diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index 5b605c839..987f19663 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -1282,9 +1282,9 @@ function ObjectBuilderGui::addWaterObjectFields(%this) %this.addField("waveSpeed[2]", "TypeFloat", "Wave Speed", "1"); %this.addField("overallWaveMagnitude", "TypeFloat", "Overall Wave Magnitude", "1.0"); - %this.addField("rippleTex", "TypeImageAsset", "Ripple Texture", "Core_Rendering:ripple_image" ); - %this.addField("depthGradientTex", "TypeImageAsset", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_image" ); - %this.addField("foamTex", "TypeImageAsset", "Foam Texture", "Core_Rendering:foam_image" ); + %this.addField("RippleTexAsset", "TypeImageAssetPtrRefactor", "Ripple Texture", "Core_Rendering:ripple_image" ); + %this.addField("DepthGradientTexAsset", "TypeImageAssetPtrRefactor", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_image" ); + %this.addField("FoamTexAsset", "TypeImageAssetPtrRefactor", "Foam Texture", "Core_Rendering:foam_image" ); } function ObjectBuilderGui::buildWaterBlock(%this) From f519cff6ff932a71cfc0564b0d86cc82b8939d96 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 21 Dec 2024 23:02:23 +0000 Subject: [PATCH 04/47] gui types using image_asset --- Engine/source/gui/controls/guiBitmapCtrl.cpp | 209 +++++++++--------- Engine/source/gui/controls/guiBitmapCtrl.h | 66 +++--- .../gui/controls/guiGameSettingsCtrl.cpp | 27 +-- .../source/gui/controls/guiGameSettingsCtrl.h | 13 +- Engine/source/gui/core/guiTypes.cpp | 15 +- Engine/source/gui/core/guiTypes.h | 5 +- .../source/gui/game/guiChunkedBitmapCtrl.cpp | 18 +- Engine/source/gui/game/guiChunkedBitmapCtrl.h | 5 +- .../source/gui/game/guiProgressBitmapCtrl.cpp | 3 +- .../source/gui/game/guiProgressBitmapCtrl.h | 11 +- .../source/gui/worldEditor/guiMissionArea.cpp | 10 +- .../source/gui/worldEditor/guiMissionArea.h | 5 +- Engine/source/gui/worldEditor/worldEditor.cpp | 18 +- Engine/source/gui/worldEditor/worldEditor.h | 13 +- .../game/data/gameUI/GUIs/playGui.gui | 2 +- .../guis/assetPreviewButtonsTemplate.gui | 6 +- .../assetBrowser/scripts/assetBrowser.tscript | 2 +- .../game/tools/gui/materialSelector.ed.gui | 4 +- .../guiEditor/gui/EditorChooseGUI.ed.gui | 2 +- .../materialEditor/gui/Profiles.ed.tscript | 4 +- .../gui/guiMaterialPropertiesWindow.ed.gui | 2 +- .../guiMaterialPropertiesWindow.ed.gui.orig | 2 +- .../game/tools/navEditor/NavEditorToolbar.gui | 2 +- .../gui/EditorChooseLevelGui.ed.gui | 2 +- .../tools/worldEditor/gui/EditorGui.ed.gui | 4 +- 25 files changed, 184 insertions(+), 266 deletions(-) diff --git a/Engine/source/gui/controls/guiBitmapCtrl.cpp b/Engine/source/gui/controls/guiBitmapCtrl.cpp index 783942d08..58ec91ba9 100644 --- a/Engine/source/gui/controls/guiBitmapCtrl.cpp +++ b/Engine/source/gui/controls/guiBitmapCtrl.cpp @@ -34,15 +34,15 @@ IMPLEMENT_CONOBJECT(GuiBitmapCtrl); -ConsoleDocClass( GuiBitmapCtrl, +ConsoleDocClass(GuiBitmapCtrl, "@brief A gui control that is used to display an image.\n\n" - + "The image is stretched to the constraints of the control by default. However, the control can also\n" "tile the image as well.\n\n" "The image itself is stored inside the GuiBitmapCtrl::bitmap field. The boolean value that decides\n" "whether the image is stretched or tiled is stored inside the GuiBitmapCtrl::wrap field.\n" - + "@tsexample\n" "// Create a tiling GuiBitmapCtrl that displays \"myImage.png\"\n" "%bitmapCtrl = new GuiBitmapCtrl()\n" @@ -51,101 +51,87 @@ ConsoleDocClass( GuiBitmapCtrl, " wrap = \"true\";\n" "};\n" "@endtsexample\n\n" - + "@ingroup GuiControls" ); GuiBitmapCtrl::GuiBitmapCtrl(void) - : mStartPoint( 0, 0 ), + : mStartPoint(0, 0), mColor(ColorI::WHITE), mAngle(0), - mWrap( false ) + mWrap(false), + mBitmap(NULL), + mBitmapName(StringTable->EmptyString()) { - INIT_ASSET(Bitmap); -} - -bool GuiBitmapCtrl::setBitmapName( void *object, const char *index, const char *data ) -{ - // Prior to this, you couldn't do bitmap.bitmap = "foo.jpg" and have it work. - // With protected console types you can now call the setBitmap function and - // make it load the image. - static_cast( object )->setBitmap( data ); - - // Return false because the setBitmap method will assign 'mBitmapName' to the - // argument we are specifying in the call. - return false; } void GuiBitmapCtrl::initPersistFields() { docsURL; - addGroup( "Bitmap" ); + addGroup("Bitmap"); - addField("Bitmap", TypeImageFilename, Offset(mBitmapName, GuiBitmapCtrl), assetDoc(Bitmap, docs), AbstractClassRep::FIELD_HideInInspectors); - addField("BitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiBitmapCtrl), assetDoc(Bitmap, asset docs.)); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiBitmapCtrl, "The bitmap to render in this BitmapCtrl.") - addField("color", TypeColorI, Offset(mColor, GuiBitmapCtrl),"color mul"); - addField( "wrap", TypeBool, Offset( mWrap, GuiBitmapCtrl ), - "If true, the bitmap is tiled inside the control rather than stretched to fit." ); + addField("color", TypeColorI, Offset(mColor, GuiBitmapCtrl), "color mul"); + addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl), + "If true, the bitmap is tiled inside the control rather than stretched to fit."); - addField("angle", TypeF32, Offset(mAngle, GuiBitmapCtrl), "rotation"); - - endGroup( "Bitmap" ); + addField("angle", TypeF32, Offset(mAngle, GuiBitmapCtrl), "rotation"); + + endGroup("Bitmap"); Parent::initPersistFields(); } bool GuiBitmapCtrl::onWake() { - if (! Parent::onWake()) + if (!Parent::onWake()) return false; setActive(true); - if (mBitmapName != StringTable->insert("texhandle")) - setBitmap(getBitmap()); return true; } void GuiBitmapCtrl::onSleep() { - if ( mBitmapName != StringTable->insert("texhandle") ) - mBitmap = NULL; - Parent::onSleep(); } //------------------------------------- void GuiBitmapCtrl::inspectPostApply() { - //This is a little bit of a 'special case' handling for this class - //Because we don't do the normal protectedField setup for the bitmapName/bitmapAsset fields - //which would automatically update the internal values and bound content, we'll do it here manually - //to ensure it's updated before we force a refresh, which would thrash the new values - if (mBitmapName != StringTable->insert("texhandle")) - { - _setBitmap(mBitmapAssetId); - } - else - { - setBitmap(getBitmap()); - } - // if the extent is set to (0,0) in the gui editor and appy hit, this control will // set it's extent to be exactly the size of the bitmap (if present) Parent::inspectPostApply(); - if (!mWrap && (getExtent().x == 0) && (getExtent().y == 0) && mBitmap) + if (!mWrap && (getExtent().x == 0) && (getExtent().y == 0) && mBitmapAsset.notNull()) { - setExtent( mBitmap->getWidth(), mBitmap->getHeight()); + setExtent(mBitmap->getWidth(), mBitmap->getHeight()); } } -void GuiBitmapCtrl::setBitmap( const char *name, bool resize ) +void GuiBitmapCtrl::setBitmap(const char* name, bool resize) { - _setBitmap(StringTable->insert(name)); - - if (mBitmap && resize) + // coming in here we are probably getting a filename. + if (AssetDatabase.isDeclaredAsset(name)) { + _setBitmap(StringTable->insert(name)); + } + else + { + StringTableEntry assetId = ImageAsset::getAssetIdByFilename(StringTable->insert(name)); + + if (assetId != StringTable->EmptyString()) + _setBitmap(assetId); + else + return; + } + + mBitmap = mBitmapAsset->getTexture(&GFXDefaultGUIProfile); + + if (mBitmapAsset.notNull() && resize) + { + setExtent(mBitmap->getWidth(), mBitmap->getHeight()); updateSizing(); } @@ -153,15 +139,6 @@ void GuiBitmapCtrl::setBitmap( const char *name, bool resize ) setUpdate(); } -void GuiBitmapCtrl::updateSizing() -{ - if(!getParent()) - return; - // updates our bounds according to our horizSizing and verSizing rules - RectI fakeBounds( getPosition(), getParent()->getExtent()); - parentResized( fakeBounds, fakeBounds); -} - void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize) { mBitmap = handle; @@ -169,46 +146,58 @@ void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize) mBitmapName = StringTable->insert("texhandle"); // Resize the control to fit the bitmap - if (resize) + if (resize) { setExtent(mBitmap->getWidth(), mBitmap->getHeight()); updateSizing(); } } -void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) +void GuiBitmapCtrl::updateSizing() { + if (!getParent()) + return; + // updates our bounds according to our horizSizing and verSizing rules + RectI fakeBounds(getPosition(), getParent()->getExtent()); + parentResized(fakeBounds, fakeBounds); +} + +void GuiBitmapCtrl::onRender(Point2I offset, const RectI& updateRect) +{ + if (mBitmap.isNull() && mBitmapAsset.notNull()) + mBitmap = getBitmap(); + if (mBitmap) { GFX->getDrawUtil()->clearBitmapModulation(); GFX->getDrawUtil()->setBitmapModulation(mColor); - if(mWrap) - { + if (mWrap) + { // We manually draw each repeat because non power of two textures will // not tile correctly when rendered with GFX->drawBitmapTile(). The non POT // bitmap will be padded by the hardware, and we'll see lots of slack // in the texture. So... lets do what we must: draw each repeat by itself: - GFXTextureObject* texture = mBitmap; - RectI srcRegion; - RectI dstRegion; - F32 xdone = ((F32)getExtent().x/(F32)texture->mBitmapSize.x)+1; - F32 ydone = ((F32)getExtent().y/(F32)texture->mBitmapSize.y)+1; + GFXTextureObject* texture = mBitmap; + RectI srcRegion; + RectI dstRegion; + F32 xdone = ((F32)getExtent().x / (F32)texture->mBitmapSize.x) + 1; + F32 ydone = ((F32)getExtent().y / (F32)texture->mBitmapSize.y) + 1; - S32 xshift = mStartPoint.x%texture->mBitmapSize.x; - S32 yshift = mStartPoint.y%texture->mBitmapSize.y; - for(S32 y = 0; y < ydone; ++y) - for(S32 x = 0; x < xdone; ++x) - { - srcRegion.set(0,0,texture->mBitmapSize.x,texture->mBitmapSize.y); - dstRegion.set( ((texture->mBitmapSize.x*x)+offset.x)-xshift, - ((texture->mBitmapSize.y*y)+offset.y)-yshift, - texture->mBitmapSize.x, - texture->mBitmapSize.y); + S32 xshift = mStartPoint.x % texture->mBitmapSize.x; + S32 yshift = mStartPoint.y % texture->mBitmapSize.y; + for (S32 y = 0; y < ydone; ++y) + for (S32 x = 0; x < xdone; ++x) + { + srcRegion.set(0, 0, texture->mBitmapSize.x, texture->mBitmapSize.y); + dstRegion.set(((texture->mBitmapSize.x * x) + offset.x) - xshift, + ((texture->mBitmapSize.y * y) + offset.y) - yshift, + texture->mBitmapSize.x, + texture->mBitmapSize.y); GFX->getDrawUtil()->drawBitmapStretchSR(texture, dstRegion, srcRegion, GFXBitmapFlip_None, GFXTextureFilterLinear, mAngle); - } + } - } - else + } + else { RectI rect(offset, getExtent()); GFX->getDrawUtil()->drawBitmapStretch(mBitmap, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false, mAngle); @@ -226,21 +215,21 @@ void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) void GuiBitmapCtrl::setValue(S32 x, S32 y) { - if (mBitmap) + if (mBitmapAsset.notNull()) { - x += mBitmap->getWidth() / 2; - y += mBitmap->getHeight() / 2; - } - while (x < 0) - x += 256; - mStartPoint.x = x % 256; + x += mBitmapAsset->getTextureBitmapWidth() / 2; + y += mBitmapAsset->getTextureBitmapHeight() / 2; + } + while (x < 0) + x += 256; + mStartPoint.x = x % 256; - while (y < 0) - y += 256; - mStartPoint.y = y % 256; + while (y < 0) + y += 256; + mStartPoint.y = y % 256; } -DefineEngineMethod( GuiBitmapCtrl, setValue, void, ( S32 x, S32 y ),, +DefineEngineMethod(GuiBitmapCtrl, setValue, void, (S32 x, S32 y), , "Set the offset of the bitmap within the control.\n" "@param x The x-axis offset of the image.\n" "@param y The y-axis offset of the image.\n") @@ -257,7 +246,7 @@ static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap1( "@param filename The filename of the image.\n" "@param resize Optional parameter. If true, the GUI will resize to fit the image.", "GuiBitmapCtrl", // The class to place the method in; use NULL for functions. - "void setBitmap( String filename, bool resize );" ); // The definition string. + "void setBitmap( String filename, bool resize );"); // The definition string. static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap2( "@brief Assign an image to the control.\n\n" @@ -265,42 +254,42 @@ static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap2( "@param filename The filename of the image.\n" "@param resize A boolean value that decides whether the ctrl refreshes or not.", "GuiBitmapCtrl", // The class to place the method in; use NULL for functions. - "void setBitmap( String filename );" ); // The definition string. + "void setBitmap( String filename );"); // The definition string. //"Set the bitmap displayed in the control. Note that it is limited in size, to 256x256." -DefineEngineMethod( GuiBitmapCtrl, setBitmap, void, ( const char * fileRoot, bool resize), ( false), +DefineEngineMethod(GuiBitmapCtrl, setBitmap, void, (const char* fileRoot, bool resize), (false), "( String filename | String filename, bool resize ) Assign an image to the control.\n\n" - "@hide" ) + "@hide") { char filename[1024]; Con::expandScriptFilename(filename, sizeof(filename), fileRoot); - object->setBitmap(filename, resize ); + object->setBitmap(filename, resize); } -DefineEngineMethod(GuiBitmapCtrl, getBitmap, const char*, (),, +DefineEngineMethod(GuiBitmapCtrl, getBitmap, const char*, (), , "Gets the current bitmap set for this control.\n\n" "@hide") { - return object->getBitmap(); + return object->_getBitmap(); } -DefineEngineMethod( GuiBitmapCtrl, setNamedTexture, bool, (String namedtexture),, +DefineEngineMethod(GuiBitmapCtrl, setNamedTexture, bool, (String namedtexture), , "@brief Set a texture as the image.\n\n" "@param namedtexture The name of the texture (NamedTexTarget).\n" - "@return true if the texture exists." ) + "@return true if the texture exists.") { GFXTexHandle theTex; - NamedTexTarget *namedTarget = NULL; + NamedTexTarget* namedTarget = NULL; namedTarget = NamedTexTarget::find(namedtexture.c_str()); - if ( namedTarget ) + if (namedTarget) { - theTex = namedTarget->getTexture( 0 ); + theTex = namedTarget->getTexture(0); } - - if ( theTex.isValid() ) + + if (theTex.isValid()) { - object->setBitmapHandle( theTex , false ); + object->setBitmapHandle(theTex, false); return true; //a new texture was set correctly } return false; //we couldn't change the texture diff --git a/Engine/source/gui/controls/guiBitmapCtrl.h b/Engine/source/gui/controls/guiBitmapCtrl.h index b641fd5a2..c953fb3b1 100644 --- a/Engine/source/gui/controls/guiBitmapCtrl.h +++ b/Engine/source/gui/controls/guiBitmapCtrl.h @@ -31,51 +31,47 @@ /// Renders a bitmap. class GuiBitmapCtrl : public GuiControl { - public: - - typedef GuiControl Parent; +public: - protected: - - /// Name of the bitmap file. If this is 'texhandle' the bitmap is not loaded - /// from a file but rather set explicitly on the control. - DECLARE_IMAGEASSET(GuiBitmapCtrl, Bitmap, onImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiBitmapCtrl, Bitmap); - - Point2I mStartPoint; - ColorI mColor; - F32 mAngle; + typedef GuiControl Parent; - /// If true, bitmap tiles inside control. Otherwise stretches. - bool mWrap; +protected: - static bool setBitmapName( void *object, const char *index, const char *data ); - static const char *getBitmapName( void *obj, const char *data ); + /// Name of the bitmap file. If this is 'texhandle' the bitmap is not loaded + /// from a file but rather set explicitly on the control. + DECLARE_IMAGEASSET_REFACTOR(GuiBitmapCtrl, Bitmap, GFXDefaultGUIProfile) - void onImageChanged() {} + Point2I mStartPoint; + ColorI mColor; + F32 mAngle; - public: - - GuiBitmapCtrl(); - static void initPersistFields(); + /// If true, bitmap tiles inside control. Otherwise stretches. + bool mWrap; - void setBitmap(const char *name,bool resize = false); - void setBitmapHandle(GFXTexHandle handle, bool resize = false); +public: + GFXTexHandle mBitmap; + StringTableEntry mBitmapName; - // GuiControl. - bool onWake() override; - void onSleep() override; - void inspectPostApply() override; + GuiBitmapCtrl(); + static void initPersistFields(); - void updateSizing(); + // GuiControl. + bool onWake() override; + void onSleep() override; + void inspectPostApply() override; - void onRender(Point2I offset, const RectI &updateRect) override; - void setValue(S32 x, S32 y); + void setBitmap(const char* name, bool resize = true); + void setBitmapHandle(GFXTexHandle handle, bool resize = false); - DECLARE_CONOBJECT( GuiBitmapCtrl ); - DECLARE_CATEGORY( "Gui Images" ); - DECLARE_DESCRIPTION( "A control that displays a single, static image from a file.n" - "The bitmap can either be tiled or stretched inside the control." ); + void updateSizing(); + + void onRender(Point2I offset, const RectI& updateRect) override; + void setValue(S32 x, S32 y); + + DECLARE_CONOBJECT(GuiBitmapCtrl); + DECLARE_CATEGORY("Gui Images"); + DECLARE_DESCRIPTION("A control that displays a single, static image from a file.n" + "The bitmap can either be tiled or stretched inside the control."); }; #endif diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp index fff03c24b..ef68c38ca 100644 --- a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp @@ -59,10 +59,6 @@ GuiGameSettingsCtrl::GuiGameSettingsCtrl() : mCallbackOnB = mCallbackOnA; mCallbackOnX = mCallbackOnA; mCallbackOnY = mCallbackOnA; - - INIT_ASSET(KeybindBitmap); - INIT_ASSET(PreviousBitmap); - INIT_ASSET(NextBitmap); } GuiGameSettingsCtrl::~GuiGameSettingsCtrl() @@ -193,7 +189,7 @@ void GuiGameSettingsCtrl::onRenderListOption(Point2I currentOffset) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretch(mPreviousBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + drawer->drawBitmapStretch(getPreviousBitmap(), RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); } else { @@ -214,7 +210,7 @@ void GuiGameSettingsCtrl::onRenderListOption(Point2I currentOffset) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretch(mNextBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + drawer->drawBitmapStretch(getNextBitmap(), RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); } else { @@ -376,7 +372,7 @@ void GuiGameSettingsCtrl::onRenderKeybindOption(Point2I currentOffset) { RectI rect(button, buttonSize); drawer->clearBitmapModulation(); - drawer->drawBitmapStretch(mKeybindBitmap, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false); + drawer->drawBitmapStretch(getKeybindBitmap(), rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false); } //drawer->drawRectFill(button, ColorI::BLUE); @@ -454,22 +450,11 @@ bool GuiGameSettingsCtrl::onWake() if( !Parent::onWake() ) return false; - _setNextBitmap(getNextBitmap()); - _setPreviousBitmap(getPreviousBitmap()); - _setKeybindBitmap(getKeybindBitmap()); - return true; } void GuiGameSettingsCtrl::onSleep() { - if (mNextBitmapAsset.notNull()) - mNextBitmap = NULL; - if (mPreviousBitmapAsset.notNull()) - mPreviousBitmap = NULL; - if (mKeybindBitmapAsset.notNull()) - mKeybindBitmap = NULL; - Parent::onSleep(); } @@ -840,9 +825,9 @@ IMPLEMENT_CALLBACK(GuiGameSettingsCtrl, onAxisEvent, void, (const char* device, void GuiGameSettingsCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(KeybindBitmap, GuiGameSettingsCtrl, "Bitmap used to display the bound key for this keybind option."); - INITPERSISTFIELD_IMAGEASSET(PreviousBitmap, GuiGameSettingsCtrl, "Bitmap used for the previous button when in list mode."); - INITPERSISTFIELD_IMAGEASSET(NextBitmap, GuiGameSettingsCtrl, "Bitmap used for the next button when in list mode."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(KeybindBitmap, GuiGameSettingsCtrl, "Bitmap used to display the bound key for this keybind option."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(PreviousBitmap, GuiGameSettingsCtrl, "Bitmap used for the previous button when in list mode."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(NextBitmap, GuiGameSettingsCtrl, "Bitmap used for the next button when in list mode."); addField("arrowSize", TypeS32, Offset(mArrowSize, GuiGameSettingsCtrl), "Size of the arrow buttons' extents"); diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.h b/Engine/source/gui/controls/guiGameSettingsCtrl.h index 737761745..dbcdc5efc 100644 --- a/Engine/source/gui/controls/guiGameSettingsCtrl.h +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.h @@ -72,14 +72,9 @@ protected: Point2F mRange; ///< When working as a slider, this sets our min/max range //Keybind option - DECLARE_IMAGEASSET(GuiGameSettingsCtrl, KeybindBitmap, changeBitmap, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, KeybindBitmap); - - DECLARE_IMAGEASSET(GuiGameSettingsCtrl, PreviousBitmap, changeBitmap, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, PreviousBitmap); - - DECLARE_IMAGEASSET(GuiGameSettingsCtrl, NextBitmap, changeBitmap, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, NextBitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, KeybindBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, PreviousBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, NextBitmap, GFXDefaultGUIProfile) S32 mArrowSize; S32 mColumnSplit; //Padding between the leftmost edge of the control, and the left side of the 'option'. @@ -89,8 +84,6 @@ protected: bool mSelected; public: - void changeBitmap() {} - /// Sets the control as selected . Only controls that are enabled can be selected. virtual void setSelected(); diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index 5c1e11359..db85c628a 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -78,8 +78,6 @@ GuiCursor::GuiCursor() mHotSpot.set(0,0); mRenderOffset.set(0.0f,0.0f); mExtent.set(1,1); - - INIT_ASSET(Bitmap); } GuiCursor::~GuiCursor() @@ -92,8 +90,7 @@ void GuiCursor::initPersistFields() addField("hotSpot", TypePoint2I, Offset(mHotSpot, GuiCursor), "The location of the cursor's hot spot (which pixel carries the click)."); addField("renderOffset",TypePoint2F, Offset(mRenderOffset, GuiCursor), "Offset of the bitmap, where 0 signifies left edge of the bitmap, 1, the right. Similarly for the Y-component."); - addProtectedField("bitmapName", TypeImageFilename, Offset(mBitmapName, GuiCursor), _setBitmapData, &defaultProtectedGetFn, "File name of the bitmap for the cursor."); - INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiCursor, "name of the bitmap for the cursor."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiCursor, "name of the bitmap for the cursor."); Parent::initPersistFields(); } @@ -114,21 +111,21 @@ void GuiCursor::onRemove() void GuiCursor::render(const Point2I &pos) { - if (mBitmap) + if (mBitmapAsset.notNull()) { - mExtent.set(mBitmap->getWidth(), mBitmap->getHeight()); + mExtent.set(getBitmap()->getWidth(), getBitmap()->getHeight()); } // Render the cursor centered according to dimensions of texture - S32 texWidth = mBitmap.getWidth(); - S32 texHeight = mBitmap.getHeight(); + S32 texWidth = getBitmap()->getWidth(); + S32 texHeight = getBitmap()->getHeight(); Point2I renderPos = pos; renderPos.x -= (S32)( texWidth * mRenderOffset.x ); renderPos.y -= (S32)( texHeight * mRenderOffset.y ); GFX->getDrawUtil()->clearBitmapModulation(); - GFX->getDrawUtil()->drawBitmap(mBitmap, renderPos); + GFX->getDrawUtil()->drawBitmap(getBitmap(), renderPos); } //------------------------------------------------------------------------------ diff --git a/Engine/source/gui/core/guiTypes.h b/Engine/source/gui/core/guiTypes.h index 759b857bc..7acb37fd7 100644 --- a/Engine/source/gui/core/guiTypes.h +++ b/Engine/source/gui/core/guiTypes.h @@ -348,8 +348,7 @@ class GuiCursor : public SimObject private: typedef SimObject Parent; - DECLARE_IMAGEASSET(GuiCursor, Bitmap, onImageChanged, GFXGuiCursorProfile); - DECLARE_ASSET_SETGET(GuiCursor, Bitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiCursor, Bitmap, GFXGuiCursorProfile) Point2I mHotSpot; Point2F mRenderOffset; @@ -367,8 +366,6 @@ public: bool onAdd(void) override; void onRemove() override; void render(const Point2I &pos); - - void onImageChanged() {} }; /// A GuiControlProfile is used by every GuiObject and is akin to a diff --git a/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp b/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp index 4aab2a247..07883e246 100644 --- a/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp +++ b/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp @@ -67,7 +67,7 @@ void GuiChunkedBitmapCtrl::initPersistFields() { docsURL; addGroup("GuiChunkedBitmapCtrl"); - INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiChunkedBitmapCtrl, "This is the bitmap to render to the control."); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiChunkedBitmapCtrl, "This is the bitmap to render to the control."); addField( "useVariable", TypeBool, Offset( mUseVariable, GuiChunkedBitmapCtrl ), "This decides whether to use the \"bitmap\" file " "or a bitmap stored in \"variable\""); @@ -88,8 +88,6 @@ DefineEngineMethod( GuiChunkedBitmapCtrl, setBitmap, void, (const char* filename GuiChunkedBitmapCtrl::GuiChunkedBitmapCtrl() { - INIT_ASSET(Bitmap); - mUseVariable = false; mTile = false; } @@ -112,16 +110,6 @@ bool GuiChunkedBitmapCtrl::onWake() if(!Parent::onWake()) return false; - if( !mBitmap - && ( ( mBitmapName && mBitmapName[ 0 ] ) - || ( mUseVariable && mConsoleVariable && mConsoleVariable[ 0 ] ) ) ) - { - if ( mUseVariable ) - mBitmap.set( Con::getVariable( mConsoleVariable ), &GFXDefaultGUIProfile, avar("%s() - mTexHandle (line %d)", __FUNCTION__, __LINE__) ); - else - mBitmap.set( mBitmapName, &GFXDefaultGUIProfile, avar("%s() - mTexHandle (line %d)", __FUNCTION__, __LINE__) ); - } - return true; } @@ -167,10 +155,10 @@ void GuiChunkedBitmapCtrl::renderRegion(const Point2I &offset, const Point2I &ex void GuiChunkedBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) { - if( mBitmap ) + if( mBitmapAsset.notNull() ) { RectI boundsRect( offset, getExtent()); - GFX->getDrawUtil()->drawBitmapStretch(mBitmap, boundsRect, GFXBitmapFlip_None, GFXTextureFilterLinear ); + GFX->getDrawUtil()->drawBitmapStretch(getBitmap(), boundsRect, GFXBitmapFlip_None, GFXTextureFilterLinear); } renderChildControls(offset, updateRect); diff --git a/Engine/source/gui/game/guiChunkedBitmapCtrl.h b/Engine/source/gui/game/guiChunkedBitmapCtrl.h index 08db54166..077087991 100644 --- a/Engine/source/gui/game/guiChunkedBitmapCtrl.h +++ b/Engine/source/gui/game/guiChunkedBitmapCtrl.h @@ -17,8 +17,7 @@ private: protected: - DECLARE_IMAGEASSET(GuiChunkedBitmapCtrl, Bitmap, onImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiChunkedBitmapCtrl, Bitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiChunkedBitmapCtrl, Bitmap, GFXDefaultGUIProfile) bool mUseVariable; bool mTile; @@ -38,6 +37,4 @@ public: void setBitmap(const char *name); void onRender(Point2I offset, const RectI &updateRect) override; - - void onImageChanged() {} }; diff --git a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp index 0d85213e1..7cdda0f03 100644 --- a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp +++ b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp @@ -124,7 +124,6 @@ GuiProgressBitmapCtrl::GuiProgressBitmapCtrl() mNumberOfBitmaps(0), mDim(0) { - INIT_ASSET(Bitmap); } //----------------------------------------------------------------------------- @@ -132,7 +131,7 @@ GuiProgressBitmapCtrl::GuiProgressBitmapCtrl() void GuiProgressBitmapCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiProgressBitmapCtrl, "Bitmap file to use for rendering the progress bar.\n\n" + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiProgressBitmapCtrl, "Bitmap file to use for rendering the progress bar.\n\n" "If the profile assigned to the control already has a bitmap assigned, this property need not be " "set in which case the bitmap from the profile is used."); diff --git a/Engine/source/gui/game/guiProgressBitmapCtrl.h b/Engine/source/gui/game/guiProgressBitmapCtrl.h index 54c702f19..6d8f1bd52 100644 --- a/Engine/source/gui/game/guiProgressBitmapCtrl.h +++ b/Engine/source/gui/game/guiProgressBitmapCtrl.h @@ -47,21 +47,12 @@ class GuiProgressBitmapCtrl : public GuiTextCtrl F32 mProgress; - DECLARE_IMAGEASSET(GuiProgressBitmapCtrl, Bitmap, onImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiProgressBitmapCtrl, Bitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiProgressBitmapCtrl, Bitmap, GFXDefaultGUIProfile) bool mUseVariable; bool mTile; S32 mNumberOfBitmaps; S32 mDim; - - static bool _setBitmap( void* object, const char* index, const char* data ) - { - static_cast< GuiProgressBitmapCtrl* >( object )->setBitmap( data ); - return false; - } - - void onImageChanged() {} public: diff --git a/Engine/source/gui/worldEditor/guiMissionArea.cpp b/Engine/source/gui/worldEditor/guiMissionArea.cpp index 9302c12b0..c951ea8b9 100644 --- a/Engine/source/gui/worldEditor/guiMissionArea.cpp +++ b/Engine/source/gui/worldEditor/guiMissionArea.cpp @@ -59,8 +59,6 @@ ConsoleDocClass( GuiMissionAreaCtrl, GuiMissionAreaCtrl::GuiMissionAreaCtrl() { - INIT_ASSET(HandleBitmap); - mHandleTextureSize = Point2I::Zero; mHandleTextureHalfSize = Point2F::Zero; @@ -90,7 +88,7 @@ void GuiMissionAreaCtrl::initPersistFields() docsURL; addField( "squareBitmap", TypeBool, Offset(mSquareBitmap, GuiMissionAreaCtrl)); - INITPERSISTFIELD_IMAGEASSET(HandleBitmap, GuiMissionAreaCtrl, "Bitmap for the mission area handles.\n"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(HandleBitmap, GuiMissionAreaCtrl, "Bitmap for the mission area handles.\n"); addField( "missionBoundsColor", TypeColorI, Offset(mMissionBoundsColor, GuiMissionAreaCtrl)); addField( "cameraColor", TypeColorI, Offset(mCameraColor, GuiMissionAreaCtrl)); @@ -114,9 +112,9 @@ bool GuiMissionAreaCtrl::onAdd() desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); mBlendStateBlock = GFX->createStateBlock( desc ); - if (!mHandleBitmap.isNull()) + if (!mHandleBitmapAsset.isNull()) { - mHandleTextureSize = Point2I(mHandleBitmap->getWidth(), mHandleBitmap->getHeight() ); + mHandleTextureSize = Point2I(getHandleBitmap()->getWidth(), getHandleBitmap()->getHeight()); mHandleTextureHalfSize = Point2F(mHandleTextureSize.x, mHandleTextureSize.y) * 0.5f; } else @@ -418,7 +416,7 @@ void GuiMissionAreaCtrl::setArea(const RectI & area) void GuiMissionAreaCtrl::drawHandle(const Point2F & pos) { Point2F pnt(pos.x-mHandleTextureHalfSize.x, pos.y-mHandleTextureHalfSize.y); - GFX->getDrawUtil()->drawBitmap(mHandleBitmap, pnt); + GFX->getDrawUtil()->drawBitmap(getHandleBitmap(), pnt); } void GuiMissionAreaCtrl::drawHandles(RectI & box) diff --git a/Engine/source/gui/worldEditor/guiMissionArea.h b/Engine/source/gui/worldEditor/guiMissionArea.h index 97c9013c5..6400e248d 100644 --- a/Engine/source/gui/worldEditor/guiMissionArea.h +++ b/Engine/source/gui/worldEditor/guiMissionArea.h @@ -63,8 +63,7 @@ protected: GFXStateBlockRef mBlendStateBlock; GFXStateBlockRef mSolidStateBlock; - DECLARE_IMAGEASSET(GuiMissionAreaCtrl, HandleBitmap, onHandleBitmapChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiMissionAreaCtrl, HandleBitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiMissionAreaCtrl, HandleBitmap, GFXDefaultGUIProfile) Point2I mHandleTextureSize; Point2F mHandleTextureHalfSize; @@ -110,8 +109,6 @@ protected: bool testWithinHandle(const Point2I & testPoint, S32 handleX, S32 handleY); S32 getHitHandles(const Point2I & mousePnt, const RectI & box); - void onHandleBitmapChanged() {} - public: GuiMissionAreaCtrl(); virtual ~GuiMissionAreaCtrl(); diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index a67b4ec7d..5b1ab494d 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -1817,9 +1817,9 @@ WorldEditor::WorldEditor() mPopupBackgroundColor.set(100,100,100); mPopupTextColor.set(255,255,0); - mSelectHandleAssetId = StringTable->insert("ToolsModule:SelectHandle"); - mDefaultHandleAssetId = StringTable->insert("ToolsModule:DefaultHandle"); - mLockedHandleAssetId = StringTable->insert("ToolsModule:LockedHandle"); + mSelectHandleAsset = StringTable->insert("ToolsModule:SelectHandle_image"); + mDefaultHandleAsset = StringTable->insert("ToolsModule:DefaultHandle_image"); + mLockedHandleAsset = StringTable->insert("ToolsModule:LockedHandle_image"); mObjectTextColor.set(255,255,255); mObjectsUseBoxCenter = true; @@ -1905,9 +1905,9 @@ bool WorldEditor::onAdd() // create the default class entry mDefaultClassEntry.mName = 0; mDefaultClassEntry.mIgnoreCollision = false; - mDefaultClassEntry.mDefaultHandle = mDefaultHandle; - mDefaultClassEntry.mSelectHandle = mSelectHandle; - mDefaultClassEntry.mLockedHandle = mLockedHandle; + mDefaultClassEntry.mDefaultHandle = getDefaultHandle(); + mDefaultClassEntry.mSelectHandle = getSelectHandle(); + mDefaultClassEntry.mLockedHandle = getLockedHandle(); if(!(mDefaultClassEntry.mDefaultHandle && mDefaultClassEntry.mSelectHandle && mDefaultClassEntry.mLockedHandle)) return false; @@ -2839,9 +2839,9 @@ void WorldEditor::initPersistFields() addField( "renderObjHandle", TypeBool, Offset(mRenderObjHandle, WorldEditor) ); addField( "renderSelectionBox", TypeBool, Offset(mRenderSelectionBox, WorldEditor) ); - INITPERSISTFIELD_IMAGEASSET(SelectHandle, WorldEditor, ""); - INITPERSISTFIELD_IMAGEASSET(DefaultHandle, WorldEditor, ""); - INITPERSISTFIELD_IMAGEASSET(LockedHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(SelectHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(DefaultHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(LockedHandle, WorldEditor, ""); endGroup( "Rendering" ); diff --git a/Engine/source/gui/worldEditor/worldEditor.h b/Engine/source/gui/worldEditor/worldEditor.h index 3cac2d0ce..f11e23c1a 100644 --- a/Engine/source/gui/worldEditor/worldEditor.h +++ b/Engine/source/gui/worldEditor/worldEditor.h @@ -328,12 +328,9 @@ class WorldEditor : public EditTSCtrl ColorI mPopupBackgroundColor; ColorI mPopupTextColor; - DECLARE_IMAGEASSET(WorldEditor, SelectHandle, onSelectHandleChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(WorldEditor, SelectHandle); - DECLARE_IMAGEASSET(WorldEditor, DefaultHandle, onDefaultHandleChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(WorldEditor, DefaultHandle); - DECLARE_IMAGEASSET(WorldEditor, LockedHandle, onLockedHandleChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(WorldEditor, LockedHandle); + DECLARE_IMAGEASSET_REFACTOR(WorldEditor, SelectHandle, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET_REFACTOR(WorldEditor, DefaultHandle, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET_REFACTOR(WorldEditor, LockedHandle, GFXStaticTextureSRGBProfile) ColorI mObjectTextColor; bool mObjectsUseBoxCenter; @@ -425,10 +422,6 @@ class WorldEditor : public EditTSCtrl void setEditorTool(EditorTool*); EditorTool* getActiveEditorTool() { return mActiveEditorTool; } - - void onSelectHandleChanged() {} - void onDefaultHandleChanged() {} - void onLockedHandleChanged() {} }; typedef WorldEditor::DropType WorldEditorDropType; diff --git a/Templates/BaseGame/game/data/gameUI/GUIs/playGui.gui b/Templates/BaseGame/game/data/gameUI/GUIs/playGui.gui index 4783b51a7..faeea23b5 100644 --- a/Templates/BaseGame/game/data/gameUI/GUIs/playGui.gui +++ b/Templates/BaseGame/game/data/gameUI/GUIs/playGui.gui @@ -28,7 +28,7 @@ $guiContent = new GameTSCtrl(PlayGui) { noCursor = "1"; new GuiBitmapCtrl(LagIcon) { - bitmap = "data/ui/art/lagIcon.png"; + bitmapAsset = "UI:lagIcon_image"; color = "255 255 255 255"; wrap = "0"; position = "572 3"; diff --git a/Templates/BaseGame/game/tools/assetBrowser/guis/assetPreviewButtonsTemplate.gui b/Templates/BaseGame/game/tools/assetBrowser/guis/assetPreviewButtonsTemplate.gui index 803f71ba5..53dc12dcb 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/guis/assetPreviewButtonsTemplate.gui +++ b/Templates/BaseGame/game/tools/assetBrowser/guis/assetPreviewButtonsTemplate.gui @@ -68,7 +68,7 @@ $guiContent = new GuiControl(AssetPreviewButtonsTemplate) { canSaveDynamicFields = "0"; new GuiBitmapButtonCtrl() { - bitmap = "tools/materialEditor/gui/cubemapBtnBorder"; + bitmapAsset = "ToolsModule:cubemapBtnBorder_n_image"; bitmapMode = "Stretched"; autoFitExtents = "0"; useModifiers = "0"; @@ -163,7 +163,7 @@ $guiContent = new GuiControl(AssetPreviewButtonsTemplate) { canSaveDynamicFields = "0"; new GuiBitmapButtonCtrl() { - bitmap = "Data/Blockout_Basics/Walls/WallGrid2x2_Albedo.png"; + bitmapAsset = "Data/Blockout_Basics/Walls/WallGrid2x2_Albedo.png"; bitmapMode = "Stretched"; autoFitExtents = "0"; useModifiers = "0"; @@ -188,7 +188,7 @@ $guiContent = new GuiControl(AssetPreviewButtonsTemplate) { canSaveDynamicFields = "0"; new GuiBitmapButtonCtrl() { - bitmap = "tools/materialEditor/gui/cubemapBtnBorder"; + bitmapAsset = "ToolsModule:cubemapBtnBorder_n_image"; bitmapMode = "Stretched"; autoFitExtents = "0"; useModifiers = "0"; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index 2575fb772..1fc3b3efd 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -2565,7 +2565,7 @@ function GuiEditor::onControlDropped(%this, %payload, %position) { %cmd = "return new guiBitmapCtrl();"; %ctrl = eval( %cmd ); - %ctrl.bitmap = %assetId; + %ctrl.bitmapAsset = %assetId; } } } diff --git a/Templates/BaseGame/game/tools/gui/materialSelector.ed.gui b/Templates/BaseGame/game/tools/gui/materialSelector.ed.gui index a1e263b2a..3575f4148 100644 --- a/Templates/BaseGame/game/tools/gui/materialSelector.ed.gui +++ b/Templates/BaseGame/game/tools/gui/materialSelector.ed.gui @@ -136,7 +136,7 @@ new GuiControl(MaterialSelectorOverlay, EditorGuiGroup) { Command = "MaterialSelector.createNewMaterial();"; hovertime = "1000"; tooltip = "Create New Unmapped Material"; - bitmap = "tools/gui/images/new"; + bitmapAsset = "ToolsModule:new_n_image"; groupNum = "-1"; buttonType = "PushButton"; useMouseEvents = "0"; @@ -1649,7 +1649,7 @@ function MaterialSelector::createNewMaterial( %this ) position = "7 4"; extent = "64 64"; buttonType = "PushButton"; - bitmap = "core/images/warnmat"; + bitmapAsset = "CoreModule:warnMat_image"; Command = ""; text = "Loading..."; useStates = false; diff --git a/Templates/BaseGame/game/tools/guiEditor/gui/EditorChooseGUI.ed.gui b/Templates/BaseGame/game/tools/guiEditor/gui/EditorChooseGUI.ed.gui index 212cbf94a..80a2f75f1 100644 --- a/Templates/BaseGame/game/tools/guiEditor/gui/EditorChooseGUI.ed.gui +++ b/Templates/BaseGame/game/tools/guiEditor/gui/EditorChooseGUI.ed.gui @@ -13,7 +13,7 @@ $guiContent = new GuiChunkedBitmapCtrl(EditorChooseGUI, EditorGuiGroup) { Visible = "1"; tooltipprofile = "ToolsGuiToolTipProfile"; hovertime = "1000"; - bitmap = "data/ui/images/background.png"; + bitmapAsset = "UI:background_image"; useVariable = "0"; tile = "0"; diff --git a/Templates/BaseGame/game/tools/materialEditor/gui/Profiles.ed.tscript b/Templates/BaseGame/game/tools/materialEditor/gui/Profiles.ed.tscript index a9f67ad6a..a8d2eb36e 100644 --- a/Templates/BaseGame/game/tools/materialEditor/gui/Profiles.ed.tscript +++ b/Templates/BaseGame/game/tools/materialEditor/gui/Profiles.ed.tscript @@ -24,7 +24,7 @@ singleton GuiControlProfile (GuiMatEdSliderProfile) { - bitmap = "./matEdSlider"; + bitmapAsset = "ToolsModule:slider_image"; category = "Editor"; }; @@ -47,9 +47,7 @@ singleton GuiControlProfile(GuiMatEdPopUpMenuProfile) mouseOverSelected = true; textOffset = "3 3"; border = 1; - /*borderThickness = 1;*/ fixedExtent = true; - //bitmap = "./images/scrollbar"; bitmapAsset = "ToolsModule:scroll_image"; hasBitmapArray = true; profileForChildren = GuiControlListPopupProfile; diff --git a/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui b/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui index 953da034f..0404faebe 100644 --- a/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui +++ b/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui @@ -4821,7 +4821,7 @@ $guiContent = new GuiControl(MaterialEditorGui,EditorGuiGroup) { tooltipprofile = "ToolsGuiToolTipProfile"; buttonType = "PushButton"; useMouseEvents = "0"; - bitmap = "ToolsModule:new_n_image"; + bitmapAsset = "ToolsModule:new_n_image"; }; // Save Button new GuiBitmapButtonCtrl() { diff --git a/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui.orig b/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui.orig index f7365bbc4..5f02923f1 100644 --- a/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui.orig +++ b/Templates/BaseGame/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui.orig @@ -4846,7 +4846,7 @@ $guiContent = new GuiControl(MaterialEditorGui,EditorGuiGroup) { tooltipprofile = "ToolsGuiToolTipProfile"; buttonType = "PushButton"; useMouseEvents = "0"; - bitmap = "ToolsModule:new_n_image"; + bitmapAsset = "ToolsModule:new_n_image"; }; // Save Button new GuiBitmapButtonCtrl() { diff --git a/Templates/BaseGame/game/tools/navEditor/NavEditorToolbar.gui b/Templates/BaseGame/game/tools/navEditor/NavEditorToolbar.gui index cdee55fb9..38c86f678 100644 --- a/Templates/BaseGame/game/tools/navEditor/NavEditorToolbar.gui +++ b/Templates/BaseGame/game/tools/navEditor/NavEditorToolbar.gui @@ -40,7 +40,7 @@ $guiContent = new GuiControl(NavEditorToolbar,EditorGuiGroup) { canSaveDynamicFields = "0"; }; new GuiBitmapCtrl() { - bitmap = "core/gui/images/separator-h.png"; + bitmapAsset = "ToolsModule:separator_h_image"; wrap = "0"; position = "90 3"; extent = "2 26"; diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/EditorChooseLevelGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/EditorChooseLevelGui.ed.gui index 6ca9dd503..a7e7b2626 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/EditorChooseLevelGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/EditorChooseLevelGui.ed.gui @@ -28,7 +28,7 @@ $guiContent = new GuiContainer(EditorChooseLevelGui, EditorGuiGroup) { Visible = "1"; tooltipprofile = "ToolsGuiToolTipProfile"; hovertime = "1000"; - bitmap = "data/ui/images/background.png"; + bitmapAsset = "UI:background_image"; useVariable = "0"; tile = "0"; }; diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui index 002f4b4fa..810a923d4 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/EditorGui.ed.gui @@ -115,8 +115,8 @@ $guiContent = new GuiContainer(EditorGui,EditorGuiGroup) { selectionBoxColor = "255 255 0 255"; selectionLocked = "0"; toggleIgnoreList = "0"; - selectHandle = "ToolsModule:SelectHandle_image"; - defaultHandle = "ToolsModule:DefaultHandle_image"; + selectHandleAsset = "ToolsModule:SelectHandle_image"; + defaultHandleAsset = "ToolsModule:DefaultHandle_image"; lockedHandleAsset = "ToolsModule:LockedHandle_image"; }; new TerrainEditor(ETerrainEditor) { From 4d893f51cff27c03cc1648895b75146997f01f47 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 22 Dec 2024 17:03:44 +0000 Subject: [PATCH 05/47] gui image asset refactor bitmap button popup ctrl ex --- Engine/source/T3D/assets/ImageAsset.cpp | 12 +---- Engine/source/T3D/assets/ImageAsset.h | 35 ++++++++++++++ .../gui/buttons/guiBitmapButtonCtrl.cpp | 32 ++++++------- .../source/gui/buttons/guiBitmapButtonCtrl.h | 47 ++++++++++++------- Engine/source/gui/controls/guiPopUpCtrlEx.cpp | 37 +++++---------- Engine/source/gui/controls/guiPopUpCtrlEx.h | 7 +-- 6 files changed, 95 insertions(+), 75 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index b249cdb56..cec0cb496 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -860,11 +860,7 @@ void GuiInspectorTypeImageAssetPtr::updatePreviewImage() { if (AssetDatabase.isDeclaredAsset(previewImage)) { - ImageAsset* imgAsset = AssetDatabase.acquireAsset(previewImage); - if (imgAsset && imgAsset->isAssetValid()) - { - mPreviewImage->_setBitmap(imgAsset->getAssetId()); - } + mPreviewImage->_setBitmap(previewImage); } } @@ -892,11 +888,7 @@ void GuiInspectorTypeImageAssetPtr::setPreviewImage(StringTableEntry assetId) { if (AssetDatabase.isDeclaredAsset(assetId)) { - ImageAsset* imgAsset = AssetDatabase.acquireAsset(assetId); - if (imgAsset && imgAsset->isAssetValid()) - { - mPreviewImage->_setBitmap(imgAsset->getAssetId()); - } + mPreviewImage->_setBitmap(assetId); } } diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 894edc58f..4635a3223 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -652,4 +652,39 @@ public: #define INITPERSISTFIELD_IMAGEASSET_REFACTOR(name, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); + +#define DECLARE_IMAGEASSET_ARRAY_REFACTOR(className, name, profile, max) \ +private: \ + AssetPtr m##name##Asset[max]; \ +public: \ + void _set##name(StringTableEntry _in, const U32& index){ \ + if(m##name##Asset[index].getAssetId() == _in) \ + return; \ + \ + if(!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset[index] = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset[index] = _in; \ + } \ + }; \ + \ + inline StringTableEntry _get##name(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ + GFXTexHandle get##name(const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(&profile) : NULL; } \ + AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} + +#define INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); + + #pragma endregion diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp index 9738cc25c..139c8f65d 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp @@ -129,7 +129,9 @@ GuiBitmapButtonCtrl::GuiBitmapButtonCtrl() setExtent( 140, 30 ); mMasked = false; mColor = ColorI::WHITE; - INIT_ASSET(Bitmap); + mBitmapName = StringTable->EmptyString(); + mBitmap = NULL; + mBitmapAsset.registerRefreshNotify(this); } //----------------------------------------------------------------------------- @@ -139,14 +141,10 @@ void GuiBitmapButtonCtrl::initPersistFields() docsURL; addGroup( "Bitmap" ); - addProtectedField("Bitmap", TypeImageFilename, Offset(mBitmapName, GuiBitmapButtonCtrl), _setBitmapFieldData, &defaultProtectedGetFn, "Texture file to display on this button.\n" + INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiBitmapButtonCtrl,"Texture file to display on this button.\n" "If useStates is false, this will be the file that renders on the control. Otherwise, this will " "specify the default texture name to which the various state and modifier suffixes are appended " - "to find the per-state and per-modifier (if enabled) textures.", AbstractClassRep::FIELD_HideInInspectors); \ - addProtectedField("BitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiBitmapButtonCtrl), _setBitmapFieldData, &defaultProtectedGetFn, "Texture file to display on this button.\n" - "If useStates is false, this will be the file that renders on the control. Otherwise, this will " - "specify the default texture name to which the various state and modifier suffixes are appended " - "to find the per-state and per-modifier (if enabled) textures."); + "to find the per-state and per-modifier (if enabled) textures.") addField("color", TypeColorI, Offset(mColor, GuiBitmapButtonCtrl), "color mul"); @@ -184,7 +182,7 @@ bool GuiBitmapButtonCtrl::onWake() return false; setActive( true ); - setBitmap( getBitmap() ); + setBitmap( mBitmapName ); return true; } @@ -242,7 +240,7 @@ void GuiBitmapButtonCtrl::inspectPostApply() { Parent::inspectPostApply(); - setBitmap(getBitmap()); + setBitmap(mBitmapName); // if the extent is set to (0,0) in the gui editor and appy hit, this control will // set it's extent to be exactly the size of the normal bitmap (if present) @@ -274,7 +272,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) if( mBitmapAsset.notNull()) { - if( dStricmp( getBitmap(), "texhandle" ) != 0 ) + if( dStricmp( mBitmapName, "texhandle" ) != 0 ) { const U32 count = mUseModifiers ? NumModifiers : 1; for( U32 i = 0; i < count; ++ i ) @@ -292,7 +290,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) static String s_h[2] = { "_h", "_h_image" }; static String s_i[2] = { "_i", "_i_image" }; - String baseName = mBitmapAssetId; + String baseName = mBitmapAsset.getAssetId(); //strip any pre-assigned suffix, just in case baseName = baseName.replace("_n_image", ""); @@ -301,7 +299,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) if( mUseModifiers ) baseName += modifiers[ i ]; - mTextures[ i ].mTextureNormal = GFXTexHandle( mBitmapAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureNormal = getBitmap(); if( mUseStates ) { @@ -323,7 +321,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureNormalAsset->load(); if (mTextures[i].mTextureNormalAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureNormal = GFXTexHandle(mTextures[i].mTextureNormalAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureNormal = mTextures[i].mTextureNormalAsset->getTexture(&GFXDefaultGUIProfile); break; } } @@ -345,7 +343,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureHilightAsset->load(); if (mTextures[i].mTextureHilightAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureHilight = GFXTexHandle(mTextures[i].mTextureHilightAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureHilight = mTextures[i].mTextureHilightAsset->getTexture(&GFXDefaultGUIProfile); break; } } @@ -369,7 +367,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureDepressedAsset->load(); if (mTextures[i].mTextureDepressedAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureDepressed = GFXTexHandle(mTextures[i].mTextureDepressedAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureDepressed = mTextures[i].mTextureDepressedAsset->getTexture(&GFXDefaultGUIProfile); break; } } @@ -393,7 +391,7 @@ void GuiBitmapButtonCtrl::setBitmap( StringTableEntry name ) mTextures[i].mTextureInactiveAsset->load(); if (mTextures[i].mTextureInactiveAsset->getStatus() == AssetBase::Ok) { - mTextures[i].mTextureInactive = GFXTexHandle(mTextures[i].mTextureInactiveAsset->getImageFile(), &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__)); + mTextures[i].mTextureInactive = mTextures[i].mTextureInactiveAsset->getTexture(&GFXDefaultGUIProfile); break; } } @@ -670,4 +668,4 @@ bool GuiBitmapButtonCtrl::pointInControl(const Point2I& parentCoordPoint) return Parent::pointInControl(parentCoordPoint); } -DEF_ASSET_BINDS(GuiBitmapButtonCtrl, Bitmap); +DEF_ASSET_BINDS_REFACTOR(GuiBitmapButtonCtrl, Bitmap) diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h index 8674432ec..1194809d7 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h @@ -49,7 +49,7 @@ /// To implement different handlers for the modifier states, use the "onDefaultClick", /// "onCtrlClick", "onAltClick", and "onShiftClick" methods. /// -class GuiBitmapButtonCtrl : public GuiButtonCtrl +class GuiBitmapButtonCtrl : public GuiButtonCtrl, protected AssetPtrCallback { public: @@ -118,9 +118,35 @@ class GuiBitmapButtonCtrl : public GuiButtonCtrl /// BitmapMode mBitmapMode; - DECLARE_IMAGEASSET(GuiBitmapButtonCtrl, Bitmap, onBitmapChange, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiBitmapButtonCtrl, Bitmap); - +private: AssetPtr mBitmapAsset; public: void _setBitmap(StringTableEntry _in) { + if (mBitmapAsset.getAssetId() == _in) return; if (!AssetDatabase.isDeclaredAsset(_in)) { + StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; AssetQuery query; S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); if (foundAssetcount != 0) { + imageAssetId = query.mAssetList[0]; + } mBitmapAsset = imageAssetId; + } + else { + mBitmapAsset = _in; + mBitmapName = _in; + mBitmap = getBitmap(); + } +}; inline StringTableEntry _getBitmap(void) const { + return mBitmapAsset.getAssetId(); +} GFXTexHandle getBitmap() { + return mBitmapAsset.notNull() ? mBitmapAsset->getTexture(&GFXDefaultGUIProfile) : 0; +} AssetPtr getBitmapAsset(void) { + return mBitmapAsset; +} static bool _setBitmapData(void* obj, const char* index, const char* data) { + static_cast(obj)->_setBitmap(_getStringTable()->insert(data)); return false; +} +protected: + + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + setBitmap(mBitmapName); + } + + GFXTexHandle mBitmap; + StringTableEntry mBitmapName; /// alpha masking bool mMasked; @@ -158,11 +184,6 @@ class GuiBitmapButtonCtrl : public GuiButtonCtrl /// @} - void onBitmapChange() - { - setBitmap(getBitmap()); - } - public: GuiBitmapButtonCtrl(); @@ -185,14 +206,6 @@ class GuiBitmapButtonCtrl : public GuiButtonCtrl DECLARE_CONOBJECT(GuiBitmapButtonCtrl); DECLARE_DESCRIPTION( "A button control rendered entirely from bitmaps.\n" "The individual button states are represented with separate bitmaps." ); - - //Basically a wrapper function to do our special state handling setup when the fields change - static bool _setBitmapFieldData(void* obj, const char* index, const char* data) - { - GuiBitmapButtonCtrl* object = static_cast(obj); - object->setBitmap(StringTable->insert(data)); - return false; - } }; typedef GuiBitmapButtonCtrl::BitmapMode GuiBitmapMode; diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp index 45183285d..9b82c1ecc 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp @@ -329,9 +329,6 @@ GuiPopUpMenuCtrlEx::GuiPopUpMenuCtrlEx(void) mBackgroundCancel = false; // Added mReverseTextList = false; // Added - Don't reverse text list if displaying up - INIT_IMAGEASSET_ARRAY(Bitmap, GFXDefaultGUIProfile, Normal); - INIT_IMAGEASSET_ARRAY(Bitmap, GFXDefaultGUIProfile, Depressed); - mBitmapBounds.set(16, 16); // Added mHotTrackItems = false; mIdMax = -1; @@ -356,8 +353,7 @@ void GuiPopUpMenuCtrlEx::initPersistFields(void) addField("sbUsesNAColor", TypeBool, Offset(mRenderScrollInNA, GuiPopUpMenuCtrlEx), "Deprecated" "@internal"); addField("reverseTextList", TypeBool, Offset(mReverseTextList, GuiPopUpMenuCtrlEx), "Reverses text list if popup extends up, instead of down"); - addProtectedField("bitmap", TypeImageFilename, Offset(mBitmapName, GuiPopUpMenuCtrlEx), _setBitmaps, &defaultProtectedGetFn, "File name of bitmap to use"); - addProtectedField("bitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiPopUpMenuCtrlEx), _setBitmaps, &defaultProtectedGetFn, "Name of bitmap asset to use"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Bitmap, NumBitmapModes, GuiPopUpMenuCtrlEx, "Name of bitmap asset to use") addField("bitmapBounds", TypePoint2I, Offset(mBitmapBounds, GuiPopUpMenuCtrlEx), "Boundaries of bitmap displayed"); addField("hotTrackCallback", TypeBool, Offset(mHotTrackItems, GuiPopUpMenuCtrlEx), @@ -368,14 +364,6 @@ void GuiPopUpMenuCtrlEx::initPersistFields(void) Parent::initPersistFields(); } -bool GuiPopUpMenuCtrlEx::_setBitmaps(void* obj, const char* index, const char* data) -{ - GuiPopUpMenuCtrlEx* object = static_cast(obj); - - object->setBitmap(data); - return true; -} - //------------------------------------------------------------------------------ ConsoleDocFragment _GuiPopUpMenuCtrlExAdd( "@brief Adds an entry to the list\n\n" @@ -690,9 +678,6 @@ bool GuiPopUpMenuCtrlEx::onWake() if ( !Parent::onWake() ) return false; - // Set the bitmap for the popup. - setBitmap(getBitmap(Normal)); - // Now update the Form Control's bitmap array, and possibly the child's too mProfile->constructBitmapArray(); @@ -818,8 +803,8 @@ void GuiPopUpMenuCtrlEx::setBitmap(const char *name) dStrcpy(p, "_d", pLen); _setBitmap((StringTableEntry)buffer, Depressed); - if (!mBitmap[Depressed]) - mBitmap[Depressed] = mBitmap[Normal]; + if (mBitmapAsset[Depressed].isNull()) + mBitmapAsset[Depressed] = mBitmapAsset[Normal]; } else { @@ -1096,17 +1081,17 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect) } // Draw a bitmap over the background? - if ( mBitmap[Depressed] ) + if ( mBitmapAsset[Depressed].notNull() ) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch(mBitmap[Depressed], rect ); + drawUtil->drawBitmapStretch(getBitmap(Depressed), rect ); } - else if (mBitmap[Normal]) + else if (mBitmapAsset[Normal].notNull()) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch(mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch(getBitmap(Normal), rect ); } // Do we render a bitmap border or lines? @@ -1140,11 +1125,11 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect) } // Draw a bitmap over the background? - if (mBitmap[Normal]) + if (mBitmapAsset[Normal].notNull()) { RectI rect( offset, mBitmapBounds ); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch(mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch(getBitmap(Normal), rect ); } // Do we render a bitmap border or lines? @@ -1170,11 +1155,11 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect) } // Draw a bitmap over the background? - if (mBitmap[Normal]) + if (mBitmapAsset[Normal].notNull()) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch(mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch(getBitmap(Normal), rect ); } // Do we render a bitmap border or lines? diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.h b/Engine/source/gui/controls/guiPopUpCtrlEx.h index f389de3e7..ac0306f35 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.h +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.h @@ -131,9 +131,8 @@ class GuiPopUpMenuCtrlEx : public GuiTextCtrl NumBitmapModes = 2 }; - DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrlEx, Bitmap, NumBitmapModes, onBitmapChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(GuiPopUpMenuCtrlEx, Bitmap); - void onBitmapChanged() {} + DECLARE_IMAGEASSET_ARRAY_REFACTOR(GuiPopUpMenuCtrlEx, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) + Point2I mBitmapBounds; // Added S32 mIdMax; @@ -144,8 +143,6 @@ class GuiPopUpMenuCtrlEx : public GuiTextCtrl virtual void removeChildren(); virtual void repositionPopup(); - static bool _setBitmaps(void* obj, const char* index, const char* data); - public: GuiPopUpMenuCtrlEx(void); ~GuiPopUpMenuCtrlEx(); From 22037bf94fccaab94b69b92a1de4030500f4526d Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 25 Dec 2024 20:23:22 +0000 Subject: [PATCH 06/47] moar refactors --- Engine/source/T3D/assets/assetMacroHelpers.h | 20 +++++++++++++ Engine/source/T3D/fx/splash.cpp | 21 ++++---------- Engine/source/T3D/fx/splash.h | 4 +-- .../source/gui/buttons/guiIconButtonCtrl.cpp | 27 ++++++++--------- Engine/source/gui/buttons/guiIconButtonCtrl.h | 3 +- Engine/source/gui/controls/guiPopUpCtrl.cpp | 29 +++++++------------ Engine/source/gui/controls/guiPopUpCtrl.h | 5 ++-- Engine/source/gui/controls/guiPopUpCtrlEx.cpp | 12 ++++++-- Engine/source/gui/controls/guiPopUpCtrlEx.h | 2 ++ .../gui/editor/inspector/dynamicField.cpp | 2 +- 10 files changed, 65 insertions(+), 60 deletions(-) diff --git a/Engine/source/T3D/assets/assetMacroHelpers.h b/Engine/source/T3D/assets/assetMacroHelpers.h index 4facaed5d..e706883b1 100644 --- a/Engine/source/T3D/assets/assetMacroHelpers.h +++ b/Engine/source/T3D/assets/assetMacroHelpers.h @@ -86,6 +86,26 @@ if (m##name##AssetId != StringTable->EmptyString())\ _set##name(netconn->unpackNetStringHandleU(stream).getString());\ } +//network send - datablock +#define PACKDATA_ASSET_ARRAY_REFACTOR(name, max)\ +for (i = 0; i < max; i++)\ +{\ + if (stream->writeFlag(m##name##Asset[i].notNull()))\ + {\ + stream->writeString(m##name##Asset[i].getAssetId()); \ + }\ +} + +//network recieve - datablock +#define UNPACKDATA_ASSET_ARRAY_REFACTOR(name, max)\ +for (i = 0; i < max; i++)\ +{\ + if (stream->readFlag())\ + {\ + m##name##Asset[i] = stream->readSTString();\ + }\ +} + #define DEF_ASSET_BINDS_REFACTOR(className,name)\ DefineEngineMethod(className, get##name, StringTableEntry, (), , "get name")\ {\ diff --git a/Engine/source/T3D/fx/splash.cpp b/Engine/source/T3D/fx/splash.cpp index 07c3a52f3..205575672 100644 --- a/Engine/source/T3D/fx/splash.cpp +++ b/Engine/source/T3D/fx/splash.cpp @@ -96,11 +96,6 @@ SplashData::SplashData() explosionId = 0; U32 i; - for (i = 0; i < NUM_TEX; i++) - { - INIT_IMAGEASSET_ARRAY(Texture, GFXStaticTextureSRGBProfile, i); - } - for( i=0; iwrite( times[i] ); } - for( i=0; iread( ×[i] ); } - for( i=0; i(), Offset( mIconLocation, GuiIconButtonCtrl ),"Where to place the icon on the control. Options are 0 (None), 1 (Left), 2 (Right), 3 (Center).\n"); addField( "sizeIconToButton", TypeBool, Offset( mFitBitmapToButton, GuiIconButtonCtrl ),"If true, the icon will be scaled to be the same size as the button.\n"); @@ -148,8 +147,6 @@ bool GuiIconButtonCtrl::onWake() return false; setActive(true); - setBitmap(mBitmapName); - if( mProfile ) mProfile->constructBitmapArray(); @@ -181,8 +178,8 @@ bool GuiIconButtonCtrl::resize(const Point2I &newPosition, const Point2I &newExt if ( mIconLocation != IconLocNone ) { - autoExtent.y = mBitmap.getHeight() + mButtonMargin.y * 2; - autoExtent.x = mBitmap.getWidth() + mButtonMargin.x * 2; + autoExtent.y = getBitmap().getHeight() + mButtonMargin.y * 2; + autoExtent.x = getBitmap().getWidth() + mButtonMargin.x * 2; } if ( mTextLocation != TextLocNone && mButtonText && mButtonText[0] ) @@ -209,7 +206,7 @@ void GuiIconButtonCtrl::setBitmap(const char *name) if(!isAwake()) return; - _setBitmap(getBitmap()); + _setBitmap(name); // So that extent is recalculated if autoSize is set. resize( getPosition(), getExtent() ); @@ -299,13 +296,13 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) RectI iconRect( 0, 0, 0, 0 ); // Render the icon - if ( mBitmap && mIconLocation != GuiIconButtonCtrl::IconLocNone ) + if ( mBitmapAsset.notNull() && mIconLocation != GuiIconButtonCtrl::IconLocNone) { // Render the normal bitmap drawer->clearBitmapModulation(); // Size of the bitmap - Point2I textureSize(mBitmap->getWidth(), mBitmap->getHeight()); + Point2I textureSize(getBitmap()->getWidth(), getBitmap()->getHeight()); // Reduce the size with the margin (if set) textureSize.x = textureSize.x - (mBitmapMargin * 2); @@ -332,7 +329,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) iconRect.point.y = offset.y + ( getHeight() - textureSize.y ) / 2; } - drawer->drawBitmapStretch(mBitmap, iconRect ); + drawer->drawBitmapStretch(getBitmap(), iconRect ); } else @@ -366,7 +363,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) iconRect.point.y = offset.y + (getHeight() / 2) - (iconRect.extent.y / 2) + mButtonMargin.y; } - drawer->drawBitmapStretch( mBitmap, iconRect ); + drawer->drawBitmapStretch(getBitmap(), iconRect ); } } @@ -383,7 +380,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) if ( mTextLocation == TextLocRight ) { Point2I start( mTextMargin, ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); - if (mBitmap && mIconLocation != IconLocNone ) + if (mBitmapAsset.notNull() && mIconLocation != IconLocNone) { start.x = iconRect.extent.x + mButtonMargin.x + mTextMargin; } @@ -403,7 +400,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect ) if ( mTextLocation == TextLocCenter ) { Point2I start; - if (mBitmap && mIconLocation == IconLocLeft ) + if (mBitmapAsset.notNull() && mIconLocation == IconLocLeft ) { start.set( ( getWidth() - textWidth - iconRect.extent.x ) / 2 + iconRect.extent.x, ( getHeight() - mProfile->mFont->getHeight() ) / 2 ); @@ -468,4 +465,4 @@ void GuiIconButtonCtrl::renderBitmapArray(RectI &bounds, S32 state) } } -DEF_ASSET_BINDS(GuiIconButtonCtrl, Bitmap); +DEF_ASSET_BINDS_REFACTOR(GuiIconButtonCtrl, Bitmap) diff --git a/Engine/source/gui/buttons/guiIconButtonCtrl.h b/Engine/source/gui/buttons/guiIconButtonCtrl.h index d4b00bfbc..da5b08ca2 100644 --- a/Engine/source/gui/buttons/guiIconButtonCtrl.h +++ b/Engine/source/gui/buttons/guiIconButtonCtrl.h @@ -42,8 +42,7 @@ private: protected: - DECLARE_IMAGEASSET(GuiIconButtonCtrl, Bitmap, onImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiIconButtonCtrl, Bitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiIconButtonCtrl, Bitmap, GFXDefaultGUIProfile) S32 mIconLocation; S32 mTextLocation; diff --git a/Engine/source/gui/controls/guiPopUpCtrl.cpp b/Engine/source/gui/controls/guiPopUpCtrl.cpp index ad4fafe4e..3e6eff7d4 100644 --- a/Engine/source/gui/controls/guiPopUpCtrl.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrl.cpp @@ -278,9 +278,6 @@ GuiPopUpMenuCtrl::GuiPopUpMenuCtrl(void) mBackgroundCancel = false; // Added mReverseTextList = false; // Added - Don't reverse text list if displaying up - INIT_IMAGEASSET_ARRAY(Bitmap, GFXDefaultGUIProfile, 0); - INIT_IMAGEASSET_ARRAY(Bitmap, GFXDefaultGUIProfile, 1); - mBitmapBounds.set(16, 16); // Added mIdMax = -1; mBackground = NULL; @@ -302,8 +299,7 @@ void GuiPopUpMenuCtrl::initPersistFields(void) addField("sbUsesNAColor", TypeBool, Offset(mRenderScrollInNA, GuiPopUpMenuCtrl)); addField("reverseTextList", TypeBool, Offset(mReverseTextList, GuiPopUpMenuCtrl)); - addProtectedField("bitmap", TypeImageFilename, Offset(mBitmapName, GuiPopUpMenuCtrl), _setBitmaps, defaultProtectedGetFn, ""); - addProtectedField("bitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiPopUpMenuCtrl), _setBitmaps, defaultProtectedGetFn, ""); + addProtectedField("BitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiPopUpMenuCtrl), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"\"."); addField("bitmapBounds", TypePoint2I, Offset(mBitmapBounds, GuiPopUpMenuCtrl)); @@ -473,9 +469,6 @@ bool GuiPopUpMenuCtrl::onWake() if ( !Parent::onWake() ) return false; - // Set the bitmap for the popup. - setBitmap(getBitmap(Normal)); - // Now update the Form Control's bitmap array, and possibly the child's too mProfile->constructBitmapArray(); @@ -592,8 +585,8 @@ void GuiPopUpMenuCtrl::setBitmap( const char *name ) dStrcpy(p, "_d", pLen); _setBitmap((StringTableEntry)buffer, Depressed); - if ( !mBitmap[Depressed] ) - mBitmap[Depressed] = mBitmap[Normal]; + if ( mBitmapAsset[Depressed].isNull() ) + mBitmapAsset[Depressed] = mBitmapAsset[Normal]; } else { @@ -898,17 +891,17 @@ void GuiPopUpMenuCtrl::onRender( Point2I offset, const RectI &updateRect ) } // Draw a bitmap over the background? - if ( mBitmap[Depressed] ) + if ( mBitmapAsset[Depressed].notNull() ) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch( mBitmap[Depressed], rect ); + drawUtil->drawBitmapStretch( getBitmap(Depressed), rect ); } - else if ( mBitmap[Normal] ) + else if ( mBitmapAsset[Normal].notNull() ) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch( mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch(getBitmap(Normal), rect ); } // Do we render a bitmap border or lines? @@ -948,11 +941,11 @@ void GuiPopUpMenuCtrl::onRender( Point2I offset, const RectI &updateRect ) } // Draw a bitmap over the background? - if ( mBitmap[Normal] ) + if ( mBitmapAsset[Normal].notNull() ) { RectI rect( offset, mBitmapBounds ); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch( mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch(getBitmap(Normal) , rect); } // Do we render a bitmap border or lines? @@ -984,11 +977,11 @@ void GuiPopUpMenuCtrl::onRender( Point2I offset, const RectI &updateRect ) } // Draw a bitmap over the background? - if ( mBitmap[Normal] ) + if (mBitmapAsset[Normal].notNull()) { RectI rect(offset, mBitmapBounds); drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapStretch( mBitmap[Normal], rect ); + drawUtil->drawBitmapStretch( getBitmap(Normal), rect); } // Do we render a bitmap border or lines? diff --git a/Engine/source/gui/controls/guiPopUpCtrl.h b/Engine/source/gui/controls/guiPopUpCtrl.h index 12568d2c6..3f7f5c02b 100644 --- a/Engine/source/gui/controls/guiPopUpCtrl.h +++ b/Engine/source/gui/controls/guiPopUpCtrl.h @@ -126,9 +126,8 @@ protected: NumBitmapModes = 2 }; - DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrl, Bitmap, NumBitmapModes, onBitmapChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(GuiPopUpMenuCtrl, Bitmap); - void onBitmapChanged() {} + DECLARE_IMAGEASSET_ARRAY_REFACTOR(GuiPopUpMenuCtrl, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) + Point2I mBitmapBounds; // Added S32 mIdMax; diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp index 9b82c1ecc..2624d4197 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp @@ -353,7 +353,7 @@ void GuiPopUpMenuCtrlEx::initPersistFields(void) addField("sbUsesNAColor", TypeBool, Offset(mRenderScrollInNA, GuiPopUpMenuCtrlEx), "Deprecated" "@internal"); addField("reverseTextList", TypeBool, Offset(mReverseTextList, GuiPopUpMenuCtrlEx), "Reverses text list if popup extends up, instead of down"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Bitmap, NumBitmapModes, GuiPopUpMenuCtrlEx, "Name of bitmap asset to use") + addProtectedField("BitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiPopUpMenuCtrlEx), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"Name of bitmap asset to use\"."); addField("bitmapBounds", TypePoint2I, Offset(mBitmapBounds, GuiPopUpMenuCtrlEx), "Boundaries of bitmap displayed"); addField("hotTrackCallback", TypeBool, Offset(mHotTrackItems, GuiPopUpMenuCtrlEx), @@ -780,7 +780,15 @@ static S32 QSORT_CALLBACK idCompare(const void *a,const void *b) GuiPopUpMenuCtrlEx::Entry *ea = (GuiPopUpMenuCtrlEx::Entry *) (a); GuiPopUpMenuCtrlEx::Entry *eb = (GuiPopUpMenuCtrlEx::Entry *) (b); return ( (ea->id < eb->id) ? -1 : ((ea->id > eb->id) ? 1 : 0) ); -} +} + +bool GuiPopUpMenuCtrlEx::_setBitmaps(void* obj, const char* index, const char* data) +{ + GuiPopUpMenuCtrlEx* object = static_cast(obj); + + object->setBitmap(data); + return true; +} //------------------------------------------------------------------------------ // Added diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.h b/Engine/source/gui/controls/guiPopUpCtrlEx.h index ac0306f35..9e8fddc87 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.h +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.h @@ -143,6 +143,8 @@ class GuiPopUpMenuCtrlEx : public GuiTextCtrl virtual void removeChildren(); virtual void repositionPopup(); + static bool _setBitmaps(void* obj, const char* index, const char* data); + public: GuiPopUpMenuCtrlEx(void); ~GuiPopUpMenuCtrlEx(); diff --git a/Engine/source/gui/editor/inspector/dynamicField.cpp b/Engine/source/gui/editor/inspector/dynamicField.cpp index 52ff17457..861066721 100644 --- a/Engine/source/gui/editor/inspector/dynamicField.cpp +++ b/Engine/source/gui/editor/inspector/dynamicField.cpp @@ -257,7 +257,7 @@ bool GuiInspectorDynamicField::onAdd() mParent->getId() ); // FIXME Hardcoded image - mDeleteButton->setField( "Bitmap", "ToolsModule:iconDelete_image" ); + mDeleteButton->_setBitmap("ToolsModule:iconDelete_image"); mDeleteButton->setField( "Text", "X" ); mDeleteButton->setField( "Command", szBuffer ); mDeleteButton->setSizing( horizResizeLeft, vertResizeCenter ); From b75d5b70c62429bca5fd7e834f872a885b3b046e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 25 Dec 2024 20:32:46 +0000 Subject: [PATCH 07/47] toolbox --- .../gui/buttons/guiToolboxButtonCtrl.cpp | 36 ++++++++----------- .../source/gui/buttons/guiToolboxButtonCtrl.h | 17 +++------ 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp b/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp index dc2c92d61..1becb6f49 100644 --- a/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp @@ -43,10 +43,6 @@ ConsoleDocClass( GuiToolboxButtonCtrl, //------------------------------------- GuiToolboxButtonCtrl::GuiToolboxButtonCtrl() { - INIT_ASSET(NormalBitmap); - INIT_ASSET(LoweredBitmap); - INIT_ASSET(HoverBitmap); - setMinExtent(Point2I(16,16)); setExtent(48, 48); mButtonType = ButtonTypeRadio; @@ -59,9 +55,9 @@ GuiToolboxButtonCtrl::GuiToolboxButtonCtrl() void GuiToolboxButtonCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET(NormalBitmap, GuiToolboxButtonCtrl, ""); - INITPERSISTFIELD_IMAGEASSET(LoweredBitmap, GuiToolboxButtonCtrl, ""); - INITPERSISTFIELD_IMAGEASSET(HoverBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(NormalBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(LoweredBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(HoverBitmap, GuiToolboxButtonCtrl, ""); Parent::initPersistFields(); } @@ -75,10 +71,6 @@ bool GuiToolboxButtonCtrl::onWake() setActive( true ); - setNormalBitmap( getNormalBitmap() ); - setLoweredBitmap( getLoweredBitmap() ); - setHoverBitmap( getHoverBitmap() ); - return true; } @@ -96,9 +88,9 @@ void GuiToolboxButtonCtrl::inspectPostApply() // set it's extent to be exactly the size of the normal bitmap (if present) Parent::inspectPostApply(); - if ((getWidth() == 0) && (getHeight() == 0) && mNormalBitmap) + if ((getWidth() == 0) && (getHeight() == 0) && mNormalBitmapAsset.notNull()) { - setExtent(mNormalBitmap->getWidth(), mNormalBitmap->getHeight()); + setExtent(getNormalBitmap()->getWidth(), getNormalBitmap()->getHeight()); } } @@ -144,15 +136,15 @@ void GuiToolboxButtonCtrl::onRender(Point2I offset, const RectI& updateRect) { RectI r(offset, getExtent()); if ( mDepressed || mStateOn ) - renderStateRect( mLoweredBitmap , r ); + renderStateRect( getLoweredBitmap(), r); else if ( mHighlighted ) - renderStateRect( mHoverBitmap , r ); + renderStateRect( getHoverBitmap(), r); } // Now render the image - if( mNormalBitmap ) + if( mNormalBitmapAsset.notNull() ) { - renderButton(mNormalBitmap, offset, updateRect ); + renderButton(getNormalBitmap(), offset, updateRect ); return; } @@ -168,7 +160,7 @@ void GuiToolboxButtonCtrl::onRender(Point2I offset, const RectI& updateRect) } -void GuiToolboxButtonCtrl::renderStateRect( GFXTexHandle &texture, const RectI& rect ) +void GuiToolboxButtonCtrl::renderStateRect( GFXTexHandle texture, const RectI& rect ) { if (texture) { @@ -179,7 +171,7 @@ void GuiToolboxButtonCtrl::renderStateRect( GFXTexHandle &texture, const RectI& //------------------------------------------------------------------------------ -void GuiToolboxButtonCtrl::renderButton(GFXTexHandle &texture, Point2I &offset, const RectI& updateRect) +void GuiToolboxButtonCtrl::renderButton(GFXTexHandle texture, Point2I &offset, const RectI& updateRect) { if (texture) { @@ -194,6 +186,6 @@ void GuiToolboxButtonCtrl::renderButton(GFXTexHandle &texture, Point2I &offset, } } -DEF_ASSET_BINDS(GuiToolboxButtonCtrl, NormalBitmap); -DEF_ASSET_BINDS(GuiToolboxButtonCtrl, LoweredBitmap); -DEF_ASSET_BINDS(GuiToolboxButtonCtrl, HoverBitmap); +DEF_ASSET_BINDS_REFACTOR(GuiToolboxButtonCtrl, NormalBitmap) +DEF_ASSET_BINDS_REFACTOR(GuiToolboxButtonCtrl, LoweredBitmap) +DEF_ASSET_BINDS_REFACTOR(GuiToolboxButtonCtrl, HoverBitmap) diff --git a/Engine/source/gui/buttons/guiToolboxButtonCtrl.h b/Engine/source/gui/buttons/guiToolboxButtonCtrl.h index 9d56308ad..c5319e9dd 100644 --- a/Engine/source/gui/buttons/guiToolboxButtonCtrl.h +++ b/Engine/source/gui/buttons/guiToolboxButtonCtrl.h @@ -39,19 +39,12 @@ private: protected: - DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, NormalBitmap, onNormalImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiToolboxButtonCtrl, NormalBitmap); - DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, LoweredBitmap, onLoweredImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiToolboxButtonCtrl, LoweredBitmap); - DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, HoverBitmap, onHoverImageChanged, GFXDefaultGUIProfile); - DECLARE_ASSET_SETGET(GuiToolboxButtonCtrl, HoverBitmap); + DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, NormalBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, LoweredBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, HoverBitmap, GFXDefaultGUIProfile) - void renderButton(GFXTexHandle &texture, Point2I &offset, const RectI& updateRect); - void renderStateRect( GFXTexHandle &texture, const RectI& rect ); - - void onNormalImageChanged() {} - void onLoweredImageChanged() {} - void onHoverImageChanged() {} + void renderButton(GFXTexHandle texture, Point2I &offset, const RectI& updateRect); + void renderStateRect( GFXTexHandle texture, const RectI& rect ); public: DECLARE_CONOBJECT(GuiToolboxButtonCtrl); From 32c6330b728629e256e8b152c661d7ff000d4fae Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 26 Dec 2024 13:11:29 +0000 Subject: [PATCH 08/47] guiControlProfile --- Engine/source/gui/buttons/guiCheckBoxCtrl.cpp | 2 +- Engine/source/gui/containers/guiFormCtrl.cpp | 6 +- Engine/source/gui/containers/guiPaneCtrl.cpp | 8 +- .../source/gui/containers/guiScrollCtrl.cpp | 2 +- .../source/gui/containers/guiWindowCtrl.cpp | 2 +- .../gui/controls/guiBitmapBorderCtrl.cpp | 2 +- .../gui/controls/guiGameListMenuCtrl.cpp | 6 +- .../gui/controls/guiGameListOptionsCtrl.cpp | 4 +- Engine/source/gui/controls/guiSliderCtrl.cpp | 8 +- .../source/gui/controls/guiTreeViewCtrl.cpp | 2 +- .../gui/core/guiDefaultControlRender.cpp | 64 +++++------ Engine/source/gui/core/guiTypes.cpp | 60 +++++------ Engine/source/gui/core/guiTypes.h | 102 +----------------- Engine/source/gui/editor/guiMenuBar.cpp | 2 +- Engine/source/gui/editor/guiPopupMenuCtrl.cpp | 2 +- .../source/gui/game/guiProgressBitmapCtrl.cpp | 8 +- 16 files changed, 91 insertions(+), 189 deletions(-) diff --git a/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp b/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp index 93e51168b..ffb63dfb9 100644 --- a/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp +++ b/Engine/source/gui/buttons/guiCheckBoxCtrl.cpp @@ -134,7 +134,7 @@ void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect) } xOffset = mProfile->mBitmapArrayRects[0].extent.x + 2 + mIndent; S32 y = (getHeight() - mProfile->mBitmapArrayRects[0].extent.y) / 2; - GFX->getDrawUtil()->drawBitmapSR(mProfile->getBitmapResource(), offset + Point2I(mIndent, y), mProfile->mBitmapArrayRects[index]); + GFX->getDrawUtil()->drawBitmapSR(mProfile->getBitmap(), offset + Point2I(mIndent, y), mProfile->mBitmapArrayRects[index]); } if(mButtonText[0] != '\0') diff --git a/Engine/source/gui/containers/guiFormCtrl.cpp b/Engine/source/gui/containers/guiFormCtrl.cpp index 3bf3289f4..8fd333071 100644 --- a/Engine/source/gui/containers/guiFormCtrl.cpp +++ b/Engine/source/gui/containers/guiFormCtrl.cpp @@ -277,7 +277,7 @@ void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect) Point2I barOffset(barStart, barTop); // Draw the start of the bar... - GFX->getDrawUtil()->drawBitmapStretchSR(mProfile->getBitmapResource(),RectI(barOffset, mProfile->mBitmapArrayRects[2].extent), mProfile->mBitmapArrayRects[2] ); + GFX->getDrawUtil()->drawBitmapStretchSR(mProfile->getBitmap(),RectI(barOffset, mProfile->mBitmapArrayRects[2].extent), mProfile->mBitmapArrayRects[2] ); // Now draw the middle... barOffset.x += mProfile->mBitmapArrayRects[2].extent.x; @@ -291,7 +291,7 @@ void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect) foo.inset(1,0); GFX->getDrawUtil()->drawBitmapStretchSR( - mProfile->getBitmapResource(), + mProfile->getBitmap(), RectI(barOffset, Point2I(barMiddleSize, mProfile->mBitmapArrayRects[3].extent.y)), foo ); @@ -300,7 +300,7 @@ void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect) // And the end barOffset.x += barMiddleSize; - GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->getBitmapResource(), RectI(barOffset, mProfile->mBitmapArrayRects[4].extent), + GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->getBitmap(), RectI(barOffset, mProfile->mBitmapArrayRects[4].extent), mProfile->mBitmapArrayRects[4]); GFX->getDrawUtil()->setBitmapModulation((mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor)); diff --git a/Engine/source/gui/containers/guiPaneCtrl.cpp b/Engine/source/gui/containers/guiPaneCtrl.cpp index d646e2f44..e5d3d70fa 100644 --- a/Engine/source/gui/containers/guiPaneCtrl.cpp +++ b/Engine/source/gui/containers/guiPaneCtrl.cpp @@ -193,7 +193,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) GFX->getDrawUtil()->clearBitmapModulation(); GFX->getDrawUtil()->drawBitmapStretchSR( - mProfile->getBitmapResource(), + mProfile->getBitmap(), RectI(offset, mProfile->mBitmapArrayRects[idx].extent), mProfile->mBitmapArrayRects[idx] ); @@ -226,7 +226,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) // Draw the start of the bar... GFX->getDrawUtil()->drawBitmapStretchSR( - mProfile->getBitmapResource(), + mProfile->getBitmap(), RectI(barOffset, mProfile->mBitmapArrayRects[2].extent), mProfile->mBitmapArrayRects[2] ); @@ -243,7 +243,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) foo.inset(1,0); GFX->getDrawUtil()->drawBitmapStretchSR( - mProfile->getBitmapResource(), + mProfile->getBitmap(), RectI(barOffset, Point2I(barMiddleSize, mProfile->mBitmapArrayRects[3].extent.y)), foo ); @@ -253,7 +253,7 @@ void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect) barOffset.x += barMiddleSize; GFX->getDrawUtil()->drawBitmapStretchSR( - mProfile->getBitmapResource(), + mProfile->getBitmap(), RectI(barOffset, mProfile->mBitmapArrayRects[4].extent), mProfile->mBitmapArrayRects[4] ); diff --git a/Engine/source/gui/containers/guiScrollCtrl.cpp b/Engine/source/gui/containers/guiScrollCtrl.cpp index c9f6d384f..d60060e7b 100644 --- a/Engine/source/gui/containers/guiScrollCtrl.cpp +++ b/Engine/source/gui/containers/guiScrollCtrl.cpp @@ -148,7 +148,7 @@ bool GuiScrollCtrl::onWake() if (! Parent::onWake()) return false; - mTextureObject = mProfile->getBitmapResource(); + mTextureObject = mProfile->getBitmap(); if (mTextureObject && (mProfile->constructBitmapArray() >= (U32)BmpStates * (U32)BmpCount)) { mBitmapBounds = mProfile->mBitmapArrayRects.address(); diff --git a/Engine/source/gui/containers/guiWindowCtrl.cpp b/Engine/source/gui/containers/guiWindowCtrl.cpp index bda7b0bfc..9100e7fe9 100644 --- a/Engine/source/gui/containers/guiWindowCtrl.cpp +++ b/Engine/source/gui/containers/guiWindowCtrl.cpp @@ -696,7 +696,7 @@ bool GuiWindowCtrl::onWake() return false; } - mTextureObject = mProfile->getBitmapResource(); + mTextureObject = mProfile->getBitmap(); mBitmapBounds = mProfile->mBitmapArrayRects.address(); S32 buttonHeight = mBitmapBounds[(U32)BmpStates * (U32)BmpClose].extent.y; diff --git a/Engine/source/gui/controls/guiBitmapBorderCtrl.cpp b/Engine/source/gui/controls/guiBitmapBorderCtrl.cpp index 05d0fea47..e0997215c 100644 --- a/Engine/source/gui/controls/guiBitmapBorderCtrl.cpp +++ b/Engine/source/gui/controls/guiBitmapBorderCtrl.cpp @@ -132,7 +132,7 @@ bool GuiBitmapBorderCtrl::onWake() //get the texture for the close, minimize, and maximize buttons mBitmapBounds = NULL; - mTextureObject = mProfile->getBitmapResource(); + mTextureObject = mProfile->getBitmap(); if( mProfile->constructBitmapArray() >= NumBitmaps ) mBitmapBounds = mProfile->mBitmapArrayRects.address(); else diff --git a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp index 4637a2285..0ea73a883 100644 --- a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp +++ b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp @@ -205,7 +205,7 @@ void GuiGameListMenuCtrl::onRenderListOption(Row* row, Point2I currentOffset) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretchSR(profile->getBitmapResource(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); + drawer->drawBitmapStretchSR(profile->getBitmap(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); // render the right arrow bool arrowOnR = (isRowSelected || isRowHighlighted) && (row->mWrapOptions || (row->mSelectedOption < row->mOptions.size() - 1)); @@ -214,7 +214,7 @@ void GuiGameListMenuCtrl::onRenderListOption(Row* row, Point2I currentOffset) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretchSR(profile->getBitmapResource(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); + drawer->drawBitmapStretchSR(profile->getBitmap(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); } // get the appropriate font color @@ -1758,7 +1758,7 @@ bool GuiGameListMenuProfile::onAdd() // We can't call enforceConstraints() here because incRefCount initializes // some of the things to enforce. Do a basic sanity check here instead. - U32 assetStatus = ImageAsset::getAssetErrCode(mBitmapAsset); + U32 assetStatus = ImageAsset::getAssetErrCode(getBitmapAsset()); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { Con::errorf( "GuiGameListMenuProfile: %s can't be created without a bitmap. Please add a 'Bitmap' property to the object definition.", getName() ); diff --git a/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp b/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp index f4d40ebe6..7793eb586 100644 --- a/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp +++ b/Engine/source/gui/controls/guiGameListOptionsCtrl.cpp @@ -111,7 +111,7 @@ void GuiGameListOptionsCtrl::onRender(Point2I offset, const RectI &updateRect) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretchSR(profile->getBitmapResource(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); + drawer->drawBitmapStretchSR(profile->getBitmap(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); // render the right arrow bool arrowOnR = (isRowSelected || isRowHighlighted) && (myRow->mWrapOptions || (myRow->mSelectedOption < myRow->mOptions.size() - 1)); @@ -120,7 +120,7 @@ void GuiGameListOptionsCtrl::onRender(Point2I offset, const RectI &updateRect) arrowOffset.y = currentOffset.y + arrowOffsetY; drawer->clearBitmapModulation(); - drawer->drawBitmapStretchSR(profile->getBitmapResource(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); + drawer->drawBitmapStretchSR(profile->getBitmap(), RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex)); } // get the appropriate font color diff --git a/Engine/source/gui/controls/guiSliderCtrl.cpp b/Engine/source/gui/controls/guiSliderCtrl.cpp index c5f4a90b6..4ab0d6850 100644 --- a/Engine/source/gui/controls/guiSliderCtrl.cpp +++ b/Engine/source/gui/controls/guiSliderCtrl.cpp @@ -432,9 +432,9 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect) drawUtil->clearBitmapModulation(); //left border - drawUtil->drawBitmapSR(mProfile->getBitmapResource(), Point2I(offset.x,offset.y), mBitmapBounds[SliderLineLeft]); + drawUtil->drawBitmapSR(mProfile->getBitmap(), Point2I(offset.x,offset.y), mBitmapBounds[SliderLineLeft]); //right border - drawUtil->drawBitmapSR(mProfile->getBitmapResource(), Point2I(offset.x + getWidth() - mBitmapBounds[SliderLineRight].extent.x, offset.y), mBitmapBounds[SliderLineRight]); + drawUtil->drawBitmapSR(mProfile->getBitmap(), Point2I(offset.x + getWidth() - mBitmapBounds[SliderLineRight].extent.x, offset.y), mBitmapBounds[SliderLineRight]); //draw our center piece to our slider control's border and stretch it @@ -448,11 +448,11 @@ void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect) stretchRect = mBitmapBounds[SliderLineCenter]; stretchRect.inset(1,0); - drawUtil->drawBitmapStretchSR(mProfile->getBitmapResource(), destRect, stretchRect); + drawUtil->drawBitmapStretchSR(mProfile->getBitmap(), destRect, stretchRect); //draw our control slider button thumb.point += pos; - drawUtil->drawBitmapSR(mProfile->getBitmapResource(),Point2I(thumb.point.x,offset.y ),mBitmapBounds[index]); + drawUtil->drawBitmapSR(mProfile->getBitmap(),Point2I(thumb.point.x,offset.y ),mBitmapBounds[index]); } else if (getWidth() >= getHeight()) diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index e1589aed5..3b95dd059 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -3781,7 +3781,7 @@ void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool ) if( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) ) { if( drawBitmap ) - drawer->drawBitmapSR( mProfile->getBitmapResource(), drawRect.point, mProfile->mBitmapArrayRects[bitmap] ); + drawer->drawBitmapSR( mProfile->getBitmap(), drawRect.point, mProfile->mBitmapArrayRects[bitmap] ); newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x; } diff --git a/Engine/source/gui/core/guiDefaultControlRender.cpp b/Engine/source/gui/core/guiDefaultControlRender.cpp index f5389968e..ff4bc1071 100644 --- a/Engine/source/gui/core/guiDefaultControlRender.cpp +++ b/Engine/source/gui/core/guiDefaultControlRender.cpp @@ -173,14 +173,14 @@ void renderBorder( const RectI &bounds, GuiControlProfile *profile ) // Draw all corners first. //top left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[BorderTopLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[BorderTopLeft]); //top right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[BorderTopRight].extent.x,bounds.point.y),mBitmapBounds[BorderTopRight]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[BorderTopRight].extent.x,bounds.point.y),mBitmapBounds[BorderTopRight]); //bottom left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y),mBitmapBounds[BorderBottomLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y),mBitmapBounds[BorderBottomLeft]); //bottom right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I( + drawer->drawBitmapSR(profile->getBitmap(),Point2I( bounds.point.x + bounds.extent.x - mBitmapBounds[BorderBottomRight].extent.x, bounds.point.y + bounds.extent.y - mBitmapBounds[BorderBottomRight].extent.y), mBitmapBounds[BorderBottomRight]); @@ -198,7 +198,7 @@ void renderBorder( const RectI &bounds, GuiControlProfile *profile ) stretchRect = mBitmapBounds[BorderTop]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //bottom line stretch destRect.point.x = bounds.point.x + mBitmapBounds[BorderBottomLeft].extent.x; destRect.extent.x = bounds.extent.x - mBitmapBounds[BorderBottomRight].extent.x - mBitmapBounds[BorderBottomLeft].extent.x; @@ -208,7 +208,7 @@ void renderBorder( const RectI &bounds, GuiControlProfile *profile ) stretchRect = mBitmapBounds[BorderBottom]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //left line stretch destRect.point.x = bounds.point.x; destRect.extent.x = mBitmapBounds[BorderLeft].extent.x; @@ -218,7 +218,7 @@ void renderBorder( const RectI &bounds, GuiControlProfile *profile ) stretchRect = mBitmapBounds[BorderLeft]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //right line stretch destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[BorderRight].extent.x; destRect.extent.x = mBitmapBounds[BorderRight].extent.x; @@ -228,7 +228,7 @@ void renderBorder( const RectI &bounds, GuiControlProfile *profile ) stretchRect = mBitmapBounds[BorderRight]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); // End drawing sides and top stretched borders break; @@ -288,14 +288,14 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, // Draw all corners first. //top left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]); //top right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]); //bottom left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]); //bottom right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I( + drawer->drawBitmapSR(profile->getBitmap(),Point2I( bounds.point.x + bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x, bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomRight].extent.y), mBitmapBounds[borderBottomRight]); @@ -313,7 +313,7 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, stretchRect = mBitmapBounds[borderTop]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //bottom line stretch destRect.point.x = bounds.point.x + mBitmapBounds[borderBottomLeft].extent.x; destRect.extent.x = bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x - mBitmapBounds[borderBottomLeft].extent.x; @@ -323,7 +323,7 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, stretchRect = mBitmapBounds[borderBottom]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //left line stretch destRect.point.x = bounds.point.x; destRect.extent.x = mBitmapBounds[borderLeft].extent.x; @@ -333,7 +333,7 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, stretchRect = mBitmapBounds[borderLeft]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //right line stretch destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x; destRect.extent.x = mBitmapBounds[borderRight].extent.x; @@ -343,7 +343,7 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, stretchRect = mBitmapBounds[borderRight]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //fill stretch destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x; destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x; @@ -353,7 +353,7 @@ void renderSizableBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, stretchRect = mBitmapBounds[fill]; stretchRect.inset(1,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); // End drawing sides and top stretched borders } @@ -388,14 +388,14 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, // Draw all corners first. //top left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderTopLeft]); //top right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderTopRight].extent.x,bounds.point.y),mBitmapBounds[borderTopRight]); //bottom left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomLeft].extent.y),mBitmapBounds[borderBottomLeft]); //bottom right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I( + drawer->drawBitmapSR(profile->getBitmap(),Point2I( bounds.point.x + bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x, bounds.point.y + bounds.extent.y - mBitmapBounds[borderBottomRight].extent.y), mBitmapBounds[borderBottomRight]); @@ -413,7 +413,7 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, stretchRect = mBitmapBounds[borderTop]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //bottom line stretch destRect.point.x = bounds.point.x + mBitmapBounds[borderBottomLeft].extent.x; destRect.extent.x = bounds.extent.x - mBitmapBounds[borderBottomRight].extent.x - mBitmapBounds[borderBottomLeft].extent.x; @@ -423,7 +423,7 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, stretchRect = mBitmapBounds[borderBottom]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //left line stretch destRect.point.x = bounds.point.x; destRect.extent.x = mBitmapBounds[borderLeft].extent.x; @@ -433,7 +433,7 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, stretchRect = mBitmapBounds[borderLeft]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //left line stretch destRect.point.x = bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x; destRect.extent.x = mBitmapBounds[borderRight].extent.x; @@ -443,7 +443,7 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, stretchRect = mBitmapBounds[borderRight]; stretchRect.inset(0,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); //fill stretch destRect.point.x = bounds.point.x + mBitmapBounds[borderLeft].extent.x; destRect.extent.x = (bounds.extent.x) - mBitmapBounds[borderLeft].extent.x - mBitmapBounds[borderRight].extent.x; @@ -453,7 +453,7 @@ void renderSizableBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, stretchRect = mBitmapBounds[fill]; stretchRect.inset(1,1); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); // End drawing sides and top stretched borders } @@ -484,9 +484,9 @@ void renderFixedBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, Gu // Draw all corners first. //left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]); //right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]); // End drawing corners @@ -501,7 +501,7 @@ void renderFixedBitmapBordersFilled( const RectI &bounds, S32 baseMultiplier, Gu stretchRect = mBitmapBounds[fill]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); // End drawing fill } @@ -529,9 +529,9 @@ void renderFixedBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, G // Draw all corners first. //left border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x,bounds.point.y),mBitmapBounds[borderLeft]); //right border - drawer->drawBitmapSR(profile->getBitmapResource(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]); + drawer->drawBitmapSR(profile->getBitmap(),Point2I(bounds.point.x + bounds.extent.x - mBitmapBounds[borderRight].extent.x,bounds.point.y),mBitmapBounds[borderRight]); // End drawing corners @@ -546,7 +546,7 @@ void renderFixedBitmapBordersFilledIndex( const RectI &bounds, S32 startIndex, G stretchRect = mBitmapBounds[fill]; stretchRect.inset(1,0); //draw it - drawer->drawBitmapStretchSR(profile->getBitmapResource(),destRect,stretchRect); + drawer->drawBitmapStretchSR(profile->getBitmap(),destRect,stretchRect); // End drawing fill } diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index db85c628a..ce1382203 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -179,7 +179,7 @@ void GuiControlProfile::setBitmapHandle(GFXTexHandle handle) { mBitmap = handle; - _setBitmap(StringTable->insert("texhandle")); + mBitmapName = "texhandle"; } bool GuiControlProfile::protectedSetBitmap( void *object, const char *index, const char *data ) @@ -196,16 +196,17 @@ bool GuiControlProfile::protectedSetBitmap( void *object, const char *index, con profile->mBitmapArrayRects.clear(); profile->mBitmap = nullptr; - if (profile->getBitmap() != StringTable->EmptyString()) + if (profile->mBitmapName != StringTable->EmptyString()) { - if (profile->mBitmapAsset.notNull() && profile->getBitmap() != StringTable->insert("texHandle")) + if (profile->mBitmapAsset.notNull() && profile->mBitmapName != StringTable->insert("texHandle")) { - profile->mBitmap.set(profile->mBitmapAsset->getImageFile(), profile->mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + profile->mBitmap = profile->getBitmap(); + profile->mBitmapName = profile->mBitmapAsset->getImageFile(); } //verify the bitmap if (!profile->mBitmap) - Con::errorf("(%s) - Failed to load profile bitmap (%s)", profile->getName(), profile->getBitmap()); + Con::errorf("(%s) - Failed to load profile bitmap (%s)", profile->getName(), profile->getBitmapAsset().getAssetId()); // If we've got a special border, make sure it's usable. //if( profile->mBorder == -1 || profile->mBorder == -2 ) @@ -271,7 +272,9 @@ GuiControlProfile::GuiControlProfile(void) : mMouseOverSelected = false; // bitmap members - INIT_ASSET(Bitmap); + mBitmap = NULL; + mBitmapName = StringTable->EmptyString(); + mUseBitmapArray = false; mChildrenProfileName = NULL; @@ -438,7 +441,7 @@ void GuiControlProfile::initPersistFields() "Texture to use for rendering control.", AbstractClassRep::FIELD_HideInInspectors); #endif - addProtectedField("bitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiControlProfile), + addProtectedField("bitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiControlProfile), &GuiControlProfile::protectedSetBitmap, &defaultProtectedGetFn, "Texture to use for rendering control."); @@ -546,15 +549,12 @@ S32 GuiControlProfile::constructBitmapArray() if( mBitmap.isNull() ) { - if (!_setBitmap(getBitmap())) - return 0; - - if (getBitmap() != StringTable->EmptyString() && mBitmapName != StringTable->insert("texhandle")) + if (mBitmapAsset.notNull() && mBitmapName != StringTable->insert("texhandle")) { - mBitmap.set(getBitmap(), mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + mBitmap = getBitmap(); } - if (getBitmap() == StringTable->EmptyString() || mBitmap.isNull()) + if (mBitmapAsset.isNull() || mBitmap.isNull()) return 0; } @@ -564,8 +564,8 @@ S32 GuiControlProfile::constructBitmapArray() ColorI sepColor; if ( !bmp || !bmp->getColor( 0, 0, sepColor ) ) { - Con::errorf("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", getBitmap(), getName()); - AssertFatal( false, avar("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", getBitmap(), getName())); + Con::errorf("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", getBitmapAsset().getAssetId(), getName()); + AssertFatal( false, avar("Failed to create bitmap array from %s for profile %s - couldn't ascertain seperator color!", getBitmapAsset().getAssetId(), getName())); return 0; } @@ -640,20 +640,16 @@ void GuiControlProfile::incLoadCount() if( mFont == NULL ) loadFont(); - // - if (getBitmap() != StringTable->EmptyString()) + if (mBitmapAsset.notNull() && mBitmapName != StringTable->insert("texHandle")) { - if (mBitmapAsset.notNull() && getBitmap() != StringTable->insert("texHandle")) - { - mBitmap.set(mBitmapAsset->getImageFile(), mBitmapProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); - } - - //verify the bitmap - if (!mBitmap) - Con::errorf("(%s) - Failed to load profile bitmap (%s)", getName(), getBitmap()); - - constructBitmapArray(); + mBitmap = getBitmap(); } + + //verify the bitmap + if (!mBitmap) + Con::errorf("(%s) - Failed to load profile bitmap (%s)", getName(), getBitmapAsset().getAssetId()); + + constructBitmapArray(); } mLoadCount ++; @@ -676,7 +672,7 @@ void GuiControlProfile::decLoadCount() getId(), getClassName(), getName(), getInternalName() ); #endif - StringTableEntry bitmapName = getBitmap(); + StringTableEntry bitmapName = getBitmapAsset().getAssetId(); if(bitmapName == StringTable->EmptyString() || bitmapName == StringTable->insert("texhandle")) mBitmap = NULL; } @@ -704,15 +700,15 @@ DefineEngineMethod( GuiControlProfile, getStringWidth, S32, (const char* string) DefineEngineMethod(GuiControlProfile, getBitmap, const char*, (), , "get name") { - return object->getBitmap(); + return object->getBitmapAsset()->getImageFile(); } DefineEngineMethod(GuiControlProfile, getBitmapAsset, const char*, (), , "") { - return object->mBitmapAssetId; + return object->getBitmapAsset().getAssetId(); } -DefineEngineMethod(GuiControlProfile, setBitmap, bool, (const char* map), , "") +DefineEngineMethod(GuiControlProfile, setBitmap, void, (const char* map), , "") { - return object->_setBitmap(StringTable->insert(map)); + object->_setBitmap(StringTable->insert(map)); } //----------------------------------------------------------------------------- diff --git a/Engine/source/gui/core/guiTypes.h b/Engine/source/gui/core/guiTypes.h index 7acb37fd7..4ede98303 100644 --- a/Engine/source/gui/core/guiTypes.h +++ b/Engine/source/gui/core/guiTypes.h @@ -457,105 +457,11 @@ public: ///< Bitmap for the bitmap of the control /// public: - GFXTexHandle mBitmap = NULL; - StringTableEntry mBitmapName; - StringTableEntry mBitmapAssetId; - AssetPtr mBitmapAsset; - GFXTextureProfile* mBitmapProfile = &GFXDefaultGUIProfile; -public: - const StringTableEntry getBitmapFile() const { return mBitmapName; } - void setBitmapFile(const FileName& _in) { mBitmapName = StringTable->insert(_in.c_str()); } - const AssetPtr& getBitmapAsset() const { return mBitmapAsset; } - void setBitmapAsset(const AssetPtr& _in) { mBitmapAsset = _in; } - - bool _setBitmap(StringTableEntry _in) - { - if (mBitmapAssetId != _in || mBitmapName != _in) - { - if (_in == StringTable->EmptyString()) - { - mBitmapName = StringTable->EmptyString(); - mBitmapAssetId = StringTable->EmptyString(); - mBitmapAsset = NULL; - mBitmap.free(); - mBitmap = NULL; - return true; - } - else if (_in[0] == '$' || _in[0] == '#') - { - mBitmapName = _in; - mBitmapAssetId = StringTable->EmptyString(); - mBitmapAsset = NULL; - mBitmap.free(); - mBitmap = NULL; - return true; - } - - if (AssetDatabase.isDeclaredAsset(_in)) - { - mBitmapAssetId = _in; - - U32 assetState = ImageAsset::getAssetById(mBitmapAssetId, &mBitmapAsset); - - if (ImageAsset::Ok == assetState) - { - mBitmapName = StringTable->EmptyString(); - } - } - else - { - StringTableEntry assetId = ImageAsset::getAssetIdByFilename(_in); - if (assetId != StringTable->EmptyString()) - { - mBitmapAssetId = assetId; - if (ImageAsset::getAssetById(mBitmapAssetId, &mBitmapAsset) == ImageAsset::Ok) - { - mBitmapName = StringTable->EmptyString(); - } - } - else - { - mBitmapName = _in; - mBitmapAssetId = StringTable->EmptyString(); - mBitmapAsset = NULL; - } - } - } - if (getBitmap() != StringTable->EmptyString() && mBitmapName != StringTable->insert("texhandle")) - { - } - else - { - mBitmap.free(); - mBitmap = NULL; - } - - if (getBitmap() != StringTable->EmptyString() && mBitmapAsset.notNull() && mBitmapAsset->getStatus() != ImageAsset::Ok) - { - Con::errorf("%s(%s)::_set%s() - image asset failure \"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ImageAsset::getAssetErrstrn(mBitmapAsset->getStatus()).c_str()); - return false; - } - return true; - } - - const StringTableEntry getBitmap() const - { - if (mBitmapAsset && (mBitmapAsset->getImageFile() != StringTable->EmptyString())) - return Platform::makeRelativePathName(mBitmapAsset->getImageFile(), Platform::getMainDotCsDir()); - else if (mBitmapAssetId != StringTable->EmptyString()) - return mBitmapAssetId; - else if (mBitmapName != StringTable->EmptyString()) - return StringTable->insert(Platform::makeRelativePathName(mBitmapName, Platform::getMainDotCsDir())); - else - return StringTable->EmptyString(); - } - GFXTexHandle getBitmapResource() - { - return mBitmap; - } - DECLARE_ASSET_SETGET(GuiControlProfile, Bitmap); - void onBitmapChanged() {} + DECLARE_IMAGEASSET_REFACTOR(GuiControlProfile, Bitmap, GFXDefaultGUIProfile) + + GFXTexHandle mBitmap; + StringTableEntry mBitmapName; bool mUseBitmapArray; ///< Flag to use the bitmap array or to fallback to non-array rendering Vector mBitmapArrayRects; ///< Used for controls which use an array of bitmaps such as checkboxes diff --git a/Engine/source/gui/editor/guiMenuBar.cpp b/Engine/source/gui/editor/guiMenuBar.cpp index cae69d291..e71ce80e6 100644 --- a/Engine/source/gui/editor/guiMenuBar.cpp +++ b/Engine/source/gui/editor/guiMenuBar.cpp @@ -409,7 +409,7 @@ void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect) bitmapstart.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - rect.extent.y) / 2; drawUtil->clearBitmapModulation(); - drawUtil->drawBitmapSR(mProfile->getBitmapResource(), offset + bitmapstart, rect); + drawUtil->drawBitmapSR(mProfile->getBitmap(), offset + bitmapstart, rect); // Should we also draw the text? if (!mMenuList[i].drawBitmapOnly) diff --git a/Engine/source/gui/editor/guiPopupMenuCtrl.cpp b/Engine/source/gui/editor/guiPopupMenuCtrl.cpp index 2a72c09b0..572c0ab08 100644 --- a/Engine/source/gui/editor/guiPopupMenuCtrl.cpp +++ b/Engine/source/gui/editor/guiPopupMenuCtrl.cpp @@ -142,7 +142,7 @@ void GuiPopupMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool s Point2I bitPos = Point2I(offset.x + mCellSize.y / 2, offset.y + mCellSize.y / 2); GFX->getDrawUtil()->clearBitmapModulation(); - GFX->getDrawUtil()->drawBitmapSR(mProfile->getBitmapResource(), bitPos + off, rect); + GFX->getDrawUtil()->drawBitmapSR(mProfile->getBitmap(), bitPos + off, rect); } } diff --git a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp index 7cdda0f03..183634028 100644 --- a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp +++ b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp @@ -220,14 +220,14 @@ void GuiProgressBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) //drawing stretch bitmap RectI progressRect = ctrlRect; progressRect.extent.x = width; - drawUtil->drawBitmapStretchSR(mProfile->getBitmapResource(), progressRect, mProfile->mBitmapArrayRects[0]); + drawUtil->drawBitmapStretchSR(mProfile->getBitmap(), progressRect, mProfile->mBitmapArrayRects[0]); } } else if(mNumberOfBitmaps >= 3) { //drawing left-end bitmap RectI progressRectLeft(ctrlRect.point.x, ctrlRect.point.y, mDim, mDim); - drawUtil->drawBitmapStretchSR(mProfile->getBitmapResource(), progressRectLeft, mProfile->mBitmapArrayRects[0]); + drawUtil->drawBitmapStretchSR(mProfile->getBitmap(), progressRectLeft, mProfile->mBitmapArrayRects[0]); //draw the progress with image S32 width = (S32)((F32)(getWidth()) * mProgress); @@ -239,11 +239,11 @@ void GuiProgressBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) progressRect.extent.x = (width - mDim - mDim); if (progressRect.extent.x < 0) progressRect.extent.x = 0; - drawUtil->drawBitmapStretchSR(mProfile->getBitmapResource(), progressRect, mProfile->mBitmapArrayRects[1]); + drawUtil->drawBitmapStretchSR(mProfile->getBitmap(), progressRect, mProfile->mBitmapArrayRects[1]); //drawing right-end bitmap RectI progressRectRight(progressRect.point.x + progressRect.extent.x, ctrlRect.point.y, mDim, mDim ); - drawUtil->drawBitmapStretchSR(mProfile->getBitmapResource(), progressRectRight, mProfile->mBitmapArrayRects[2]); + drawUtil->drawBitmapStretchSR(mProfile->getBitmap(), progressRectRight, mProfile->mBitmapArrayRects[2]); } } else From eb746a11427f85de5449e7b6dc66619b770c7dc1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 26 Dec 2024 13:59:46 +0000 Subject: [PATCH 09/47] console spam moved error printout in guiType guiControlProfile incLoadCount inside a check to make sure the profile has a bitmap asset set. remove older typeImageAssetId from group and variable inspector classes --- Engine/source/T3D/assets/ImageAsset.cpp | 2 +- Engine/source/gui/core/guiTypes.cpp | 12 ++++++------ Engine/source/gui/editor/inspector/group.cpp | 2 +- .../gui/editor/inspector/variableInspector.cpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index cec0cb496..8f62bd7f9 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -116,7 +116,7 @@ ConsoleSetType(TypeImageAssetId) IMPLEMENT_STRUCT(AssetPtr, AssetPtrImageAsset,, "") END_IMPLEMENT_STRUCT -ConsoleType(ImageAssetPtr, TypeImageAssetPtrRefactor, AssetPtr, "") +ConsoleType(ImageAssetPtr, TypeImageAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) ConsoleGetType(TypeImageAssetPtrRefactor) diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index ce1382203..bd5532aae 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -643,13 +643,13 @@ void GuiControlProfile::incLoadCount() if (mBitmapAsset.notNull() && mBitmapName != StringTable->insert("texHandle")) { mBitmap = getBitmap(); + + //verify the bitmap + if (!mBitmap) + Con::errorf("(%s) - Failed to load profile bitmap (%s)", getName(), getBitmapAsset().getAssetId()); + + constructBitmapArray(); } - - //verify the bitmap - if (!mBitmap) - Con::errorf("(%s) - Failed to load profile bitmap (%s)", getName(), getBitmapAsset().getAssetId()); - - constructBitmapArray(); } mLoadCount ++; diff --git a/Engine/source/gui/editor/inspector/group.cpp b/Engine/source/gui/editor/inspector/group.cpp index 2f517d52d..3dfd19248 100644 --- a/Engine/source/gui/editor/inspector/group.cpp +++ b/Engine/source/gui/editor/inspector/group.cpp @@ -663,7 +663,7 @@ void GuiInspectorGroup::addInspectorField(StringTableEntry name, StringTableEntr else if (typeName == StringTable->insert("material")) fieldType = TypeMaterialAssetId; else if (typeName == StringTable->insert("image")) - fieldType = TypeImageAssetId; + fieldType = TypeImageAssetPtrRefactor; else if (typeName == StringTable->insert("shape")) fieldType = TypeShapeAssetId; else if (typeName == StringTable->insert("sound")) diff --git a/Engine/source/gui/editor/inspector/variableInspector.cpp b/Engine/source/gui/editor/inspector/variableInspector.cpp index c856c8b1a..80195fc00 100644 --- a/Engine/source/gui/editor/inspector/variableInspector.cpp +++ b/Engine/source/gui/editor/inspector/variableInspector.cpp @@ -203,7 +203,7 @@ void GuiVariableInspector::addField(const char* name, const char* label, const c else if (newField->mFieldTypeName == StringTable->insert("material")) fieldTypeMask = TypeMaterialAssetId; else if (newField->mFieldTypeName == StringTable->insert("image")) - fieldTypeMask = TypeImageAssetId; + fieldTypeMask = TypeImageAssetPtrRefactor; else if (newField->mFieldTypeName == StringTable->insert("shape")) fieldTypeMask = TypeShapeAssetId; else if (newField->mFieldTypeName == StringTable->insert("bool")) From 4d980e5406161d3c588b4bb9c4907d438d391b31 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 26 Dec 2024 14:36:05 +0000 Subject: [PATCH 10/47] various cleanups and fixes basicClouds refactored null dereference fixes in guiMenuBar --- Engine/source/T3D/assets/ImageAsset.h | 39 +++++++++++++++++++- Engine/source/T3D/assets/assetMacroHelpers.h | 25 ++++++++++++- Engine/source/T3D/fx/splash.cpp | 8 ++-- Engine/source/environment/basicClouds.cpp | 27 +++++--------- Engine/source/environment/basicClouds.h | 5 +-- Engine/source/gui/editor/guiMenuBar.cpp | 32 ++++++++++++++-- 6 files changed, 104 insertions(+), 32 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 4635a3223..4a90cabdb 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -618,7 +618,8 @@ public: AssetPtr get##name##Asset(void) { return m##name##Asset; } \ static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} -#define DECLARE_IMAGEASSET_NET_REFACTOR(className, name, profile, mask) \ + +#define DECLARE_IMAGEASSET_NET_REFACTOR(className, name, profile, mask) \ private: \ AssetPtr m##name##Asset; \ public: \ @@ -647,7 +648,8 @@ public: inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ GFXTexHandle get##name() { return m##name##Asset.notNull() ? m##name##Asset->getTexture(&profile) : NULL; } \ AssetPtr get##name##Asset(void) { return m##name##Asset; } \ - static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} + #define INITPERSISTFIELD_IMAGEASSET_REFACTOR(name, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); @@ -683,6 +685,39 @@ public: AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} + +#define DECLARE_IMAGEASSET_ARRAY_NET_REFACTOR(className, name, profile, max, mask) \ +private: \ + AssetPtr m##name##Asset[max]; \ +public: \ + void _set##name(StringTableEntry _in, const U32& index){ \ + if(m##name##Asset[index].getAssetId() == _in) \ + return; \ + \ + if(!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset[index] = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset[index] = _in; \ + } \ + setMaskBits(mask); \ + }; \ + \ + inline StringTableEntry _get##name(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ + GFXTexHandle get##name(const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(&profile) : NULL; } \ + AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} + + #define INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); diff --git a/Engine/source/T3D/assets/assetMacroHelpers.h b/Engine/source/T3D/assets/assetMacroHelpers.h index e706883b1..ebe777bf0 100644 --- a/Engine/source/T3D/assets/assetMacroHelpers.h +++ b/Engine/source/T3D/assets/assetMacroHelpers.h @@ -88,7 +88,7 @@ if (m##name##AssetId != StringTable->EmptyString())\ //network send - datablock #define PACKDATA_ASSET_ARRAY_REFACTOR(name, max)\ -for (i = 0; i < max; i++)\ +for (U32 i = 0; i < max; i++)\ {\ if (stream->writeFlag(m##name##Asset[i].notNull()))\ {\ @@ -98,7 +98,7 @@ for (i = 0; i < max; i++)\ //network recieve - datablock #define UNPACKDATA_ASSET_ARRAY_REFACTOR(name, max)\ -for (i = 0; i < max; i++)\ +for (U32 i = 0; i < max; i++)\ {\ if (stream->readFlag())\ {\ @@ -106,6 +106,27 @@ for (i = 0; i < max; i++)\ }\ } +//network send - object-instance +#define PACK_ASSET_ARRAY_REFACTOR(netconn, name, max)\ +for (U32 i = 0; i < max; i++)\ +{\ + if (stream->writeFlag(m##name##Asset[i].notNull()))\ + {\ + NetStringHandle assetIdStr = m##name##Asset[i].getAssetId();\ + netconn->packNetStringHandleU(stream, assetIdStr);\ + }\ +} + +//network recieve - object-instance +#define UNPACK_ASSET_ARRAY_REFACTOR(netconn, name, max)\ +for (U32 i = 0; i < max; i++)\ +{\ + if (stream->readFlag())\ + {\ + m##name##Asset[i] = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\ + }\ +} + #define DEF_ASSET_BINDS_REFACTOR(className,name)\ DefineEngineMethod(className, get##name, StringTableEntry, (), , "get name")\ {\ diff --git a/Engine/source/T3D/fx/splash.cpp b/Engine/source/T3D/fx/splash.cpp index 205575672..1cc697d07 100644 --- a/Engine/source/T3D/fx/splash.cpp +++ b/Engine/source/T3D/fx/splash.cpp @@ -183,6 +183,8 @@ void SplashData::packData(BitStream* stream) stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); } + PACKDATA_ASSET_ARRAY_REFACTOR(Texture, NUM_TEX); + S32 i; for( i=0; iwrite( times[i] ); } - - PACKDATA_ASSET_ARRAY_REFACTOR(Texture, NUM_TEX); } //-------------------------------------------------------------------------- @@ -236,6 +236,8 @@ void SplashData::unpackData(BitStream* stream) explosionId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); } + UNPACKDATA_ASSET_ARRAY_REFACTOR(Texture, NUM_TEX); + U32 i; for( i=0; iread( ×[i] ); } - - UNPACKDATA_ASSET_ARRAY_REFACTOR(Texture, NUM_TEX); } //-------------------------------------------------------------------------- diff --git a/Engine/source/environment/basicClouds.cpp b/Engine/source/environment/basicClouds.cpp index b4b7a9765..2d3945c1d 100644 --- a/Engine/source/environment/basicClouds.cpp +++ b/Engine/source/environment/basicClouds.cpp @@ -98,9 +98,6 @@ BasicClouds::BasicClouds() mTexOffset[0].set( 0.5f, 0.5f ); mTexOffset[1].set( 0.5f, 0.5f ); mTexOffset[2].set( 0.5f, 0.5f ); - - for (U32 i=0; i< TEX_COUNT;i++) - INIT_IMAGEASSET_ARRAY(Texture, GFXStaticTextureSRGBProfile, i); } IMPLEMENT_CO_NETOBJECT_V1( BasicClouds ); @@ -177,7 +174,7 @@ void BasicClouds::initPersistFields() addField( "layerEnabled", TypeBool, Offset( mLayerEnabled, BasicClouds ), TEX_COUNT, "Enable or disable rendering of this layer." ); - INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, TEX_COUNT, BasicClouds, "Texture for this layer."); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Texture, TEX_COUNT, BasicClouds, "Texture for this layer."); addField( "texScale", TypeF32, Offset( mTexScale, BasicClouds ), TEX_COUNT, "Texture repeat for this layer." ); @@ -215,12 +212,11 @@ U32 BasicClouds::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) { U32 retMask = Parent::packUpdate( conn, mask, stream ); + PACK_ASSET_ARRAY_REFACTOR(conn, Texture, TEX_COUNT) + for ( U32 i = 0; i < TEX_COUNT; i++ ) { stream->writeFlag( mLayerEnabled[i] ); - - PACK_ASSET_ARRAY(conn, Texture, i); - stream->write( mTexScale[i] ); mathWrite( *stream, mTexDirection[i] ); stream->write( mTexSpeed[i] ); @@ -236,12 +232,11 @@ void BasicClouds::unpackUpdate( NetConnection *conn, BitStream *stream ) { Parent::unpackUpdate( conn, stream ); + UNPACK_ASSET_ARRAY_REFACTOR(conn, Texture, TEX_COUNT) + for ( U32 i = 0; i < TEX_COUNT; i++ ) { mLayerEnabled[i] = stream->readFlag(); - - UNPACK_ASSET_ARRAY(conn, Texture, i); - stream->read( &mTexScale[i] ); mathRead( *stream, &mTexDirection[i] ); stream->read( &mTexSpeed[i] ); @@ -315,14 +310,14 @@ void BasicClouds::renderObject( ObjectRenderInst *ri, SceneRenderState *state, B for ( U32 i = 0; i < TEX_COUNT; i++ ) { - if ( !mLayerEnabled[i] ) + if ( !mLayerEnabled[i] || mTextureAsset[i].isNull()) continue; mShaderConsts->setSafe( mTexScaleSC, mTexScale[i] ); mShaderConsts->setSafe( mTexDirectionSC, mTexDirection[i] * mTexSpeed[i] ); mShaderConsts->setSafe( mTexOffsetSC, mTexOffset[i] ); - GFX->setTexture( mDiffuseMapSC->getSamplerRegister(), mTexture[i] ); + GFX->setTexture( mDiffuseMapSC->getSamplerRegister(), getTexture(i) ); GFX->setVertexBuffer( mVB[i] ); GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount ); @@ -337,13 +332,11 @@ void BasicClouds::_initTexture() { for ( U32 i = 0; i < TEX_COUNT; i++ ) { - if ( !mLayerEnabled[i] ) + if ( mLayerEnabled[i] && mTextureAsset[i].notNull()) { - mTexture[i] = NULL; - continue; + // load the resource. + getTexture(i); } - - _setTexture(getTexture(i), i); } } diff --git a/Engine/source/environment/basicClouds.h b/Engine/source/environment/basicClouds.h index bd67d1362..8157212ff 100644 --- a/Engine/source/environment/basicClouds.h +++ b/Engine/source/environment/basicClouds.h @@ -94,9 +94,8 @@ protected: static U32 smVertCount; static U32 smTriangleCount; - DECLARE_IMAGEASSET_ARRAY(BasicClouds, Texture, TEX_COUNT, onTextureChanged); - DECLARE_IMAGEASSET_ARRAY_NET_SETGET(BasicClouds, Texture, -1); - void onTextureChanged() {} + DECLARE_IMAGEASSET_ARRAY_NET_REFACTOR(BasicClouds, Texture, GFXStaticTextureSRGBProfile, TEX_COUNT, -1) + GFXStateBlockRef mStateblock; GFXShaderRef mShader; diff --git a/Engine/source/gui/editor/guiMenuBar.cpp b/Engine/source/gui/editor/guiMenuBar.cpp index e71ce80e6..399fc916d 100644 --- a/Engine/source/gui/editor/guiMenuBar.cpp +++ b/Engine/source/gui/editor/guiMenuBar.cpp @@ -515,10 +515,22 @@ void GuiMenuBar::processTick() void GuiMenuBar::insert(SimObject* pObject, S32 pos) { - PopupMenu* menu = dynamic_cast(pObject); + PopupMenu* menu = nullptr; + if (pObject != nullptr) + { + menu = dynamic_cast(pObject); + } + if (menu == nullptr) { - Con::errorf("GuiMenuBar::insert() - attempted to insert non-popupMenu object: %d", pObject->getId()); + if (pObject != nullptr) + { + Con::errorf("GuiMenuBar::insert() - attempted to insert non-popupMenu object: %d", pObject->getId()); + } + else + { + Con::errorf("GuiMenuBar::insert() - attempted to insert a nullptr object."); + } return; } @@ -541,10 +553,22 @@ void GuiMenuBar::insert(SimObject* pObject, S32 pos) void GuiMenuBar::remove(SimObject* pObject) { - PopupMenu* menu = dynamic_cast(pObject); + PopupMenu* menu = nullptr; + if (pObject != nullptr) + { + menu = dynamic_cast(pObject); + } + if (menu == nullptr) { - Con::errorf("GuiMenuBar::remove() - attempted to remove non-popupMenu object: %d", pObject->getId()); + if (pObject != nullptr) + { + Con::errorf("GuiMenuBar::insert() - attempted to insert non-popupMenu object: %d", pObject->getId()); + } + else + { + Con::errorf("GuiMenuBar::insert() - attempted to insert a nullptr object."); + } return; } From cebfdbc5ec225364d9fae9a9e8e567d115c2ee49 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 27 Dec 2024 12:53:04 +0000 Subject: [PATCH 11/47] material definition changing the beast over to the refactor --- Engine/source/T3D/assets/ImageAsset.h | 15 +++++++ Engine/source/T3D/assets/MaterialAsset.cpp | 4 +- Engine/source/T3D/assets/assetImporter.cpp | 4 +- Engine/source/T3D/fx/groundCover.cpp | 8 ++-- .../source/materials/materialDefinition.cpp | 43 ++++--------------- Engine/source/materials/materialDefinition.h | 13 ++---- Engine/source/materials/processedMaterial.cpp | 40 +++-------------- .../materials/processedShaderMaterial.cpp | 4 +- .../renderInstance/renderDeferredMgr.cpp | 7 ++- Engine/source/ts/assimp/assimpAppMaterial.cpp | 4 +- .../source/ts/collada/colladaAppMaterial.cpp | 4 +- Engine/source/ts/collada/colladaUtils.cpp | 16 +++---- Engine/source/ts/tsLastDetail.cpp | 4 +- 13 files changed, 61 insertions(+), 105 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 4a90cabdb..78209b95b 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -721,5 +721,20 @@ public: #define INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); +#define DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(className,name, max)\ +DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\ +{\ + return object->get##name##Asset(index).notNull() ? object->get##name##Asset(index)->getImageFile() : ""; \ +}\ +DefineEngineMethod(className, get##name##Asset, const char*, (S32 index), , assetText(name, asset reference))\ +{\ + if(index >= max || index < 0)\ + return "";\ + return object->_get##name(index); \ +}\ +DefineEngineMethod(className, set##name, void, (const char* map, S32 index), , assetText(name,assignment. first tries asset then flat file.))\ +{\ + object->_set##name(StringTable->insert(map), index);\ +} #pragma endregion diff --git a/Engine/source/T3D/assets/MaterialAsset.cpp b/Engine/source/T3D/assets/MaterialAsset.cpp index abedd6204..43b876dc1 100644 --- a/Engine/source/T3D/assets/MaterialAsset.cpp +++ b/Engine/source/T3D/assets/MaterialAsset.cpp @@ -644,7 +644,7 @@ void GuiInspectorTypeMaterialAssetPtr::updatePreviewImage() MaterialAsset* matAsset = AssetDatabase.acquireAsset(previewImage); if (matAsset && matAsset->getMaterialDefinition()) { - mPreviewImage->_setBitmap(matAsset->getMaterialDefinition()->mDiffuseMapAssetId[0]); + mPreviewImage->_setBitmap(matAsset->getMaterialDefinition()->_getDiffuseMap(0)); } } } @@ -676,7 +676,7 @@ void GuiInspectorTypeMaterialAssetPtr::setPreviewImage(StringTableEntry assetId) MaterialAsset* matAsset = AssetDatabase.acquireAsset(assetId); if (matAsset && matAsset->getMaterialDefinition()) { - mPreviewImage->_setBitmap(matAsset->getMaterialDefinition()->mDiffuseMapAssetId[0]); + mPreviewImage->_setBitmap(matAsset->getMaterialDefinition()->_getDiffuseMap(0)); } } } diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 3f0e514df..ba8ad9eb8 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2988,11 +2988,11 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem) if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty()) { - newMat->mDiffuseMapAssetId[0] = assetMapFillInStr; + newMat->_setDiffuseMap(assetMapFillInStr,0); } else if (imageType == ImageAsset::ImageTypes::Normal) { - newMat->mNormalMapAssetId[0] = assetMapFillInStr; + newMat->_setNormalMap(assetMapFillInStr, 0); } else if (imageType == ImageAsset::ImageTypes::ORMConfig) { diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index cfe618993..16c1ba03d 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -969,10 +969,10 @@ void GroundCover::_initialize( U32 cellCount, U32 cellPlacementCount ) if(mat) { GFXTexHandle tex; - if (mat->getDiffuseMapResource(0)) - tex = mat->getDiffuseMapResource(0); - else if (mat->getDiffuseMap(0) != StringTable->EmptyString()) - tex = GFXTexHandle(mat->getDiffuseMap(0), &GFXStaticTextureSRGBProfile, "GroundCover texture aspect ratio check"); + if (mat->getDiffuseMap(0)) + tex = mat->getDiffuseMap(0); + else if (mat->getDiffuseMapAsset(0).notNull()) + tex = mat->getDiffuseMap(0); if(tex.isValid()) { diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 3084ce2f4..25071f579 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -142,18 +142,15 @@ Material::Material() mAccuCoverage[i] = 0.9f; mAccuSpecular[i] = 16.0f; - INIT_IMAGEASSET_ARRAY(DiffuseMap, GFXStaticTextureSRGBProfile, i); INIT_IMAGEASSET_ARRAY(OverlayMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(LightMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(ToneMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(DetailMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(NormalMap, GFXNormalMapProfile, i); INIT_IMAGEASSET_ARRAY(ORMConfigMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(RoughMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(AOMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(MetalMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(GlowMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(DetailNormalMap, GFXNormalMapProfile, i); mParallaxScale[i] = 0.0f; @@ -258,14 +255,14 @@ void Material::initPersistFields() addArray("Stages", MAX_STAGES); addGroup("Basic Texture Maps"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(DiffuseMap, MAX_STAGES, Material, "Albedo"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DiffuseMap, MAX_STAGES, Material, "Albedo"); addField("diffuseColor", TypeColorF, Offset(mDiffuse, Material), MAX_STAGES, "This color is multiplied against the diffuse texture color. If no diffuse texture " "is present this is the material color."); addField("diffuseMapSRGB", TypeBool, Offset(mDiffuseMapSRGB, Material), MAX_STAGES, "Enable sRGB for the diffuse color texture map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY(NormalMap, MAX_STAGES, Material, "NormalMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(NormalMap, MAX_STAGES, Material, "NormalMap"); endGroup("Basic Texture Maps"); addGroup("Light Influence Maps"); @@ -303,7 +300,7 @@ void Material::initPersistFields() addField("detailScale", TypePoint2F, Offset(mDetailScale, Material), MAX_STAGES, "The scale factor for the detail map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailNormalMap, MAX_STAGES, Material, "DetailNormalMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DetailNormalMap, MAX_STAGES, Material, "DetailNormalMap"); addField("detailNormalMapStrength", TypeF32, Offset(mDetailNormalMapStrength, Material), MAX_STAGES, "Used to scale the strength of the detail normal map when blended with the base normal map."); @@ -506,18 +503,12 @@ void Material::initPersistFields() // They point at the new 'map' fields, but reads always return // an empty string and writes only apply if the value is not empty. // - addProtectedField("baseTex", TypeImageFilename, Offset(mDiffuseMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see diffuseMap\n", AbstractClassRep::FIELD_HideInInspectors); addProtectedField("detailTex", TypeImageFilename, Offset(mDetailMapName, Material), defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, "For backwards compatibility.\n@see detailMap\n", AbstractClassRep::FIELD_HideInInspectors); addProtectedField("overlayTex", TypeImageFilename, Offset(mOverlayMapName, Material), defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, "For backwards compatibility.\n@see overlayMap\n", AbstractClassRep::FIELD_HideInInspectors); - addProtectedField("bumpTex", TypeImageFilename, Offset(mNormalMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see normalMap\n", AbstractClassRep::FIELD_HideInInspectors); addProtectedField("colorMultiply", TypeColorF, Offset(mDiffuse, Material), defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, "For backwards compatibility.\n@see diffuseColor\n", AbstractClassRep::FIELD_HideInInspectors); @@ -656,26 +647,11 @@ void Material::_mapMaterial() // If mapTo not defined in script, try to use the base texture name instead if (mMapTo.isEmpty()) { - if (mDiffuseMapName[0] == StringTable->EmptyString() && mDiffuseMapAsset->isNull()) + if (mDiffuseMapAsset->isNull()) return; - - else + else if (mDiffuseMapAsset->notNull()) { - // extract filename from base texture - if (mDiffuseMapName[0] != StringTable->EmptyString()) - { - U32 slashPos = String(mDiffuseMapName[0]).find('/', 0, String::Right); - if (slashPos == String::NPos) - // no '/' character, must be no path, just the filename - mMapTo = mDiffuseMapName[0]; - else - // use everything after the last slash - mMapTo = String(mDiffuseMapName[0]).substr(slashPos + 1, (U32)strlen(mDiffuseMapName[0]) - slashPos - 1); - } - else if (!mDiffuseMapAsset->isNull()) - { - mMapTo = mDiffuseMapAsset[0]->getImageFile(); - } + mMapTo = mDiffuseMapAsset[0]->getImageFile(); } } @@ -850,16 +826,15 @@ bool Material::_setAccuEnabled(void* object, const char* index, const char* data //material.getDiffuseMap(%layer); //returns the raw file referenced //material.getDiffuseMapAsset(%layer); //returns the asset id //material.setDiffuseMap(%texture, %layer); //tries to set the asset and failing that attempts a flat file reference -DEF_IMAGEASSET_ARRAY_BINDS(Material, DiffuseMap) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DiffuseMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, NormalMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailNormalMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS(Material, OverlayMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, LightMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, ToneMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, NormalMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, ORMConfigMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, RoughMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, GlowMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailNormalMap); - diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index e17bdd317..3bce188c6 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -208,10 +208,9 @@ public: //----------------------------------------------------------------------- // Data //----------------------------------------------------------------------- - void onImageAssetChanged(); - - DECLARE_IMAGEASSET_ARRAY(Material, DiffuseMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DiffuseMap); + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DiffuseMap, GFXStaticTextureSRGBProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, NormalMap, GFXNormalMapProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailNormalMap, GFXNormalMapProfile, MAX_STAGES) bool mDiffuseMapSRGB[MAX_STAGES]; // SRGB diffuse DECLARE_IMAGEASSET_ARRAY(Material, OverlayMap, MAX_STAGES, onImageAssetChanged); @@ -226,8 +225,6 @@ public: DECLARE_IMAGEASSET_ARRAY(Material, DetailMap, MAX_STAGES, onImageAssetChanged); DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DetailMap); - DECLARE_IMAGEASSET_ARRAY(Material, NormalMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, NormalMap); DECLARE_IMAGEASSET_ARRAY(Material, ORMConfigMap, MAX_STAGES, onImageAssetChanged); DECLARE_IMAGEASSET_ARRAY_SETGET(Material, ORMConfigMap); @@ -250,10 +247,6 @@ public: 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, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DetailNormalMap); /// The strength scalar for the detail normal map. F32 mDetailNormalMapStrength[MAX_STAGES]; diff --git a/Engine/source/materials/processedMaterial.cpp b/Engine/source/materials/processedMaterial.cpp index a4841ac6d..035c2d21c 100644 --- a/Engine/source/materials/processedMaterial.cpp +++ b/Engine/source/materials/processedMaterial.cpp @@ -392,9 +392,9 @@ void ProcessedMaterial::_setStageData() for (i = 0; i < Material::MAX_STAGES; i++) { // DiffuseMap - if (mMaterial->mDiffuseMapAsset[i] && !mMaterial->mDiffuseMapAsset[i].isNull()) + if (mMaterial->getDiffuseMapAsset(i).notNull()) { - mStages[i].setTex(MFT_DiffuseMap, mMaterial->getDiffuseMapResource(i)); + mStages[i].setTex(MFT_DiffuseMap, mMaterial->getDiffuseMap(i)); 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. @@ -404,20 +404,6 @@ void ProcessedMaterial::_setStageData() mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile)); } } - else if (mMaterial->mDiffuseMapName[i] != StringTable->EmptyString()) - { - 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. - 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 - // that the texture for this stage was missing. - mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile)); - } - } // OverlayMap if (mMaterial->getOverlayMap(i) != StringTable->EmptyString()) { @@ -451,10 +437,9 @@ void ProcessedMaterial::_setStageData() } // NormalMap - if (mMaterial->mNormalMapAsset[i] && !mMaterial->mNormalMapAsset[i].isNull()) + if (mMaterial->getNormalMapAsset(i).notNull()) { - mStages[i].setTex(MFT_NormalMap, mMaterial->getNormalMapResource(i)); - //mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->getDiffuseMap(i), &GFXStaticTextureSRGBProfile)); + mStages[i].setTex(MFT_NormalMap, mMaterial->getNormalMap(i)); if (!mStages[i].getTex(MFT_NormalMap)) { // Load a debug texture to make it clear to the user @@ -462,24 +447,13 @@ void ProcessedMaterial::_setStageData() mStages[i].setTex(MFT_NormalMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXNormalMapProfile)); } } - else if (mMaterial->mNormalMapName[i] != StringTable->EmptyString()) - { - mStages[i].setTex(MFT_NormalMap, _createTexture(mMaterial->mNormalMapName[i], &GFXNormalMapProfile)); - if (!mStages[i].getTex(MFT_NormalMap)) - { - //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->mNormalMapName[i]).startsWith("#")) - mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->mNormalMapName[i], i); - } - } // Detail Normal Map - if (mMaterial->getDetailNormalMap(i) != StringTable->EmptyString()) + if (mMaterial->getDetailNormalMapAsset(i).notNull()) { - mStages[i].setTex(MFT_DetailNormalMap, mMaterial->getDetailNormalMapResource(i)); + mStages[i].setTex(MFT_DetailNormalMap, mMaterial->getDetailNormalMap(i)); if (!mStages[i].getTex(MFT_DetailNormalMap)) - mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->getDetailNormalMap(i), i); + mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->getDetailNormalMapAsset(i), i); } //depending on creation method this may or may not have been shoved into srgb space eroneously diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 521ec04c6..ac7e210f3 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -229,9 +229,9 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features, mInstancingState = new InstancingState(); mInstancingState->setFormat( _getRPD( 0 )->shader->getInstancingFormat(), mVertexFormat ); } - if (mMaterial && mMaterial->mDiffuseMapName[0] != StringTable->EmptyString() && String(mMaterial->mDiffuseMapName[0]).startsWith("#")) + if (mMaterial && mMaterial->getDiffuseMapAsset(0).notNull() && String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).startsWith("#")) { - String texTargetBufferName = String(mMaterial->mDiffuseMapName[0]).substr(1, (U32)strlen(mMaterial->mDiffuseMapName[0]) - 1); + String texTargetBufferName = String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).substr(1, (U32)strlen(mMaterial->getDiffuseMapAsset(0)->getImageFile()) - 1); NamedTexTarget *texTarget = NamedTexTarget::find(texTargetBufferName); RenderPassData* rpd = getPass(0); diff --git a/Engine/source/renderInstance/renderDeferredMgr.cpp b/Engine/source/renderInstance/renderDeferredMgr.cpp index 65276a111..e7fd4f907 100644 --- a/Engine/source/renderInstance/renderDeferredMgr.cpp +++ b/Engine/source/renderInstance/renderDeferredMgr.cpp @@ -883,11 +883,10 @@ bool DeferredMatInstance::init( const FeatureSet &features, { bool vaild = Parent::init(features, vertexFormat); - if (mMaterial && mMaterial->getDiffuseMap(0) != StringTable->EmptyString() && String(mMaterial->getDiffuseMap(0)).startsWith("#")) + if (mMaterial && mMaterial->getDiffuseMapAsset(0).notNull() && String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).startsWith("#")) { - String difName = mMaterial->getDiffuseMap(0); - String texTargetBufferName = difName.substr(1, difName.length() - 1); - NamedTexTarget *texTarget = NamedTexTarget::find(texTargetBufferName); + String texTargetBufferName = String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).substr(1, (U32)strlen(mMaterial->getDiffuseMapAsset(0)->getImageFile()) - 1); + NamedTexTarget* texTarget = NamedTexTarget::find(texTargetBufferName); RenderPassData* rpd = getPass(0); if (rpd) diff --git a/Engine/source/ts/assimp/assimpAppMaterial.cpp b/Engine/source/ts/assimp/assimpAppMaterial.cpp index cf62d6cbb..71526e9c0 100644 --- a/Engine/source/ts/assimp/assimpAppMaterial.cpp +++ b/Engine/source/ts/assimp/assimpAppMaterial.cpp @@ -170,14 +170,14 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co { torquePath = texName.C_Str(); if (!torquePath.isEmpty()) - mat->mDiffuseMapName[0] = cleanTextureName(torquePath, cleanFile, path, false); + mat->_setDiffuseMap(cleanTextureName(torquePath, cleanFile, path, false), 0); } if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), texName)) { torquePath = texName.C_Str(); if (!torquePath.isEmpty()) - mat->mNormalMapName[0] = cleanTextureName(torquePath, cleanFile, path, false); + mat->_setNormalMap(cleanTextureName(torquePath, cleanFile, path, false), 0); } #ifdef TORQUE_PBR_MATERIALS diff --git a/Engine/source/ts/collada/colladaAppMaterial.cpp b/Engine/source/ts/collada/colladaAppMaterial.cpp index 81eafc1e3..6c53915ff 100644 --- a/Engine/source/ts/collada/colladaAppMaterial.cpp +++ b/Engine/source/ts/collada/colladaAppMaterial.cpp @@ -208,8 +208,8 @@ Material *ColladaAppMaterial::createMaterial(const Torque::Path& path) const Material *newMat = MATMGR->allocateAndRegister( cleanName, getName() ); Con::setVariable("$Con::File", oldScriptFile); // restore script path - newMat->mDiffuseMapName[0] = diffuseMap; - newMat->mNormalMapName[0] = normalMap; + newMat->_setDiffuseMap(diffuseMap, 0); + newMat->_setNormalMap(normalMap, 0); newMat->mDiffuse[0] = diffuseColor; newMat->mRoughness[0] = roughness; diff --git a/Engine/source/ts/collada/colladaUtils.cpp b/Engine/source/ts/collada/colladaUtils.cpp index 6563bbd2c..dc91b26f8 100644 --- a/Engine/source/ts/collada/colladaUtils.cpp +++ b/Engine/source/ts/collada/colladaUtils.cpp @@ -1030,8 +1030,8 @@ void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const { Torque::Path diffusePath; - if (mat->mDiffuseMapName[0] != StringTable->EmptyString()) - diffusePath = Torque::Path(mat->mDiffuseMapName[0]); + if (mat->getDiffuseMapAsset(0).notNull()) + diffusePath = Torque::Path(mat->getDiffuseMapAsset(0)->getImageFile()); else diffusePath = String("warningMat"); @@ -1040,8 +1040,8 @@ void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const } else { - if (mat->mDiffuseMapName[0] != StringTable->EmptyString()) - diffuseMap += Torque::Path(mat->mDiffuseMapName[0]); + if (mat->getDiffuseMapAsset(0).notNull()) + diffuseMap += Torque::Path(mat->getDiffuseMapAsset(0)->getImageFile()); else diffuseMap += "warningMat"; } @@ -1316,8 +1316,8 @@ void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const { Torque::Path diffusePath; - if (mat->mDiffuseMapName[0] != StringTable->EmptyString()) - diffusePath = Torque::Path(mat->mDiffuseMapName[0]); + if (mat->getDiffuseMapAsset(0).notNull()) + diffusePath = Torque::Path(mat->getDiffuseMapAsset(0)->getImageFile()); else diffusePath = String("warningMat"); @@ -1326,8 +1326,8 @@ void ColladaUtils::exportColladaMaterials(tinyxml2::XMLElement* rootNode, const } else { - if (mat->mDiffuseMapName[0] != StringTable->EmptyString()) - diffuseMap += Torque::Path(mat->mDiffuseMapName[0]); + if (mat->getDiffuseMapAsset(0).notNull()) + diffuseMap += Torque::Path(mat->getDiffuseMapAsset(0)->getImageFile()); else diffuseMap += "warningMat"; } diff --git a/Engine/source/ts/tsLastDetail.cpp b/Engine/source/ts/tsLastDetail.cpp index a65a22851..df9c2f29f 100644 --- a/Engine/source/ts/tsLastDetail.cpp +++ b/Engine/source/ts/tsLastDetail.cpp @@ -252,8 +252,8 @@ void TSLastDetail::update( bool forceUpdate ) // Setup the material for this imposter. mMaterial = MATMGR->allocateAndRegister( String::EmptyString ); mMaterial->mAutoGenerated = true; - mMaterial->setDiffuseMapFile(diffuseMapPath, 0); - mMaterial->setNormalMapFile(_getNormalMapPath(), 0); + mMaterial->_setDiffuseMap(diffuseMapPath, 0); + mMaterial->_setNormalMap(_getNormalMapPath(), 0); mMaterial->mImposterLimits.set( (mNumPolarSteps * 2) + 1, mNumEquatorSteps, mPolarAngle, mIncludePoles ); mMaterial->mTranslucent = true; From 58119a4f82bd5348e29938703d0fb1feef0f8a22 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 27 Dec 2024 14:16:47 +0000 Subject: [PATCH 12/47] more material def --- Engine/source/T3D/assets/ImageAsset.h | 10 +++--- Engine/source/T3D/assets/assetImporter.cpp | 2 +- .../source/materials/materialDefinition.cpp | 33 +++++++------------ Engine/source/materials/materialDefinition.h | 20 +++-------- Engine/source/materials/processedMaterial.cpp | 32 +++++++++--------- 5 files changed, 39 insertions(+), 58 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 78209b95b..6786c141c 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -598,7 +598,7 @@ public: \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ - StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ AssetQuery query; \ S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ if (foundAssetcount != 0) \ @@ -629,7 +629,7 @@ public: \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ - StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ AssetQuery query; \ S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ if (foundAssetcount != 0) \ @@ -665,7 +665,7 @@ public: \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ - StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ AssetQuery query; \ S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ if (foundAssetcount != 0) \ @@ -682,6 +682,7 @@ public: \ inline StringTableEntry _get##name(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ GFXTexHandle get##name(const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(&profile) : NULL; } \ + GFXTexHandle get##name(GFXTextureProfile* requestedProfile, const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(requestedProfile) : NULL; }\ AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} @@ -696,7 +697,7 @@ public: \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ - StringTableEntry imageAssetId = ImageAsset::smNoImageAssetFallback; \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ AssetQuery query; \ S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ if (foundAssetcount != 0) \ @@ -714,6 +715,7 @@ public: \ inline StringTableEntry _get##name(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ GFXTexHandle get##name(const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(&profile) : NULL; } \ + GFXTexHandle get##name(GFXTextureProfile* requestedProfile, const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(requestedProfile) : NULL; }\ AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index ba8ad9eb8..4e8a9c192 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2996,7 +2996,7 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem) } else if (imageType == ImageAsset::ImageTypes::ORMConfig) { - newMat->mORMConfigMapAssetId[0] = assetMapFillInStr; + newMat->_setORMConfigMap(assetMapFillInStr, 0); } else if (imageType == ImageAsset::ImageTypes::Metalness) { diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 25071f579..80a1e46c1 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -142,11 +142,6 @@ Material::Material() mAccuCoverage[i] = 0.9f; mAccuSpecular[i] = 16.0f; - INIT_IMAGEASSET_ARRAY(OverlayMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(LightMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(ToneMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(DetailMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(ORMConfigMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(RoughMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(AOMap, GFXStaticTextureProfile, i); INIT_IMAGEASSET_ARRAY(MetalMap, GFXStaticTextureProfile, i); @@ -282,7 +277,7 @@ void Material::initPersistFields() addField("metalChan", TypeF32, Offset(mMetalChan, Material), MAX_STAGES, "The input channel metalness maps use."); - INITPERSISTFIELD_IMAGEASSET_ARRAY(ORMConfigMap, MAX_STAGES, Material, "AO|Roughness|metalness map"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(ORMConfigMap, MAX_STAGES, Material, "AO|Roughness|metalness map"); addField("isSRGb", TypeBool, Offset(mIsSRGb, Material), MAX_STAGES, "Substance Designer Workaround."); @@ -296,7 +291,7 @@ void Material::initPersistFields() endGroup("Light Influence Maps"); addGroup("Advanced Texture Maps"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailMap, MAX_STAGES, Material, "DetailMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DetailMap, MAX_STAGES, Material, "DetailMap"); addField("detailScale", TypePoint2F, Offset(mDetailScale, Material), MAX_STAGES, "The scale factor for the detail map."); @@ -304,9 +299,9 @@ void Material::initPersistFields() addField("detailNormalMapStrength", TypeF32, Offset(mDetailNormalMapStrength, Material), MAX_STAGES, "Used to scale the strength of the detail normal map when blended with the base normal map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY(OverlayMap, MAX_STAGES, Material, "Overlay"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(LightMap, MAX_STAGES, Material, "LightMap"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(ToneMap, MAX_STAGES, Material, "ToneMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(OverlayMap, MAX_STAGES, Material, "Overlay"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(LightMap, MAX_STAGES, Material, "LightMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(ToneMap, MAX_STAGES, Material, "ToneMap"); endGroup("Advanced Texture Maps"); addGroup("Accumulation Properties"); @@ -503,12 +498,6 @@ void Material::initPersistFields() // They point at the new 'map' fields, but reads always return // an empty string and writes only apply if the value is not empty. // - addProtectedField("detailTex", TypeImageFilename, Offset(mDetailMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see detailMap\n", AbstractClassRep::FIELD_HideInInspectors); - addProtectedField("overlayTex", TypeImageFilename, Offset(mOverlayMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see overlayMap\n", AbstractClassRep::FIELD_HideInInspectors); addProtectedField("colorMultiply", TypeColorF, Offset(mDiffuse, Material), defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, "For backwards compatibility.\n@see diffuseColor\n", AbstractClassRep::FIELD_HideInInspectors); @@ -614,7 +603,7 @@ bool Material::isLightmapped() const { bool ret = false; for (U32 i = 0; i < MAX_STAGES; i++) - ret |= mLightMapName[i] != StringTable->EmptyString() || mToneMapName[i] != StringTable->EmptyString() || mVertLit[i]; + ret |= mLightMapAsset[i].notNull() || mToneMapAsset[i].notNull() || mVertLit[i]; return ret; } @@ -829,11 +818,11 @@ bool Material::_setAccuEnabled(void* object, const char* index, const char* data DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DiffuseMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, NormalMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailNormalMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS(Material, OverlayMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, LightMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, ToneMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, ORMConfigMap); +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, OverlayMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, LightMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ToneMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ORMConfigMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS(Material, RoughMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap); DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap); diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 3bce188c6..4ef870aa3 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -213,21 +213,11 @@ public: DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailNormalMap, GFXNormalMapProfile, MAX_STAGES) bool mDiffuseMapSRGB[MAX_STAGES]; // SRGB diffuse - DECLARE_IMAGEASSET_ARRAY(Material, OverlayMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, OverlayMap); - - DECLARE_IMAGEASSET_ARRAY(Material, LightMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, LightMap); - - DECLARE_IMAGEASSET_ARRAY(Material, ToneMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, ToneMap); - - DECLARE_IMAGEASSET_ARRAY(Material, DetailMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, DetailMap); - - - DECLARE_IMAGEASSET_ARRAY(Material, ORMConfigMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, ORMConfigMap); + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, OverlayMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, LightMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ToneMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ORMConfigMap, GFXStaticTextureProfile, MAX_STAGES) bool mIsSRGb[MAX_STAGES]; DECLARE_IMAGEASSET_ARRAY(Material, AOMap, MAX_STAGES, onImageAssetChanged); diff --git a/Engine/source/materials/processedMaterial.cpp b/Engine/source/materials/processedMaterial.cpp index 035c2d21c..031ffb58c 100644 --- a/Engine/source/materials/processedMaterial.cpp +++ b/Engine/source/materials/processedMaterial.cpp @@ -405,35 +405,35 @@ void ProcessedMaterial::_setStageData() } } // OverlayMap - if (mMaterial->getOverlayMap(i) != StringTable->EmptyString()) + if (mMaterial->getOverlayMapAsset(i).notNull()) { - mStages[i].setTex(MFT_OverlayMap, mMaterial->getOverlayMapResource(i)); + mStages[i].setTex(MFT_OverlayMap, mMaterial->getOverlayMap(i)); if (!mStages[i].getTex(MFT_OverlayMap)) - mMaterial->logError("Failed to load overlay map %s for stage %i", mMaterial->getOverlayMap(i), i); + mMaterial->logError("Failed to load overlay map %s for stage %i", mMaterial->_getOverlayMap(i), i); } // LightMap - if (mMaterial->getLightMap(i) != StringTable->EmptyString()) + if (mMaterial->getLightMapAsset(i).notNull()) { - mStages[i].setTex(MFT_LightMap, mMaterial->getLightMapResource(i)); + mStages[i].setTex(MFT_LightMap, mMaterial->getLightMap(i)); if (!mStages[i].getTex(MFT_LightMap)) - mMaterial->logError("Failed to load light map %s for stage %i", mMaterial->getLightMap(i), i); + mMaterial->logError("Failed to load light map %s for stage %i", mMaterial->_getLightMap(i), i); } // ToneMap - if (mMaterial->getToneMap(i) != StringTable->EmptyString()) + if (mMaterial->getToneMapAsset(i).notNull()) { - mStages[i].setTex(MFT_ToneMap, mMaterial->getToneMapResource(i)); + mStages[i].setTex(MFT_ToneMap, mMaterial->getToneMap(i)); if (!mStages[i].getTex(MFT_ToneMap)) - mMaterial->logError("Failed to load tone map %s for stage %i", mMaterial->getToneMap(i), i); + mMaterial->logError("Failed to load tone map %s for stage %i", mMaterial->_getToneMap(i), i); } // DetailMap - if (mMaterial->getDetailMap(i) != StringTable->EmptyString()) + if (mMaterial->getDetailMapAsset(i).notNull()) { - mStages[i].setTex(MFT_DetailMap, mMaterial->getDetailMapResource(i)); + mStages[i].setTex(MFT_DetailMap, mMaterial->getDetailMap(i)); if (!mStages[i].getTex(MFT_DetailMap)) - mMaterial->logError("Failed to load detail map %s for stage %i", mMaterial->getDetailMap(i), i); + mMaterial->logError("Failed to load detail map %s for stage %i", mMaterial->_getDetailMap(i), i); } // NormalMap @@ -453,7 +453,7 @@ void ProcessedMaterial::_setStageData() { mStages[i].setTex(MFT_DetailNormalMap, mMaterial->getDetailNormalMap(i)); if (!mStages[i].getTex(MFT_DetailNormalMap)) - mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->getDetailNormalMapAsset(i), i); + mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->_getDetailNormalMap(i), i); } //depending on creation method this may or may not have been shoved into srgb space eroneously @@ -462,11 +462,11 @@ void ProcessedMaterial::_setStageData() profile = &GFXStaticTextureSRGBProfile; // ORMConfig - if (mMaterial->getORMConfigMap(i) != StringTable->EmptyString()) + if (mMaterial->getORMConfigMapAsset(i).notNull()) { - mStages[i].setTex(MFT_OrmMap, _createTexture(mMaterial->getORMConfigMap(i), profile)); + mStages[i].setTex(MFT_OrmMap, mMaterial->getORMConfigMap(profile, i)); if (!mStages[i].getTex(MFT_OrmMap)) - mMaterial->logError("Failed to load PBR Config map %s for stage %i", mMaterial->getORMConfigMap(i), i); + mMaterial->logError("Failed to load PBR Config map %s for stage %i", mMaterial->_getORMConfigMap(i), i); } else { From 0f4d2d16894e1931953696b475b1818aa41257e3 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 27 Dec 2024 14:38:01 +0000 Subject: [PATCH 13/47] material definition finished --- Engine/source/T3D/assets/assetImporter.cpp | 6 ++--- .../source/materials/materialDefinition.cpp | 21 +++++++--------- Engine/source/materials/materialDefinition.h | 24 ++++++------------- Engine/source/materials/processedMaterial.cpp | 12 +++++----- Engine/source/ts/assimp/assimpAppMaterial.cpp | 8 +++---- 5 files changed, 28 insertions(+), 43 deletions(-) diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 4e8a9c192..dee0afbe3 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -3000,15 +3000,15 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem) } else if (imageType == ImageAsset::ImageTypes::Metalness) { - newMat->mMetalMapAssetId[0] = assetMapFillInStr; + newMat->_setMetalMap(assetMapFillInStr, 0); } else if (imageType == ImageAsset::ImageTypes::AO) { - newMat->mAOMapAssetId[0] = assetMapFillInStr; + newMat->_setAOMap(assetMapFillInStr, 0); } else if (imageType == ImageAsset::ImageTypes::Roughness) { - newMat->mRoughMapAssetId[0] = assetMapFillInStr; + newMat->_setRoughMap(assetMapFillInStr, 0); hasRoughness = true; } } diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 80a1e46c1..486ecbd1d 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -142,11 +142,6 @@ Material::Material() mAccuCoverage[i] = 0.9f; mAccuSpecular[i] = 16.0f; - INIT_IMAGEASSET_ARRAY(RoughMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(AOMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(MetalMap, GFXStaticTextureProfile, i); - INIT_IMAGEASSET_ARRAY(GlowMap, GFXStaticTextureProfile, i); - mParallaxScale[i] = 0.0f; mVertLit[i] = false; @@ -281,10 +276,10 @@ void Material::initPersistFields() addField("isSRGb", TypeBool, Offset(mIsSRGb, Material), MAX_STAGES, "Substance Designer Workaround."); - INITPERSISTFIELD_IMAGEASSET_ARRAY(AOMap, MAX_STAGES, Material, "AOMap"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(RoughMap, MAX_STAGES, Material, "RoughMap (also needs MetalMap)"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(MetalMap, MAX_STAGES, Material, "MetalMap (also needs RoughMap)"); - INITPERSISTFIELD_IMAGEASSET_ARRAY(GlowMap, MAX_STAGES, Material, "GlowMap (needs Albedo)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(AOMap, MAX_STAGES, Material, "AOMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(RoughMap, MAX_STAGES, Material, "RoughMap (also needs MetalMap)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(MetalMap, MAX_STAGES, Material, "MetalMap (also needs RoughMap)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(GlowMap, MAX_STAGES, Material, "GlowMap (needs Albedo)"); addField("glowMul", TypeF32, Offset(mGlowMul, Material), MAX_STAGES, "glow mask multiplier"); @@ -823,7 +818,7 @@ DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, LightMap, Material::Constants::MAX DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ToneMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailMap, Material::Constants::MAX_STAGES) DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ORMConfigMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS(Material, RoughMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap); -DEF_IMAGEASSET_ARRAY_BINDS(Material, GlowMap); +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, RoughMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, AOMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, MetalMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, GlowMap, Material::Constants::MAX_STAGES) diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 4ef870aa3..db8312d3a 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -211,36 +211,26 @@ public: DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DiffuseMap, GFXStaticTextureSRGBProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, NormalMap, GFXNormalMapProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailNormalMap, GFXNormalMapProfile, MAX_STAGES) - - bool mDiffuseMapSRGB[MAX_STAGES]; // SRGB diffuse DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, OverlayMap, GFXStaticTextureProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, LightMap, GFXStaticTextureProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ToneMap, GFXStaticTextureProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailMap, GFXStaticTextureProfile, MAX_STAGES) DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ORMConfigMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, AOMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, RoughMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, MetalMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, GlowMap, GFXStaticTextureProfile, MAX_STAGES) - bool mIsSRGb[MAX_STAGES]; - DECLARE_IMAGEASSET_ARRAY(Material, AOMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, AOMap); + bool mDiffuseMapSRGB[MAX_STAGES]; // SRGB diffuse + bool mIsSRGb[MAX_STAGES]; // SRGB ORM F32 mAOChan[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, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, MetalMap); - F32 mMetalChan[MAX_STAGES]; - DECLARE_IMAGEASSET_ARRAY(Material, GlowMap, MAX_STAGES, onImageAssetChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(Material, GlowMap); - F32 mGlowMul[MAX_STAGES]; /// The strength scalar for the detail normal map. - F32 mDetailNormalMapStrength[MAX_STAGES]; - + F32 mDetailNormalMapStrength[MAX_STAGES]; bool mAccuEnabled[MAX_STAGES]; F32 mAccuScale[MAX_STAGES]; F32 mAccuDirection[MAX_STAGES]; diff --git a/Engine/source/materials/processedMaterial.cpp b/Engine/source/materials/processedMaterial.cpp index 031ffb58c..41242c9b1 100644 --- a/Engine/source/materials/processedMaterial.cpp +++ b/Engine/source/materials/processedMaterial.cpp @@ -470,25 +470,25 @@ void ProcessedMaterial::_setStageData() } else { - if ((mMaterial->getAOMap(i) != StringTable->EmptyString()) || (mMaterial->getRoughMap(i) != StringTable->EmptyString()) || (mMaterial->getMetalMap(i) != StringTable->EmptyString())) + if ((mMaterial->getAOMapAsset(i).notNull()) || (mMaterial->getRoughMapAsset(i).notNull()) || (mMaterial->getMetalMapAsset(i).notNull())) { U32 inputKey[4]; inputKey[0] = mMaterial->mAOChan[i]; inputKey[1] = mMaterial->mRoughnessChan[i]; inputKey[2] = mMaterial->mMetalChan[i]; inputKey[3] = 0; - mStages[i].setTex(MFT_OrmMap, _createCompositeTexture( mMaterial->getAOMap(i), mMaterial->getRoughMap(i), - mMaterial->getMetalMap(i), "", + mStages[i].setTex(MFT_OrmMap, _createCompositeTexture( mMaterial->getAOMapAsset(i)->getImageFile(), mMaterial->getRoughMapAsset(i)->getImageFile(), + mMaterial->getMetalMapAsset(i)->getImageFile(), "", inputKey, profile)); if (!mStages[i].getTex(MFT_OrmMap)) mMaterial->logError("Failed to dynamically create ORM Config map for stage %i", i); } } - if (mMaterial->getGlowMap(i) != StringTable->EmptyString()) + if (mMaterial->getGlowMapAsset(i).notNull()) { - mStages[i].setTex(MFT_GlowMap, mMaterial->getGlowMapResource(i)); + mStages[i].setTex(MFT_GlowMap, mMaterial->getGlowMap(i)); if (!mStages[i].getTex(MFT_GlowMap)) - mMaterial->logError("Failed to load glow map %s for stage %i", mMaterial->getGlowMap(i), i); + mMaterial->logError("Failed to load glow map %s for stage %i", mMaterial->_getGlowMap(i), i); } } diff --git a/Engine/source/ts/assimp/assimpAppMaterial.cpp b/Engine/source/ts/assimp/assimpAppMaterial.cpp index 71526e9c0..d761f1a18 100644 --- a/Engine/source/ts/assimp/assimpAppMaterial.cpp +++ b/Engine/source/ts/assimp/assimpAppMaterial.cpp @@ -194,20 +194,20 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co { // If we have either map, fill all three slots if (rmName.isNotEmpty()) { - mat->mRoughMapName[0] = cleanTextureName(rmName, cleanFile, path, false); // Roughness + mat->_setRoughMap(cleanTextureName(rmName, cleanFile, path, false), 0); // Roughness mat->mRoughnessChan[0] = 1.0f; mat->mInvertRoughness[0] = (floatVal == 1.0f); - mat->mMetalMapName[0] = cleanTextureName(rmName, cleanFile, path, false); // Metallic + mat->_setMetalMap(cleanTextureName(rmName, cleanFile, path, false), 0); // Metallic mat->mMetalChan[0] = 2.0f; } if (aoName.isNotEmpty()) { - mat->mAOMapName[0] = cleanTextureName(aoName, cleanFile, path, false); // occlusion + mat->_setAOMap(cleanTextureName(aoName, cleanFile, path, false), 0); // occlusion mat->mAOChan[0] = 0.0f; } else { - mat->mAOMapName[0] = cleanTextureName(rmName, cleanFile, path, false); // occlusion + mat->_setAOMap(cleanTextureName(aoName, cleanFile, path, false), 0); // occlusion mat->mAOChan[0] = 0.0f; } } From d87655bb3ac641a2b2b310b75b78fa37e716c35e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 27 Dec 2024 15:25:02 +0000 Subject: [PATCH 14/47] merge dev --- Engine/source/T3D/assets/ImageAsset.h | 15 ++++++++++----- Engine/source/materials/materialDefinition.cpp | 6 ------ Engine/source/materials/processedMaterial.cpp | 4 ++-- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 6786c141c..1198aa6bd 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -336,7 +336,10 @@ public: \ const StringTableEntry get##name() const\ {\ if (m##name##Asset && (m##name##Asset->getImageFile() != StringTable->EmptyString()))\ - return Platform::makeRelativePathName(m##name##Asset->getImageFile(), Platform::getMainDotCsDir());\ + if (m##name##Asset->getImageFile()[0] == '#' || m##name##Asset->getImageFile()[0] == '$')\ + return m##name##Asset->getImageFile();\ + else\ + return Platform::makeRelativePathName(m##name##Asset->getImageFile(), Platform::getMainDotCsDir());\ else if (m##name##AssetId != StringTable->EmptyString())\ return m##name##AssetId;\ else if (m##name##Name != StringTable->EmptyString())\ @@ -346,7 +349,7 @@ public: \ }\ GFXTexHandle get##name##Resource() \ {\ - if (m##name##Asset && (m##name##Asset->getImageFileName() != StringTable->EmptyString()))\ + if (m##name##Asset && (m##name##Asset->getImageFile() != StringTable->EmptyString()))\ return m##name##Asset->getTexture(m##name##Profile);\ return m##name;\ }\ @@ -453,7 +456,6 @@ public: \ }\ if (get##name(index) != StringTable->EmptyString() && m##name##Name[index] != StringTable->insert("texhandle"))\ {\ - 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__));\ }\ @@ -483,7 +485,10 @@ public: \ const StringTableEntry get##name(const U32& index) const\ {\ if (m##name##Asset[index] && (m##name##Asset[index]->getImageFile() != StringTable->EmptyString()))\ - return Platform::makeRelativePathName(m##name##Asset[index]->getImageFile(), Platform::getMainDotCsDir());\ + if (m##name##Asset[index]->getImageFile()[0] == '#' || m##name##Asset[index]->getImageFile()[0] == '$')\ + return m##name##Asset[index]->getImageFile();\ + else\ + return Platform::makeRelativePathName(m##name##Asset[index]->getImageFile(), Platform::getMainDotCsDir());\ else if (m##name##AssetId[index] != StringTable->EmptyString())\ return m##name##AssetId[index];\ else if (m##name##Name[index] != StringTable->EmptyString())\ @@ -500,7 +505,7 @@ public: \ {\ if(index >= sm##name##Count || index < 0)\ return nullptr;\ - if (m##name##Asset[index] && (m##name##Asset[index]->getImageFileName() != StringTable->EmptyString()))\ + if (m##name##Asset[index] && (m##name##Asset[index]->getImageFile() != StringTable->EmptyString()))\ return m##name##Asset[index]->getTexture(m##name##Profile[index]);\ return m##name[index];\ }\ diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 486ecbd1d..cc998bdeb 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -230,12 +230,6 @@ Material::Material() mReverbSoundOcclusion = 1.0; } -void Material::onImageAssetChanged() -{ - flush(); - reload(); -} - void Material::initPersistFields() { docsURL; diff --git a/Engine/source/materials/processedMaterial.cpp b/Engine/source/materials/processedMaterial.cpp index 41242c9b1..bf172bd7e 100644 --- a/Engine/source/materials/processedMaterial.cpp +++ b/Engine/source/materials/processedMaterial.cpp @@ -398,8 +398,8 @@ void ProcessedMaterial::_setStageData() 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. - 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); + if (!String(mMaterial->getDiffuseMapAsset(i)->getImageFile()).startsWith("#") && !String(mMaterial->getDiffuseMapAsset(i)->getImageFile()).startsWith("$")) + mMaterial->logError("Failed to load diffuse map %s for stage %i", mMaterial->getDiffuseMapAsset(i)->getImageFile(), i); mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile)); } From 2bf2da74a054b142a56c1bbdd89b1d653d8bd9d4 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 30 Dec 2024 17:46:16 +0000 Subject: [PATCH 15/47] sound asset refactor init --- Engine/source/T3D/assets/SoundAsset.cpp | 49 +++++++++++++++++ Engine/source/T3D/assets/SoundAsset.h | 72 +++++++++++++++++++++++++ Engine/source/afx/afxMagicMissile.cpp | 17 +++--- Engine/source/afx/afxMagicMissile.h | 3 +- 4 files changed, 130 insertions(+), 11 deletions(-) diff --git a/Engine/source/T3D/assets/SoundAsset.cpp b/Engine/source/T3D/assets/SoundAsset.cpp index a71c08f5b..bd09f3f5b 100644 --- a/Engine/source/T3D/assets/SoundAsset.cpp +++ b/Engine/source/T3D/assets/SoundAsset.cpp @@ -110,6 +110,55 @@ ConsoleSetType(TypeSoundAssetId) Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset."); } +//----------------------------------------------------------------------------- +// REFACTOR +//----------------------------------------------------------------------------- + +IMPLEMENT_STRUCT(AssetPtr, AssetPtrSoundAsset, , "") +END_IMPLEMENT_STRUCT + +ConsoleType(SoundAssetPtr, TypeSoundAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) + + +ConsoleGetType(TypeSoundAssetPtrRefactor) +{ + // Fetch asset Id. + return (*((AssetPtr*)dptr)).getAssetId(); +} + +ConsoleSetType(TypeSoundAssetPtrRefactor) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + const char* pFieldValue = argv[0]; + + // Fetch asset pointer. + AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); + + // Is the asset pointer the correct type? + if (pAssetPtr == NULL) + { + // No, so fail. + Con::warnf("(TypeSoundAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); + + return; + } + + // Warn. + Con::warnf("(TypeSoundAssetPtr) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- +// REFACTOR END +//----------------------------------------------------------------------------- + const String SoundAsset::mErrCodeStrings[] = { "BadProfile", diff --git a/Engine/source/T3D/assets/SoundAsset.h b/Engine/source/T3D/assets/SoundAsset.h index f867e0e4f..41a01e75e 100644 --- a/Engine/source/T3D/assets/SoundAsset.h +++ b/Engine/source/T3D/assets/SoundAsset.h @@ -180,6 +180,9 @@ protected: DefineConsoleType(TypeSoundAssetPtr, SoundAsset) DefineConsoleType(TypeSoundAssetId, String) +DECLARE_STRUCT(AssetPtr) +DefineConsoleType(TypeSoundAssetPtrRefactor, AssetPtr) + #pragma region Singular Asset Macros //Singular assets @@ -579,5 +582,74 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ } #pragma endregion + +#pragma region Refactor Asset Macros + +#define DECLARE_SOUNDASSET_REFACTOR(className, name) \ +private: \ + AssetPtr m##name##Asset; \ +public: \ + void _set##name(StringTableEntry _in) { \ + \ + if (m##name##Asset.getAssetId() == _in) \ + return; \ + \ + if (!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + } \ +}; \ + \ +inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ +AssetPtr get##name##Asset(void) { return m##name##Asset; } \ +static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false; } + +#define DECLARE_SOUNDASSET_NET_REFACTOR(className, name, profile, mask) \ +private: \ + AssetPtr m##name##Asset; \ +public: \ + void _set##name(StringTableEntry _in){ \ + if(m##name##Asset.getAssetId() == _in) \ + return; \ + \ + if(!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry imageAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + imageAssetId = query.mAssetList[0]; \ + } \ + m##name##Asset = imageAssetId; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + } \ + setMaskBits(mask); \ + }; \ + \ + inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ + AssetPtr get##name##Asset(void) { return m##name##Asset; } \ + static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} + + +#define INITPERSISTFIELD_SSOUNDASSET_REFACTOR(name, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeSoundAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); + +#pragma endregion + #endif // _ASSET_BASE_H_ diff --git a/Engine/source/afx/afxMagicMissile.cpp b/Engine/source/afx/afxMagicMissile.cpp index e797c2dc1..adeda2620 100644 --- a/Engine/source/afx/afxMagicMissile.cpp +++ b/Engine/source/afx/afxMagicMissile.cpp @@ -142,7 +142,6 @@ U32 Projectile::smProjectileWarpTicks = 5; afxMagicMissileData::afxMagicMissileData() { INIT_ASSET(ProjectileShape); - INIT_ASSET(ProjectileSound); /* From stock Projectile code... explosion = NULL; @@ -247,7 +246,7 @@ afxMagicMissileData::afxMagicMissileData(const afxMagicMissileData& other, bool { CLONE_ASSET(ProjectileShape); projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName - CLONE_ASSET(ProjectileSound); + CLONE_ASSET_REFACTOR(ProjectileSound); splash = other.splash; splashId = other.splashId; // -- for pack/unpack of splash ptr lightDesc = other.lightDesc; @@ -345,7 +344,7 @@ void afxMagicMissileData::initPersistFields() endGroup("Particle Effects"); addGroup("Sounds"); - INITPERSISTFIELD_SOUNDASSET(ProjectileSound, afxMagicMissileData, "sound for the projectile"); + INITPERSISTFIELD_SSOUNDASSET_REFACTOR(ProjectileSound, afxMagicMissileData, "sound for the projectile") endGroup("Sounds"); addGroup("Light Emitter"); @@ -517,7 +516,7 @@ bool afxMagicMissileData::preload(bool server, String &errorStr) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(decal): %d", decalId); */ - if (!isProjectileSoundValid()) + if (mProjectileShapeAsset.isNull()) { //return false; -TODO: trigger asset download } @@ -627,7 +626,7 @@ void afxMagicMissileData::packData(BitStream* stream) DataBlockObjectIdLast); */ - PACKDATA_ASSET(ProjectileSound); + PACKDATA_ASSET_REFACTOR(ProjectileSound) if ( stream->writeFlag(lightDesc != NULL)) stream->writeRangedU32(lightDesc->getId(), DataBlockObjectIdFirst, @@ -733,7 +732,7 @@ void afxMagicMissileData::unpackData(BitStream* stream) decalId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); */ - UNPACKDATA_ASSET(ProjectileSound); + UNPACKDATA_ASSET_REFACTOR(ProjectileSound) if (stream->readFlag()) lightDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); @@ -1157,8 +1156,8 @@ bool afxMagicMissile::onNewDataBlock(GameBaseData* dptr, bool reload) SFX_DELETE( mSound ); - if (mDataBlock->getProjectileSound()) - mSound = SFX->createSource(mDataBlock->getProjectileSoundProfile()); + if (mDataBlock->getProjectileSoundAsset().notNull()) + mSound = SFX->createSource(mDataBlock->getProjectileSoundAsset()->getSFXTrack()); } return true; @@ -1993,7 +1992,7 @@ void afxMagicMissile::get_launch_data(Point3F& pos, Point3F& vel) void afxMagicMissile::updateSound() { - if (!mDataBlock->isProjectileSoundValid()) + if (mDataBlock->getProjectileSoundAsset().isNull()) return; if ( mSound ) diff --git a/Engine/source/afx/afxMagicMissile.h b/Engine/source/afx/afxMagicMissile.h index e3f6ee755..9f0c90227 100644 --- a/Engine/source/afx/afxMagicMissile.h +++ b/Engine/source/afx/afxMagicMissile.h @@ -126,8 +126,7 @@ public: SplashData* splash; // Water Splash Datablock S32 splashId; // Water splash ID - DECLARE_SOUNDASSET(afxMagicMissileData, ProjectileSound); - DECLARE_ASSET_SETGET(afxMagicMissileData, ProjectileSound); + DECLARE_SOUNDASSET_REFACTOR(afxMagicMissileData, ProjectileSound) LightDescription *lightDesc; S32 lightDescId; From e16a66f3631616ae097b6f6d43ad9f22f6021d9b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 24 Mar 2025 19:58:52 +0000 Subject: [PATCH 16/47] Revert "sound asset refactor init" This reverts commit 2bf2da74a054b142a56c1bbdd89b1d653d8bd9d4. --- Engine/source/T3D/assets/SoundAsset.cpp | 49 ----------------- Engine/source/T3D/assets/SoundAsset.h | 72 ------------------------- Engine/source/afx/afxMagicMissile.cpp | 17 +++--- Engine/source/afx/afxMagicMissile.h | 3 +- 4 files changed, 11 insertions(+), 130 deletions(-) diff --git a/Engine/source/T3D/assets/SoundAsset.cpp b/Engine/source/T3D/assets/SoundAsset.cpp index bd09f3f5b..a71c08f5b 100644 --- a/Engine/source/T3D/assets/SoundAsset.cpp +++ b/Engine/source/T3D/assets/SoundAsset.cpp @@ -110,55 +110,6 @@ ConsoleSetType(TypeSoundAssetId) Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset."); } -//----------------------------------------------------------------------------- -// REFACTOR -//----------------------------------------------------------------------------- - -IMPLEMENT_STRUCT(AssetPtr, AssetPtrSoundAsset, , "") -END_IMPLEMENT_STRUCT - -ConsoleType(SoundAssetPtr, TypeSoundAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) - - -ConsoleGetType(TypeSoundAssetPtrRefactor) -{ - // Fetch asset Id. - return (*((AssetPtr*)dptr)).getAssetId(); -} - -ConsoleSetType(TypeSoundAssetPtrRefactor) -{ - // Was a single argument specified? - if (argc == 1) - { - // Yes, so fetch field value. - const char* pFieldValue = argv[0]; - - // Fetch asset pointer. - AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); - - // Is the asset pointer the correct type? - if (pAssetPtr == NULL) - { - // No, so fail. - Con::warnf("(TypeSoundAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); - return; - } - - // Set asset. - pAssetPtr->setAssetId(pFieldValue); - - return; - } - - // Warn. - Con::warnf("(TypeSoundAssetPtr) - Cannot set multiple args to a single asset."); -} - -//----------------------------------------------------------------------------- -// REFACTOR END -//----------------------------------------------------------------------------- - const String SoundAsset::mErrCodeStrings[] = { "BadProfile", diff --git a/Engine/source/T3D/assets/SoundAsset.h b/Engine/source/T3D/assets/SoundAsset.h index 41a01e75e..f867e0e4f 100644 --- a/Engine/source/T3D/assets/SoundAsset.h +++ b/Engine/source/T3D/assets/SoundAsset.h @@ -180,9 +180,6 @@ protected: DefineConsoleType(TypeSoundAssetPtr, SoundAsset) DefineConsoleType(TypeSoundAssetId, String) -DECLARE_STRUCT(AssetPtr) -DefineConsoleType(TypeSoundAssetPtrRefactor, AssetPtr) - #pragma region Singular Asset Macros //Singular assets @@ -582,74 +579,5 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\ } #pragma endregion - -#pragma region Refactor Asset Macros - -#define DECLARE_SOUNDASSET_REFACTOR(className, name) \ -private: \ - AssetPtr m##name##Asset; \ -public: \ - void _set##name(StringTableEntry _in) { \ - \ - if (m##name##Asset.getAssetId() == _in) \ - return; \ - \ - if (!AssetDatabase.isDeclaredAsset(_in)) \ - { \ - StringTableEntry imageAssetId = StringTable->EmptyString(); \ - AssetQuery query; \ - S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ - if (foundAssetcount != 0) \ - { \ - imageAssetId = query.mAssetList[0]; \ - } \ - m##name##Asset = imageAssetId; \ - } \ - else \ - { \ - m##name##Asset = _in; \ - } \ -}; \ - \ -inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ -AssetPtr get##name##Asset(void) { return m##name##Asset; } \ -static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false; } - -#define DECLARE_SOUNDASSET_NET_REFACTOR(className, name, profile, mask) \ -private: \ - AssetPtr m##name##Asset; \ -public: \ - void _set##name(StringTableEntry _in){ \ - if(m##name##Asset.getAssetId() == _in) \ - return; \ - \ - if(!AssetDatabase.isDeclaredAsset(_in)) \ - { \ - StringTableEntry imageAssetId = StringTable->EmptyString(); \ - AssetQuery query; \ - S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ - if (foundAssetcount != 0) \ - { \ - imageAssetId = query.mAssetList[0]; \ - } \ - m##name##Asset = imageAssetId; \ - } \ - else \ - { \ - m##name##Asset = _in; \ - } \ - setMaskBits(mask); \ - }; \ - \ - inline StringTableEntry _get##name(void) const { return m##name##Asset.getAssetId(); } \ - AssetPtr get##name##Asset(void) { return m##name##Asset; } \ - static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} - - -#define INITPERSISTFIELD_SSOUNDASSET_REFACTOR(name, consoleClass, docs) \ - addProtectedField(assetText(name, Asset), TypeSoundAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); - -#pragma endregion - #endif // _ASSET_BASE_H_ diff --git a/Engine/source/afx/afxMagicMissile.cpp b/Engine/source/afx/afxMagicMissile.cpp index adeda2620..e797c2dc1 100644 --- a/Engine/source/afx/afxMagicMissile.cpp +++ b/Engine/source/afx/afxMagicMissile.cpp @@ -142,6 +142,7 @@ U32 Projectile::smProjectileWarpTicks = 5; afxMagicMissileData::afxMagicMissileData() { INIT_ASSET(ProjectileShape); + INIT_ASSET(ProjectileSound); /* From stock Projectile code... explosion = NULL; @@ -246,7 +247,7 @@ afxMagicMissileData::afxMagicMissileData(const afxMagicMissileData& other, bool { CLONE_ASSET(ProjectileShape); projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName - CLONE_ASSET_REFACTOR(ProjectileSound); + CLONE_ASSET(ProjectileSound); splash = other.splash; splashId = other.splashId; // -- for pack/unpack of splash ptr lightDesc = other.lightDesc; @@ -344,7 +345,7 @@ void afxMagicMissileData::initPersistFields() endGroup("Particle Effects"); addGroup("Sounds"); - INITPERSISTFIELD_SSOUNDASSET_REFACTOR(ProjectileSound, afxMagicMissileData, "sound for the projectile") + INITPERSISTFIELD_SOUNDASSET(ProjectileSound, afxMagicMissileData, "sound for the projectile"); endGroup("Sounds"); addGroup("Light Emitter"); @@ -516,7 +517,7 @@ bool afxMagicMissileData::preload(bool server, String &errorStr) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(decal): %d", decalId); */ - if (mProjectileShapeAsset.isNull()) + if (!isProjectileSoundValid()) { //return false; -TODO: trigger asset download } @@ -626,7 +627,7 @@ void afxMagicMissileData::packData(BitStream* stream) DataBlockObjectIdLast); */ - PACKDATA_ASSET_REFACTOR(ProjectileSound) + PACKDATA_ASSET(ProjectileSound); if ( stream->writeFlag(lightDesc != NULL)) stream->writeRangedU32(lightDesc->getId(), DataBlockObjectIdFirst, @@ -732,7 +733,7 @@ void afxMagicMissileData::unpackData(BitStream* stream) decalId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); */ - UNPACKDATA_ASSET_REFACTOR(ProjectileSound) + UNPACKDATA_ASSET(ProjectileSound); if (stream->readFlag()) lightDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); @@ -1156,8 +1157,8 @@ bool afxMagicMissile::onNewDataBlock(GameBaseData* dptr, bool reload) SFX_DELETE( mSound ); - if (mDataBlock->getProjectileSoundAsset().notNull()) - mSound = SFX->createSource(mDataBlock->getProjectileSoundAsset()->getSFXTrack()); + if (mDataBlock->getProjectileSound()) + mSound = SFX->createSource(mDataBlock->getProjectileSoundProfile()); } return true; @@ -1992,7 +1993,7 @@ void afxMagicMissile::get_launch_data(Point3F& pos, Point3F& vel) void afxMagicMissile::updateSound() { - if (mDataBlock->getProjectileSoundAsset().isNull()) + if (!mDataBlock->isProjectileSoundValid()) return; if ( mSound ) diff --git a/Engine/source/afx/afxMagicMissile.h b/Engine/source/afx/afxMagicMissile.h index 9f0c90227..e3f6ee755 100644 --- a/Engine/source/afx/afxMagicMissile.h +++ b/Engine/source/afx/afxMagicMissile.h @@ -126,7 +126,8 @@ public: SplashData* splash; // Water Splash Datablock S32 splashId; // Water splash ID - DECLARE_SOUNDASSET_REFACTOR(afxMagicMissileData, ProjectileSound) + DECLARE_SOUNDASSET(afxMagicMissileData, ProjectileSound); + DECLARE_ASSET_SETGET(afxMagicMissileData, ProjectileSound); LightDescription *lightDesc; S32 lightDescId; From b2fe48ab8d5d2382e87e89b3304c0126e2914c9f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 24 Mar 2025 21:50:04 +0000 Subject: [PATCH 17/47] more merge conflicts fixed more merge conflicts (afxZodiac and MaterialDefinition) Updated cubemapdata to use refactor asset added new part to image_asset macro to create a private asset if the file exists. updated reflectionProbe errors to actual function name where the error occurs. --- Engine/source/T3D/assets/ImageAsset.h | 14 ++++- .../source/T3D/lighting/reflectionProbe.cpp | 4 +- Engine/source/afx/ce/afxZodiac.cpp | 17 +----- Engine/source/gfx/sim/cubemapData.cpp | 61 +++++++++---------- Engine/source/gfx/sim/cubemapData.h | 12 ++-- .../source/materials/materialDefinition.cpp | 17 ------ 6 files changed, 50 insertions(+), 75 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 1198aa6bd..1f6289cb7 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -171,7 +171,7 @@ public: void setTextureHDR(const bool pIsHDR); inline bool getTextureHDR(void) const { return mIsHDRImage; }; - inline GFXTexHandle& getTexture(void) { load(); generateTexture(); return mTextureHandle; } + inline GFXTexHandle& getTexture(void) { load(); generateTexture(); return mTextureHandle; } GFXTexHandle getTexture(GFXTextureProfile* requestedProfile); static StringTableEntry getImageTypeNameFromType(ImageTypes type); @@ -610,6 +610,12 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ + else if(Torque::FS::IsFile(_in)) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ m##name##Asset = imageAssetId; \ } \ else \ @@ -677,6 +683,12 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ + else if(Torque::FS::IsFile(_in)) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ m##name##Asset[index] = imageAssetId; \ } \ else \ diff --git a/Engine/source/T3D/lighting/reflectionProbe.cpp b/Engine/source/T3D/lighting/reflectionProbe.cpp index 793f7dd1d..b4a10342f 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.cpp +++ b/Engine/source/T3D/lighting/reflectionProbe.cpp @@ -605,7 +605,7 @@ void ReflectionProbe::processBakedCubemap() if (mIrridianceMap == nullptr || mIrridianceMap->mCubemap.isNull()) { - Con::errorf("ReflectionProbe::processDynamicCubemap() - Unable to load baked irradiance map at %s", getIrradianceMapPath().c_str()); + Con::errorf("ReflectionProbe::processBakedCubemap() - Unable to load baked irradiance map at %s", getIrradianceMapPath().c_str()); return; } @@ -618,7 +618,7 @@ void ReflectionProbe::processBakedCubemap() if (mPrefilterMap == nullptr || mPrefilterMap->mCubemap.isNull()) { - Con::errorf("ReflectionProbe::processDynamicCubemap() - Unable to load baked prefilter map at %s", getPrefilterMapPath().c_str()); + Con::errorf("ReflectionProbe::processBakedCubemap() - Unable to load baked prefilter map at %s", getPrefilterMapPath().c_str()); return; } diff --git a/Engine/source/afx/ce/afxZodiac.cpp b/Engine/source/afx/ce/afxZodiac.cpp index 9e7ed11d5..88d9d9fec 100644 --- a/Engine/source/afx/ce/afxZodiac.cpp +++ b/Engine/source/afx/ce/afxZodiac.cpp @@ -324,22 +324,11 @@ bool afxZodiacData::preload(bool server, String &errorStr) if (vert_range.x == 0.0f && vert_range.y == 0.0f) vert_range.x = vert_range.y = radius_xy; - if (mTextureAssetId != StringTable->EmptyString()) + if (mTextureAsset.notNull()) { - mTextureAsset = mTextureAssetId; - if (mTextureAsset.notNull()) - { - if (getTexture() != StringTable->EmptyString() && mTextureName != StringTable->insert("texhandle")) - { - if (mTextureAsset.notNull()) - { - mTextureAsset->getChangedSignal().notify(this, &afxZodiacData::onImageChanged); - } - - mTexture.set(getTexture(), mTextureProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); - } - } + getTexture(); } + return true; } diff --git a/Engine/source/gfx/sim/cubemapData.cpp b/Engine/source/gfx/sim/cubemapData.cpp index 0e7d7686e..5165a2d24 100644 --- a/Engine/source/gfx/sim/cubemapData.cpp +++ b/Engine/source/gfx/sim/cubemapData.cpp @@ -41,13 +41,6 @@ IMPLEMENT_CONOBJECT( CubemapData ); CubemapData::CubemapData() { mCubemap = NULL; - - for (U32 i = 0; i < 6; i++) - { - INIT_IMAGEASSET_ARRAY(CubeMapFace, GFXStaticTextureSRGBProfile, i); - } - - INIT_ASSET(CubeMap); } CubemapData::~CubemapData() @@ -77,17 +70,7 @@ ConsoleDocClass( CubemapData, void CubemapData::initPersistFields() { docsURL; - addProtectedField( "cubeFace", TypeStringFilename, Offset(mCubeMapFaceName, CubemapData), _setCubeMapFaceData, defaultProtectedGetFn, 6, - "@brief The 6 cubemap face textures for a static cubemap.\n\n" - "They are in the following order:\n" - " - cubeFace[0] is -X\n" - " - cubeFace[1] is +X\n" - " - cubeFace[2] is -Z\n" - " - cubeFace[3] is +Z\n" - " - cubeFace[4] is -Y\n" - " - cubeFace[5] is +Y\n", AbstractClassRep::FIELD_HideInInspectors ); - - INITPERSISTFIELD_IMAGEASSET_ARRAY(CubeMapFace, 6, CubemapData, "@brief The 6 cubemap face textures for a static cubemap.\n\n" + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(CubeMapFace, 6, CubemapData, "@brief The 6 cubemap face textures for a static cubemap.\n\n" "They are in the following order:\n" " - cubeFace[0] is -X\n" " - cubeFace[1] is +X\n" @@ -96,7 +79,7 @@ void CubemapData::initPersistFields() " - cubeFace[4] is -Y\n" " - cubeFace[5] is +Y\n"); - INITPERSISTFIELD_IMAGEASSET(CubeMap, CubemapData, "@brief Cubemap dds Image Asset.\n\n"); + INITPERSISTFIELD_IMAGEASSET_REFACTOR(CubeMap, CubemapData, "@brief Cubemap dds Image Asset.\n\n"); } bool CubemapData::onAdd() @@ -116,19 +99,26 @@ void CubemapData::createMap() { bool initSuccess = true; //check mCubeMapFile first - if (getCubeMap() != StringTable->EmptyString()) + if (mCubeMapAsset.notNull()) { - mCubemap = TEXMGR->createCubemap(getCubeMap()); + mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile()); return; } else { for (U32 i = 0; i < 6; i++) { - if (!_setCubeMapFace(getCubeMapFace(i), i)) + if (mCubeMapFaceAsset[i].notNull()) { - Con::errorf("CubemapData::createMap - Failed to load texture '%s'", getCubeMapFace(i)); - initSuccess = false; + if (!getCubeMapFace(i)) + { + Con::errorf("CubemapData::createMap - Failed to load texture '%s'", getCubeMapFace(i)); + initSuccess = false; + } + else + { + mCubeMapFaceTex[i] = getCubeMapFace(i); + } } } } @@ -136,9 +126,10 @@ void CubemapData::createMap() if( initSuccess ) { mCubemap = GFX->createCubemap(); - if (!mCubeMapFace || mCubeMapFace->isNull()) + if (mCubeMapFaceAsset->isNull()) return; - mCubemap->initStatic(mCubeMapFace); + + mCubemap->initStatic(mCubeMapFaceTex); } } } @@ -150,18 +141,22 @@ void CubemapData::updateFaces() for( U32 i=0; i<6; i++ ) { //check mCubeMapFile first - if (getCubeMap() != StringTable->EmptyString()) + if (mCubeMapAsset.notNull()) { - mCubemap = TEXMGR->createCubemap(getCubeMap()); + mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile()); return; } else { - if (!_setCubeMapFace(getCubeMapFace(i), i)) + if (!getCubeMapFace(i)) { Con::errorf("CubemapData::createMap - Failed to load texture '%s'", getCubeMapFace(i)); initSuccess = false; } + else + { + mCubeMapFaceTex[i] = getCubeMapFace(i); + } } } @@ -170,13 +165,13 @@ void CubemapData::updateFaces() mCubemap = NULL; mCubemap = GFX->createCubemap(); - mCubemap->initStatic( mCubeMapFace ); + mCubemap->initStatic(mCubeMapFaceTex); } } void CubemapData::setCubemapFile(FileName newCubemapFile) { - mCubeMapName = newCubemapFile; + _setCubeMap(newCubemapFile); } void CubemapData::setCubeFaceFile(U32 index, FileName newFaceFile) @@ -184,7 +179,7 @@ void CubemapData::setCubeFaceFile(U32 index, FileName newFaceFile) if (index >= 6) return; - mCubeMapFaceName[index] = newFaceFile; + _setCubeMapFace(newFaceFile, index); } void CubemapData::setCubeFaceTexture(U32 index, GFXTexHandle newFaceTexture) @@ -192,7 +187,7 @@ void CubemapData::setCubeFaceTexture(U32 index, GFXTexHandle newFaceTexture) if (index >= 6) return; - mCubeMapFace[index] = newFaceTexture; + mCubeMapFaceTex[index] = newFaceTexture; } DefineEngineMethod( CubemapData, updateFaces, void, (),, diff --git a/Engine/source/gfx/sim/cubemapData.h b/Engine/source/gfx/sim/cubemapData.h index c79dd4289..8fea60641 100644 --- a/Engine/source/gfx/sim/cubemapData.h +++ b/Engine/source/gfx/sim/cubemapData.h @@ -70,20 +70,16 @@ public: void setCubeFaceTexture(U32 index, GFXTexHandle newFaceTexture); - GFXTexHandle* getCubeFaceTexture(U32 faceIdx) { return &mCubeMapFace[faceIdx]; } + GFXTexHandle* getCubeFaceTexture(U32 faceIdx) { return &mCubeMapFaceTex[faceIdx]; } protected: - DECLARE_IMAGEASSET(CubemapData, CubeMap, onCubemapChanged, GFXStaticTextureSRGBProfile); - DECLARE_ASSET_SETGET(CubemapData, CubeMap); + DECLARE_IMAGEASSET_REFACTOR(CubemapData, CubeMap, GFXStaticTextureSRGBProfile); - DECLARE_IMAGEASSET_ARRAY(CubemapData, CubeMapFace, 6, onCubeMapFaceChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(CubemapData, CubeMapFace); + DECLARE_IMAGEASSET_ARRAY_REFACTOR(CubemapData, CubeMapFace, GFXStaticTextureSRGBProfile, 6); - void onCubeMapFaceChanged() {} + GFXTexHandle mCubeMapFaceTex[6]; GFXTexHandle mDepthBuff; GFXTextureTargetRef mRenderTarget; - - void onCubemapChanged() {} }; #endif // CUBEMAPDATA diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 64e12bb23..98bdb9729 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -232,11 +232,6 @@ FRangeValidator glowMulRange(0.0f, 20.0f); FRangeValidator parallaxScaleRange(0.0f, 4.0f); FRangeValidator scrollSpeedRange(0.0f, 10.0f); FRangeValidator waveFreqRange(0.0f, 10.0f); -void Material::onImageAssetChanged() -{ - flush(); - reload(); -} void Material::initPersistFields() { @@ -495,18 +490,6 @@ void Material::initPersistFields() // They point at the new 'map' fields, but reads always return // an empty string and writes only apply if the value is not empty. // - addProtectedField("baseTex", TypeImageFilename, Offset(mDiffuseMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see diffuseMap\n", AbstractClassRep::FIELD_HideInInspectors); - addProtectedField("detailTex", TypeImageFilename, Offset(mDetailMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see detailMap\n", AbstractClassRep::FIELD_HideInInspectors); - addProtectedField("overlayTex", TypeImageFilename, Offset(mOverlayMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see overlayMap\n", AbstractClassRep::FIELD_HideInInspectors); - addProtectedField("bumpTex", TypeImageFilename, Offset(mNormalMapName, Material), - defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, - "For backwards compatibility.\n@see normalMap\n", AbstractClassRep::FIELD_HideInInspectors); addProtectedField("colorMultiply", TypeColorF, Offset(mDiffuse, Material), defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, "For backwards compatibility.\n@see diffuseColor\n", AbstractClassRep::FIELD_HideInInspectors); From 15503cbf7cfebfd6873ca75ff8f1a711ef75619c Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 24 Mar 2025 22:18:18 +0000 Subject: [PATCH 18/47] Update cubemapData.cpp --- Engine/source/gfx/sim/cubemapData.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Engine/source/gfx/sim/cubemapData.cpp b/Engine/source/gfx/sim/cubemapData.cpp index 5165a2d24..c73afb4cd 100644 --- a/Engine/source/gfx/sim/cubemapData.cpp +++ b/Engine/source/gfx/sim/cubemapData.cpp @@ -112,7 +112,7 @@ void CubemapData::createMap() { if (!getCubeMapFace(i)) { - Con::errorf("CubemapData::createMap - Failed to load texture '%s'", getCubeMapFace(i)); + Con::errorf("CubemapData::createMap - Failed to load texture '%s'", mCubeMapFaceAsset[i]->getImageFile()); initSuccess = false; } else @@ -148,14 +148,17 @@ void CubemapData::updateFaces() } else { - if (!getCubeMapFace(i)) + if (mCubeMapFaceAsset[i].notNull()) { - Con::errorf("CubemapData::createMap - Failed to load texture '%s'", getCubeMapFace(i)); - initSuccess = false; - } - else - { - mCubeMapFaceTex[i] = getCubeMapFace(i); + if (!getCubeMapFace(i)) + { + Con::errorf("CubemapData::createMap - Failed to load texture '%s'", mCubeMapFaceAsset[i]->getImageFile()); + initSuccess = false; + } + else + { + mCubeMapFaceTex[i] = getCubeMapFace(i); + } } } } From 6640cae0d72581ffb8aa7cb699fda0abfaf2c621 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 25 Mar 2025 14:34:28 +0000 Subject: [PATCH 19/47] Update cubemapData.cpp missed checks, and loop should be inner --- Engine/source/gfx/sim/cubemapData.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Engine/source/gfx/sim/cubemapData.cpp b/Engine/source/gfx/sim/cubemapData.cpp index c73afb4cd..494ba1852 100644 --- a/Engine/source/gfx/sim/cubemapData.cpp +++ b/Engine/source/gfx/sim/cubemapData.cpp @@ -138,15 +138,15 @@ void CubemapData::updateFaces() { bool initSuccess = true; - for( U32 i=0; i<6; i++ ) + //check mCubeMapFile first + if (mCubeMapAsset.notNull()) { - //check mCubeMapFile first - if (mCubeMapAsset.notNull()) - { - mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile()); - return; - } - else + mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile()); + return; + } + else + { + for (U32 i = 0; i < 6; i++) { if (mCubeMapFaceAsset[i].notNull()) { @@ -167,6 +167,8 @@ void CubemapData::updateFaces() { mCubemap = NULL; mCubemap = GFX->createCubemap(); + if (mCubeMapFaceAsset->isNull()) + return; mCubemap->initStatic(mCubeMapFaceTex); } From 987ff90467d22be921f539b64410b596a04e14bf Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 25 Mar 2025 18:22:26 +0000 Subject: [PATCH 20/47] named target functionality --- Engine/source/T3D/assets/ImageAsset.cpp | 25 +++++++++++++++++++ Engine/source/T3D/assets/ImageAsset.h | 4 ++- .../materials/processedShaderMaterial.cpp | 16 +++++++++--- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 8f62bd7f9..ed6505313 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -332,6 +332,9 @@ void ImageAsset::initializeAsset(void) Parent::initializeAsset(); // Ensure the image-file is expanded. + if (isNamedTarget()) + return; + mImageFile = expandAssetFilePath(mImageFile); } @@ -378,6 +381,13 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) if (mLoadedState == Ok) Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); + if (String(pImageFile).startsWith("#")) + { + mImageFile = StringTable->insert(pImageFile); + refreshAsset(); + return; + } + mImageFile = getOwned() ? expandAssetFilePath(pImageFile) : StringTable->insert(pImageFile); refreshAsset(); @@ -411,6 +421,12 @@ U32 ImageAsset::load() if (!Torque::FS::IsFile(mImageFile)) { + if (isNamedTarget()) + { + mLoadedState = Ok; + return mLoadedState; + } + Con::errorf("ImageAsset::initializeAsset: Attempted to load file %s but it was not valid!", mImageFile); mLoadedState = BadFileReference; return mLoadedState; @@ -428,6 +444,9 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) { load(); + if (isNamedTarget()) + return getNamedTarget()->getTexture(); + if (mLoadedState == Ok) { if (mResourceMap.contains(requestedProfile)) @@ -554,6 +573,9 @@ void ImageAsset::onTamlPreWrite(void) // Call parent. Parent::onTamlPreWrite(); + if (isNamedTarget()) + return; + // Ensure the image-file is collapsed. mImageFile = getOwned() ? collapseAssetFilePath(mImageFile) : mImageFile; } @@ -563,6 +585,9 @@ void ImageAsset::onTamlPostWrite(void) // Call parent. Parent::onTamlPostWrite(); + if (isNamedTarget()) + return; + // Ensure the image-file is expanded. mImageFile = getOwned() ? expandAssetFilePath(mImageFile) : mImageFile; } diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 1f6289cb7..e9898a393 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -137,7 +137,6 @@ private: GFXTexHandle mTextureHandle; ImageTypes mImageType; HashMap mResourceMap; - void generateTexture(void); public: ImageAsset(); @@ -189,6 +188,9 @@ public: inline U32 getTextureBitmapDepth(void) const { return mTextureHandle->getBitmapDepth(); } bool isAssetValid(void) const override { return !mTextureHandle.isNull(); } + bool isNamedTarget(void) const { return String(getImageFile()).startsWith("#"); } + NamedTexTargetRef getNamedTarget(void) const { return NamedTexTarget::find(mImageFile + 1); } + static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* imageAsset); static StringTableEntry getAssetIdByFilename(StringTableEntry fileName); static U32 getAssetById(StringTableEntry assetId, AssetPtr* imageAsset); diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 7b5617a5e..12885a7cf 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -231,8 +231,7 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features, } if (mMaterial && mMaterial->getDiffuseMapAsset(0).notNull() && String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).startsWith("#")) { - String texTargetBufferName = String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).substr(1, (U32)strlen(mMaterial->getDiffuseMapAsset(0)->getImageFile()) - 1); - NamedTexTarget *texTarget = NamedTexTarget::find(texTargetBufferName); + NamedTexTarget *texTarget = mMaterial->getDiffuseMapAsset(0)->getNamedTarget(); RenderPassData* rpd = getPass(0); if (rpd) @@ -878,8 +877,17 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S texTarget = rpd->mTexSlot[i].texTarget; if ( !texTarget ) { - GFX->setTexture( i, NULL ); - break; + // try again. + texTarget = mMaterial->getDiffuseMapAsset(0)->getNamedTarget(); + if (!texTarget) + { + GFX->setTexture(i, NULL); + break; + } + else + { + rpd->mTexSlot[i].texTarget = texTarget; + } } texObject = texTarget->getTexture(); From 6c2b4f89797f699baabcb7183ac3aa9e774645ff Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 25 Mar 2025 19:14:05 +0000 Subject: [PATCH 21/47] null handling --- Engine/source/T3D/assets/ImageAsset.cpp | 4 +++- Engine/source/T3D/assets/ImageAsset.h | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index ed6505313..d9e309f7c 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -187,7 +187,8 @@ ImageAsset::ImageAsset() : mUseMips(true), mIsHDRImage(false), mImageType(Albedo), - mTextureHandle(NULL) + mTextureHandle(NULL), + mIsNamedTarget(false) { mLoadedState = AssetErrCode::NotLoaded; } @@ -384,6 +385,7 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) if (String(pImageFile).startsWith("#")) { mImageFile = StringTable->insert(pImageFile); + mIsNamedTarget = true; refreshAsset(); return; } diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index e9898a393..d6a6aa1ab 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -137,6 +137,7 @@ private: GFXTexHandle mTextureHandle; ImageTypes mImageType; HashMap mResourceMap; + bool mIsNamedTarget; void generateTexture(void); public: ImageAsset(); @@ -188,7 +189,7 @@ public: inline U32 getTextureBitmapDepth(void) const { return mTextureHandle->getBitmapDepth(); } bool isAssetValid(void) const override { return !mTextureHandle.isNull(); } - bool isNamedTarget(void) const { return String(getImageFile()).startsWith("#"); } + bool isNamedTarget(void) const { return mIsNamedTarget; } NamedTexTargetRef getNamedTarget(void) const { return NamedTexTarget::find(mImageFile + 1); } static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* imageAsset); @@ -700,7 +701,7 @@ public: }; \ \ inline StringTableEntry _get##name(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ - GFXTexHandle get##name(const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(&profile) : NULL; } \ + GFXTexHandle get##name(const U32& index) { return get##name(&profile, index); } \ GFXTexHandle get##name(GFXTextureProfile* requestedProfile, const U32& index) { return m##name##Asset[index].notNull() ? m##name##Asset[index]->getTexture(requestedProfile) : NULL; }\ AssetPtr get##name##Asset(const U32& index) { return m##name##Asset[index]; } \ static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} From 9f2ab5a64ef664b1f4bf7b50d7ac4343b12742bd Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 07:57:14 +0000 Subject: [PATCH 22/47] Update particleEmitter.cpp null check around asset --- Engine/source/T3D/fx/particleEmitter.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index f55657ccd..718b9df6e 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -740,16 +740,19 @@ bool ParticleEmitterData::preload(bool server, String &errorStr) // otherwise, check that all particles refer to the same texture else if (particleDataBlocks.size() > 1) { - StringTableEntry txr_name = particleDataBlocks[0]->getTextureAsset()->getImageFile(); - for (S32 i = 1; i < particleDataBlocks.size(); i++) - { - // warn if particle textures are inconsistent - if (particleDataBlocks[i]->getTextureAsset()->getImageFile() != txr_name) - { - Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) particles reference different textures.", getName()); - break; - } - } + if (particleDataBlocks[0]->getTextureAsset().notNull()) + { + StringTableEntry txr_name = particleDataBlocks[0]->getTextureAsset()->getImageFile(); + for (S32 i = 1; i < particleDataBlocks.size(); i++) + { + // warn if particle textures are inconsistent + if (particleDataBlocks[i]->getTextureAsset()->getImageFile() != txr_name) + { + Con::warnf(ConsoleLogEntry::General, "ParticleEmitterData(%s) particles reference different textures.", getName()); + break; + } + } + } } } From bab7878ca6f170fbc474d686558b8391c88cf424 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 09:12:06 +0000 Subject: [PATCH 23/47] give named target a fallback we need to give named target a fallback image so references are kept when a named target is not ready. --- Engine/source/T3D/assets/ImageAsset.cpp | 23 +++++++++++++++--- Engine/source/T3D/assets/ImageAsset.h | 1 + .../core/rendering/Core_Rendering.tscript | 1 + .../core/rendering/images/namedTarget.png | Bin 0 -> 11733 bytes .../images/namedTarget_image.asset.taml | 3 +++ 5 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 Templates/BaseGame/game/core/rendering/images/namedTarget.png create mode 100644 Templates/BaseGame/game/core/rendering/images/namedTarget_image.asset.taml diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index d9e309f7c..093fde0b8 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -53,6 +53,7 @@ //----------------------------------------------------------------------------- StringTableEntry ImageAsset::smNoImageAssetFallback = NULL; +StringTableEntry ImageAsset::smNamedTargetAssetFallback = NULL; //----------------------------------------------------------------------------- @@ -139,7 +140,6 @@ ConsoleSetType(TypeImageAssetPtrRefactor) // Is the asset pointer the correct type? if (pAssetPtr == NULL) { - // No, so fail. Con::warnf("(TypeImageAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); return; } @@ -207,7 +207,12 @@ void ImageAsset::consoleInit() "The assetId of the texture to display when the requested image asset is missing.\n" "@ingroup GFX\n"); + Con::addVariable("$Core::NamedTargetFallback", TypeString, &smNamedTargetAssetFallback, + "The assetId of the texture to display when the requested image asset is named target.\n" + "@ingroup GFX\n"); + smNoImageAssetFallback = StringTable->insert(Con::getVariable("$Core::NoImageAssetFallback")); + smNamedTargetAssetFallback = StringTable->insert(Con::getVariable("$Core::NamedTargetFallback")); } //----------------------------------------------------------------------------- @@ -447,7 +452,19 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) load(); if (isNamedTarget()) - return getNamedTarget()->getTexture(); + { + GFXTexHandle tex = getNamedTarget()->getTexture(); + if(tex.isNull()) + { + AssetPtr fallbackAsset; + ImageAsset::getAssetById(smNamedTargetAssetFallback, &fallbackAsset); + return fallbackAsset->getTexture(); + } + else + { + return tex; + } + } if (mLoadedState == Ok) { @@ -460,7 +477,7 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) //If we don't have an existing map case to the requested format, we'll just create it and insert it in GFXTexHandle newTex; - newTex.set(mImageFile, requestedProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + newTex.set(mImageFile, requestedProfile, avar("%s %s() - mTextureObject (line %d)", mImageFile, __FUNCTION__, __LINE__)); if (newTex) { mLoadedState = AssetErrCode::Ok; diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index d6a6aa1ab..02ec29c5b 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -113,6 +113,7 @@ public: }; static StringTableEntry smNoImageAssetFallback; + static StringTableEntry smNamedTargetAssetFallback; enum ImageAssetErrCode { diff --git a/Templates/BaseGame/game/core/rendering/Core_Rendering.tscript b/Templates/BaseGame/game/core/rendering/Core_Rendering.tscript index 1051ee621..8675e3168 100644 --- a/Templates/BaseGame/game/core/rendering/Core_Rendering.tscript +++ b/Templates/BaseGame/game/core/rendering/Core_Rendering.tscript @@ -9,6 +9,7 @@ function Core_Rendering::onCreate(%this) $Core::WetnessTexture = "core/rendering/images/wetMap.png"; $Core::NoImageAssetFallback = "Core_Rendering:missingTexture_image"; + $Core::NamedTargetFallback = "Core_Rendering:namedTarget_image"; $Core::NoMaterialAssetFallback = "Core_Rendering:noMaterial"; $Core::NoShapeAssetFallback = "Core_Rendering:noShape"; diff --git a/Templates/BaseGame/game/core/rendering/images/namedTarget.png b/Templates/BaseGame/game/core/rendering/images/namedTarget.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2656a5fffa2d15d5063f25f4ee67dc10fd1caa GIT binary patch literal 11733 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/rendering/images/namedTarget_image.asset.taml b/Templates/BaseGame/game/core/rendering/images/namedTarget_image.asset.taml new file mode 100644 index 000000000..7cd23509a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/images/namedTarget_image.asset.taml @@ -0,0 +1,3 @@ + From 16d219769f08a89baadb86c877dc209e248d0582 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 10:12:14 +0000 Subject: [PATCH 24/47] set preview image set the image asset preview image for namedTargets --- Engine/source/T3D/assets/ImageAsset.cpp | 8 ++++++++ .../tools/assetBrowser/scripts/assetTypes/image.tscript | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 093fde0b8..f02e79db0 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -649,6 +649,14 @@ DefineEngineMethod(ImageAsset, getImageInfo, const char*, (), , return object->getImageInfo(); } +DefineEngineMethod(ImageAsset, isNamedTarget, bool, (), , + "Gets whether this image is a named target.\n" + "@return bool for isNamedTarget.") +{ + return object->isNamedTarget(); +} + + #ifdef TORQUE_TOOLS DefineEngineStaticMethod(ImageAsset, getAssetIdByFilename, const char*, (const char* filePath), (""), "Queries the Asset Database to see if any asset exists that is associated with the provided file path.\n" diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index 6e2e9deea..2263d0227 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -179,8 +179,8 @@ function AssetBrowser::buildImageAssetPreview(%this, %assetDef, %previewData) { //%module = %this.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%assetDef.getImagePath()))); - %previewData.previewImage = "ToolsModule:genericAssetIcon_image"; - %previewData.previewLoaded = false; //this marks it for loading progressively later + %previewData.previewImage = %assetDef.isNamedTarget() ? "Core_Rendering:namedTarget_image" : "ToolsModule:genericAssetIcon_image"; + %previewData.previewLoaded = %assetDef.isNamedTarget() ? true : false; //if image target we are loaded, else mark for loading later. %previewData.assetName = %assetDef.assetName; %previewData.assetPath = %assetDef.scriptFile; From e1a2a6d9f944a33f26417f81e6ac612144dabe0e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 10:55:54 +0000 Subject: [PATCH 25/47] fix material editor material editor now handles named targets propertly when loading also update preview image in material editor --- .../assetBrowser/scripts/assetBrowser.tscript | 3 +- .../scripts/materialEditor.ed.tscript | 30 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index 1fc3b3efd..b820a3e22 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -2772,6 +2772,7 @@ function AssetBrowser::importLooseFiles(%this) function getAssetPreviewImage(%asset) { + echo(%asset); if(isFile(%asset)) { %aq = new AssetQuery(); @@ -2793,7 +2794,7 @@ function getAssetPreviewImage(%asset) %moduleName = AssetDatabase.getAssetModule(%asset).ModuleId; %assetName = AssetDatabase.getAssetName(%asset); %previewAssetName = "ToolsModule:" @ %moduleName @ "_" @ %assetName @ "_PreviewImage"; - + echo(%previewAssetName); if(AssetDatabase.isDeclaredAsset(%previewAssetName)) { %previewDef = AssetDatabase.acquireAsset(%previewAssetName); diff --git a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript index a0919e915..a9b958d47 100644 --- a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript +++ b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript @@ -747,8 +747,8 @@ function MaterialEditorGui::setActiveMaterial( %this, %material ) // we create or recreate a material to hold in a pristine state // or, this crashes the ap. fix properly - BJR -// if(isObject(notDirtyMaterial)) -// notDirtyMaterial.delete(); + //if(isObject(notDirtyMaterial)) + // notDirtyMaterial.delete(); singleton Material(notDirtyMaterial) { @@ -860,16 +860,27 @@ function MaterialEditorGui::convertTextureFields(%this) } function MaterialEditorGui::convertMaterialTextureField(%this, %material, %mapName) - { +{ for(%index = 0; %index < 4; %index++) { %mapFile = %material.call("get" @ %mapName, %index); if(%mapFile !$= "" && !isFile(%mapFile)) - { - //see if we can't go finding it - %mapFile = MaterialEditorGui.searchForTexture(MaterialEditorGui.currentMaterial, %mapFile); - MaterialEditorGui.currentMaterial.call("set" @ %mapName, %mapFile, %index); - } + { + if(isFile(%mapFile)) + { + //see if we can't go finding it + %mapFile = MaterialEditorGui.searchForTexture(MaterialEditorGui.currentMaterial, %mapFile); + MaterialEditorGui.currentMaterial.call("set" @ %mapName, %mapFile, %index); + } + else + { + %assetPtr = %material.call("get" @ %mapName @ "Asset", %index); + if(%assetPtr.isNamedTarget()) + { + MaterialEditorGui.currentMaterial.call("set" @ %mapName, %assetPtr, %index); + } + } + } } } @@ -1088,8 +1099,9 @@ function MaterialEditorGui::guiSync( %this, %material ) //Diffuse %diffuseMap = (%material).getDiffuseMap(%layer); %diffuseMapText = %diffuseMap !$= "" && %diffuseMap !$=$MaterialEditor::emptyMaterialImage ? (%material).getDiffuseMapAsset(%layer) : "None"; + MaterialEditorPropertiesWindow-->diffuseMapNameText.setText( %diffuseMapText ); - MaterialEditorPropertiesWindow-->diffuseMapDisplayBitmap.setBitmap( getAssetPreviewImage(%diffuseMap) ); + MaterialEditorPropertiesWindow-->diffuseMapDisplayBitmap.setBitmap( getAssetPreviewImage(%diffuseMapText) ); //Normal %normalMap = (%material).getNormalMap(%layer); From d86962d1fdce64b06aee449c0f9fa3e8aa5dd34f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 14:31:11 +0000 Subject: [PATCH 26/47] requirements for postfx update to handle posteffects with image_asset_refactor --- Engine/source/T3D/assets/ImageAsset.cpp | 2 +- Engine/source/T3D/assets/ImageAsset.h | 3 +- Engine/source/postFx/postEffect.cpp | 62 +++++++++++++------------ Engine/source/postFx/postEffect.h | 6 +-- Engine/source/postFx/postEffectVis.cpp | 8 ++-- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index f02e79db0..0004145bd 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -387,7 +387,7 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) if (mLoadedState == Ok) Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); - if (String(pImageFile).startsWith("#")) + if (String(pImageFile).startsWith("#") || String(pImageFile).startsWith("$")) { mImageFile = StringTable->insert(pImageFile); mIsNamedTarget = true; diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 02ec29c5b..9d7338644 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -677,7 +677,6 @@ public: void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ return; \ - \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ StringTableEntry imageAssetId = StringTable->EmptyString(); \ @@ -687,7 +686,7 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ - else if(Torque::FS::IsFile(_in)) \ + else if(Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ { \ ImageAsset* privateImage = new ImageAsset(); \ privateImage->setImageFile(_in); \ diff --git a/Engine/source/postFx/postEffect.cpp b/Engine/source/postFx/postEffect.cpp index 8026dd392..8c87d601a 100644 --- a/Engine/source/postFx/postEffect.cpp +++ b/Engine/source/postFx/postEffect.cpp @@ -508,10 +508,6 @@ PostEffect::PostEffect() dMemset( mTexSizeSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures ); dMemset( mRenderTargetParamsSC, 0, sizeof( GFXShaderConstHandle* ) * NumTextures ); - for (U32 i = 0; i < NumTextures; i++) - { - INIT_IMAGEASSET_ARRAY(Texture, PostFxTextureProfile, i); - } } PostEffect::~PostEffect() @@ -556,7 +552,8 @@ void PostEffect::initPersistFields() addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ), "Specifies how the viewport should be set up for a target texture." ); - INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, NumTextures, PostEffect, "Input textures to this effect ( samplers ).\n" + addProtectedField("Texture", TypeImageFilename, Offset(mTextureAsset, PostEffect), _setTextureData, &defaultProtectedGetFn, NumTextures, "Input textures to this effect(samplers).\n", AbstractClassRep::FIELD_HideInInspectors); + INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Texture, NumTextures, PostEffect, "Input textures to this effect ( samplers ).\n" "@see PFXTextureIdentifiers"); addField("textureSRGB", TypeBool, Offset(mTexSRGB, PostEffect), NumTextures, @@ -608,22 +605,24 @@ bool PostEffect::onAdd() for (S32 i = 0; i < NumTextures; i++) { mTextureType[i] = NormalTextureType; - String texFilename = getTexture(i); + if (mTextureAsset[i].notNull()) { + String texFilename = mTextureAsset[i]->getImageFile(); - // Skip empty stages or ones with variable or target names. - if (texFilename.isEmpty() || - texFilename[0] == '$' || - texFilename[0] == '#') - continue; + // Skip empty stages or ones with variable or target names. + if (texFilename.isEmpty() || + texFilename[0] == '$' || + texFilename[0] == '#') + continue; - mTextureProfile[i] = (mTexSRGB[i]) ? &PostFxTextureSRGBProfile : &PostFxTextureProfile; - _setTexture(texFilename, i); + mTextureProfile[i] = (mTexSRGB[i]) ? &PostFxTextureSRGBProfile : &PostFxTextureProfile; + _setTexture(texFilename, i); + } } // Is the target a named target? if ( mTargetName.isNotEmpty() && mTargetName[0] == '#' ) { - mNamedTarget.registerWithName( mTargetName.substr( 1 ) ); + mNamedTarget.registerWithName(mTargetName.substr(1)); mNamedTarget.getTextureDelegate().bind( this, &PostEffect::_getTargetTexture ); } if ( mTargetDepthStencilName.isNotEmpty() && mTargetDepthStencilName[0] == '#' ) @@ -1136,7 +1135,7 @@ void PostEffect::_setupConstants( const SceneRenderState *state ) void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI *inTexViewport ) { - const String &texFilename = getTexture( stage ); + const String &texFilename = mTextureAsset[stage].notNull() ? mTextureAsset[stage]->getImageFile() : ""; GFXTexHandle theTex; NamedTexTarget *namedTarget = NULL; @@ -1173,7 +1172,11 @@ void PostEffect::_setupTexture( U32 stage, GFXTexHandle &inputTex, const RectI * } else { - theTex = mTexture[ stage ]; + theTex = mTexture[stage]; + + if (!theTex && mTextureAsset[stage].notNull()) + theTex = mTextureAsset[stage]->getTexture(mTextureProfile[stage]); + if ( theTex ) viewport.set( 0, 0, theTex->getWidth(), theTex->getHeight() ); } @@ -1640,7 +1643,6 @@ void PostEffect::reload() void PostEffect::setTexture( U32 index, const String &texFilePath ) { // Set the new texture name. - mTextureName[index] = texFilePath; mTexture[index].free(); // Skip empty stages or ones with variable or target names. @@ -1651,14 +1653,13 @@ void PostEffect::setTexture( U32 index, const String &texFilePath ) mTextureProfile[index] = (mTexSRGB[index])? &PostFxTextureSRGBProfile : &PostFxTextureProfile; _setTexture(texFilePath, index); - + mTexture[index] = mTextureAsset[index]->getTexture(mTextureProfile[index]); mTextureType[index] = NormalTextureType; } void PostEffect::setTexture(U32 index, const GFXTexHandle& texHandle) { // Set the new texture name. - mTextureName[index] = StringTable->EmptyString(); mTexture[index].free(); // Skip empty stages or ones with variable or target names. @@ -1847,18 +1848,21 @@ void PostEffect::_checkRequirements() { if (mTextureType[i] == NormalTextureType) { - const String &texFilename = mTextureName[i]; - - if (texFilename.isNotEmpty() && texFilename[0] == '#') + if (mTextureAsset[i].notNull()) { - NamedTexTarget *namedTarget = NamedTexTarget::find(texFilename.c_str() + 1); - if (!namedTarget) - { - return; - } + const String& texFilename = mTextureAsset[i]->getImageFile(); - // Grab the macros for shader initialization. - namedTarget->getShaderMacros(¯os); + if (texFilename.isNotEmpty() && texFilename[0] == '#') + { + NamedTexTarget* namedTarget = NamedTexTarget::find(texFilename.c_str() + 1); + if (!namedTarget) + { + return; + } + + // Grab the macros for shader initialization. + namedTarget->getShaderMacros(¯os); + } } } } diff --git a/Engine/source/postFx/postEffect.h b/Engine/source/postFx/postEffect.h index e485f14d2..4f9a1c2c8 100644 --- a/Engine/source/postFx/postEffect.h +++ b/Engine/source/postFx/postEffect.h @@ -90,9 +90,9 @@ public: protected: - DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, NumTextures, onTextureChanged); - DECLARE_IMAGEASSET_ARRAY_SETGET(PostEffect, Texture); - void onTextureChanged() {} + DECLARE_IMAGEASSET_ARRAY_REFACTOR(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures); + GFXTextureProfile* mTextureProfile[NumTextures]; + GFXTexHandle mTexture[NumTextures]; bool mTexSRGB[NumTextures]; diff --git a/Engine/source/postFx/postEffectVis.cpp b/Engine/source/postFx/postEffectVis.cpp index a3ff66b9c..4a7442b72 100644 --- a/Engine/source/postFx/postEffectVis.cpp +++ b/Engine/source/postFx/postEffectVis.cpp @@ -103,7 +103,7 @@ void PostEffectVis::open( PostEffect *pfx ) // Only allocate window/bitmaps for input textures that are actually used. if ( i > Target ) { - if ( pfx->mTextureName[i-1] == StringTable->EmptyString()) + if ( pfx->mTextureAsset[i-1].notNull() && pfx->mTextureAsset[i - 1]->getImageFile() == StringTable->EmptyString()) { window.window[i] = NULL; window.bmp[i] = NULL; @@ -275,9 +275,9 @@ void PostEffectVis::onPFXProcessed( PostEffect *pfx ) if ( tex ) - dSprintf( caption, 256, "%s[%i] input%i - %s [ %ix%i ]", name, pfx->getId(), i-1, pfx->mTextureName[i-1], tex->getWidth(), tex->getHeight() ); + dSprintf( caption, 256, "%s[%i] input%i - %s [ %ix%i ]", name, pfx->getId(), i-1, pfx->mTextureAsset[i - 1].notNull() ? pfx->mTextureAsset[i - 1]->getImageFile() : "", tex->getWidth(), tex->getHeight()); else - dSprintf( caption, 256, "%s[%i] input%i - %s", name, pfx->getId(), i-1, pfx->mTextureName[i-1] ); + dSprintf( caption, 256, "%s[%i] input%i - %s", name, pfx->getId(), i-1, pfx->mTextureAsset[i - 1].notNull() ? pfx->mTextureAsset[i - 1]->getImageFile() : ""); pWinCtrl->setDataField( StringTable->insert("text"), NULL, caption ); } @@ -364,7 +364,7 @@ void PostEffectVis::_setDefaultCaption( VisWindow &vis, U32 texIndex ) else dSprintf( name, 256, "%s", pfx->getName() ); - dSprintf( caption, 256, "%s[%i] input%i - %s [NOT ENABLED]", name, pfx->getId(), texIndex-1, pfx->mTextureName[texIndex-1] ); + dSprintf( caption, 256, "%s[%i] input%i - %s [NOT ENABLED]", name, pfx->getId(), texIndex-1, pfx->mTextureAsset[texIndex - 1].notNull() ? pfx->mTextureAsset[texIndex - 1]->getImageFile() : ""); winCtrl->setDataField( StringTable->insert("text"), NULL, caption ); } From 465c79f39d93a70182a03a706ecb3c3e77d6b81a Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 15:07:07 +0000 Subject: [PATCH 27/47] Update ImageAsset.h update macros to share target functionality add extra check to see if image asset exists. --- Engine/source/T3D/assets/ImageAsset.h | 48 +++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 9d7338644..f06994dec 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -614,11 +614,15 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ - else if(Torque::FS::IsFile(_in)) \ + else if(Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ { \ - ImageAsset* privateImage = new ImageAsset(); \ - privateImage->setImageFile(_in); \ - imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + imageAssetId = ImageAsset::getAssetIdByFilename(_in); \ + if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ } \ m##name##Asset = imageAssetId; \ } \ @@ -641,7 +645,6 @@ public: void _set##name(StringTableEntry _in){ \ if(m##name##Asset.getAssetId() == _in) \ return; \ - \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ StringTableEntry imageAssetId = StringTable->EmptyString(); \ @@ -651,11 +654,21 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ - m##name##Asset = imageAssetId; \ + else if(Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + imageAssetId = ImageAsset::getAssetIdByFilename(_in); \ + if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ + } \ + m##name##Asset[index] = imageAssetId; \ } \ else \ { \ - m##name##Asset = _in; \ + m##name##Asset[index] = _in; \ } \ setMaskBits(mask); \ }; \ @@ -688,9 +701,13 @@ public: } \ else if(Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ { \ - ImageAsset* privateImage = new ImageAsset(); \ - privateImage->setImageFile(_in); \ - imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + imageAssetId = ImageAsset::getAssetIdByFilename(_in); \ + if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ } \ m##name##Asset[index] = imageAssetId; \ } \ @@ -714,7 +731,6 @@ public: void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ return; \ - \ if(!AssetDatabase.isDeclaredAsset(_in)) \ { \ StringTableEntry imageAssetId = StringTable->EmptyString(); \ @@ -724,6 +740,16 @@ public: { \ imageAssetId = query.mAssetList[0]; \ } \ + else if(Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + imageAssetId = ImageAsset::getAssetIdByFilename(_in); \ + if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ + { \ + ImageAsset* privateImage = new ImageAsset(); \ + privateImage->setImageFile(_in); \ + imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ + } \ + } \ m##name##Asset[index] = imageAssetId; \ } \ else \ From f59ccc3f9970225765118519b53f163e74fe959b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 15:41:53 +0000 Subject: [PATCH 28/47] Update ImageAsset.h --- Engine/source/T3D/assets/ImageAsset.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index f06994dec..9e1deddde 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -660,15 +660,16 @@ public: if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ { \ ImageAsset* privateImage = new ImageAsset(); \ + privateImage->mpModuleDefinition = ModuleDatabase->findLoadedModule("Core"); \ privateImage->setImageFile(_in); \ imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ } \ - m##name##Asset[index] = imageAssetId; \ + m##name##Asset = imageAssetId; \ } \ else \ { \ - m##name##Asset[index] = _in; \ + m##name##Asset = _in; \ } \ setMaskBits(mask); \ }; \ From 086db03bbcf1aa029729381a9d321b49a0bf0b5c Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 15:42:26 +0000 Subject: [PATCH 29/47] Update ImageAsset.h --- Engine/source/T3D/assets/ImageAsset.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 9e1deddde..c1bb9dd58 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -660,7 +660,6 @@ public: if (imageAssetId == ImageAsset::smNoImageAssetFallback) \ { \ ImageAsset* privateImage = new ImageAsset(); \ - privateImage->mpModuleDefinition = ModuleDatabase->findLoadedModule("Core"); \ privateImage->setImageFile(_in); \ imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ From b630442683c7d9c6553a6ac6ae114cc4bc930927 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 17:34:25 +0000 Subject: [PATCH 30/47] Update assetManager.cpp stop crash when dumping declared assets if the asset is private --- Engine/source/assets/assetManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/assets/assetManager.cpp b/Engine/source/assets/assetManager.cpp index 30efc47db..863f7638c 100644 --- a/Engine/source/assets/assetManager.cpp +++ b/Engine/source/assets/assetManager.cpp @@ -1613,8 +1613,8 @@ void AssetManager::dumpDeclaredAssets( void ) const pAssetDefinition->mAssetInternal, pAssetDefinition->mAssetPrivate, pAssetDefinition->mAssetType, - pAssetDefinition->mpModuleDefinition->getModuleId(), - pAssetDefinition->mpModuleDefinition->getVersionId(), + pAssetDefinition->mAssetPrivate ? "Private" : pAssetDefinition->mpModuleDefinition->getModuleId(), + pAssetDefinition->mAssetPrivate ? 0 : pAssetDefinition->mpModuleDefinition->getVersionId(), pAssetDefinition->mAssetBaseFilePath ); } From 7af992970a542e4a2dada0eba1326cb1932d8c2b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 18:51:44 +0000 Subject: [PATCH 31/47] Update ImageAsset.cpp update getAssetIdByFilename to also check the imageFile of the asset This helps match filenames for assets created privately such as probe bakes and targets --- Engine/source/T3D/assets/ImageAsset.cpp | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 0004145bd..27fa241f6 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -297,7 +297,38 @@ StringTableEntry ImageAsset::getAssetIdByFilename(StringTableEntry fileName) } else { - AssetPtr imageAsset = imageAssetId; //ensures the fallback is loaded + foundAssetcount = AssetDatabase.findAssetType(&query, "ImageAsset"); + if (foundAssetcount != 0) + { + // loop all image assets and see if we can find one + // using the same image file/named target. + for (auto imgAsset : query.mAssetList) + { + AssetPtr temp = imgAsset; + if (temp.notNull()) + { + if (temp->getImageFile() == fileName) + { + return imgAsset; + } + else + { + Torque::Path temp1 = temp->getImageFile(); + Torque::Path temp2 = fileName; + + if (temp1.getFileName() == temp2.getFileName()) + { + return imgAsset; + } + } + + } + } + } + else + { + AssetPtr imageAsset = imageAssetId; //ensures the fallback is loaded + } } return imageAssetId; From 3b70689abccae5547d5c14a5ea3db906fe1c0751 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 26 Mar 2025 21:16:43 +0000 Subject: [PATCH 32/47] clean out old macros --- Engine/source/T3D/assets/ImageAsset.cpp | 65 ----- Engine/source/T3D/assets/ImageAsset.h | 363 ------------------------ 2 files changed, 428 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 27fa241f6..1137e9a41 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -59,56 +59,6 @@ StringTableEntry ImageAsset::smNamedTargetAssetFallback = NULL; IMPLEMENT_CONOBJECT(ImageAsset); -ConsoleType(ImageAssetPtr, TypeImageAssetPtr, const char*, "") - -//----------------------------------------------------------------------------- - -ConsoleGetType(TypeImageAssetPtr) -{ - // Fetch asset Id. - return *((const char**)(dptr)); -} - -//----------------------------------------------------------------------------- - -ConsoleSetType(TypeImageAssetPtr) -{ - // Was a single argument specified? - if (argc == 1) - { - // Yes, so fetch field value. - *((const char**)dptr) = StringTable->insert(argv[0]); - - return; - } - - // Warn. - Con::warnf("(TypeImageAssetPtr) - Cannot set multiple args to a single asset."); -} - -ConsoleType(assetIdString, TypeImageAssetId, const char*, "") - -ConsoleGetType(TypeImageAssetId) -{ - // Fetch asset Id. - return *((const char**)(dptr)); -} - -ConsoleSetType(TypeImageAssetId) -{ - // Was a single argument specified? - if (argc == 1) - { - *((const char**)dptr) = StringTable->insert(argv[0]); - - return; - } - - // Warn. - Con::warnf("(TypeImageAssetId) - Cannot set multiple args to a single asset."); -} - -//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // REFACTOR @@ -978,18 +928,3 @@ void GuiInspectorTypeImageAssetPtr::setPreviewImage(StringTableEntry assetId) if (mPreviewImage->getBitmapAsset().isNull()) mPreviewImage->_setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); } - -IMPLEMENT_CONOBJECT(GuiInspectorTypeImageAssetId); - -ConsoleDocClass(GuiInspectorTypeImageAssetId, - "@brief Inspector field type for Images\n\n" - "Editor use only.\n\n" - "@internal" -); - -void GuiInspectorTypeImageAssetId::consoleInit() -{ - Parent::consoleInit(); - - ConsoleBaseType::getType(TypeImageAssetId)->setInspectorFieldType("GuiInspectorTypeImageAssetId"); -} diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index c1bb9dd58..b363ed8a1 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -226,375 +226,12 @@ protected: static bool writeTextureHDR(void* obj, StringTableEntry pFieldName) { return static_cast(obj)->getTextureHDR() == true; } }; -DefineConsoleType(TypeImageAssetPtr, ImageAsset) -DefineConsoleType(TypeImageAssetId, String) - DECLARE_STRUCT(AssetPtr) DefineConsoleType(TypeImageAssetPtrRefactor, AssetPtr ) typedef ImageAsset::ImageTypes ImageAssetType; DefineEnumType(ImageAssetType); -#pragma region Singular Asset Macros - -//Singular assets -/// -/// Declares an image asset -/// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions -/// -#define DECLARE_IMAGEASSET(className, name, changeFunc, profile) public: \ - GFXTexHandle m##name = NULL;\ - StringTableEntry m##name##Name; \ - StringTableEntry m##name##AssetId;\ - AssetPtr m##name##Asset;\ - GFXTextureProfile* m##name##Profile = &profile;\ -public: \ - const StringTableEntry get##name##File() const { return m##name##Name; }\ - void set##name##File(const FileName &_in) { m##name##Name = StringTable->insert(_in.c_str());}\ - const AssetPtr & get##name##Asset() const { return m##name##Asset; }\ - void set##name##Asset(const AssetPtr &_in) { m##name##Asset = _in;}\ - \ - bool _set##name(StringTableEntry _in)\ - {\ - if(m##name##AssetId != _in || m##name##Name != _in)\ - {\ - if (_in == NULL || _in == StringTable->EmptyString())\ - {\ - m##name##Name = StringTable->EmptyString();\ - m##name##AssetId = StringTable->EmptyString();\ - m##name##Asset = NULL;\ - m##name.free();\ - m##name = NULL;\ - return true;\ - }\ - else if(_in[0] == '$' || _in[0] == '#')\ - {\ - m##name##Name = _in;\ - m##name##AssetId = StringTable->EmptyString();\ - m##name##Asset = NULL;\ - m##name.free();\ - m##name = NULL;\ - return true;\ - }\ - \ - if (AssetDatabase.isDeclaredAsset(_in))\ - {\ - m##name##AssetId = _in;\ - \ - U32 assetState = ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset);\ - \ - if (ImageAsset::Ok == assetState)\ - {\ - m##name##Name = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - StringTableEntry assetId = ImageAsset::getAssetIdByFilename(_in);\ - if (assetId != StringTable->EmptyString())\ - {\ - m##name##AssetId = assetId;\ - if (ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset) == ImageAsset::Ok)\ - {\ - m##name##Name = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - m##name##Name = _in;\ - m##name##AssetId = StringTable->EmptyString();\ - m##name##Asset = NULL;\ - }\ - }\ - }\ - if (get##name() != StringTable->EmptyString() && m##name##Name != StringTable->insert("texhandle"))\ - {\ - \ - if (get##name()[0] != '$' && get##name()[0] != '#') {\ - m##name.set(get##name(), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\ - }\ - }\ - else\ - {\ - m##name.free();\ - m##name = NULL;\ - }\ - \ - if(get##name() == StringTable->EmptyString())\ - return true;\ - \ - if (m##name##Asset.notNull() && m##name##Asset->getStatus() != ImageAsset::Ok)\ - {\ - Con::errorf("%s(%s)::_set%s() - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ImageAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\ - return false; \ - }\ - else if (!m##name)\ - {\ - if (GFX->getAdapterType() != NullDevice)\ - Con::errorf("%s(%s)::_set%s() - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), _in);\ - return false;\ - }\ - return true;\ - }\ - \ - const StringTableEntry get##name() const\ - {\ - if (m##name##Asset && (m##name##Asset->getImageFile() != StringTable->EmptyString()))\ - if (m##name##Asset->getImageFile()[0] == '#' || m##name##Asset->getImageFile()[0] == '$')\ - return m##name##Asset->getImageFile();\ - else\ - return Platform::makeRelativePathName(m##name##Asset->getImageFile(), Platform::getMainDotCsDir());\ - else if (m##name##AssetId != StringTable->EmptyString())\ - return m##name##AssetId;\ - else if (m##name##Name != StringTable->EmptyString())\ - return StringTable->insert(Platform::makeRelativePathName(m##name##Name, Platform::getMainDotCsDir()));\ - else\ - return StringTable->EmptyString();\ - }\ - GFXTexHandle get##name##Resource() \ - {\ - if (m##name##Asset && (m##name##Asset->getImageFile() != 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); } - -#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS - -#define INITPERSISTFIELD_IMAGEASSET(name, consoleClass, docs) \ - addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, docs)); \ - addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); - -#else - -#define INITPERSISTFIELD_IMAGEASSET(name, consoleClass, docs) \ - addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, docs), AbstractClassRep::FIELD_HideInInspectors); \ - addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); - -#endif // SHOW_LEGACY_FILE_FIELDS - -#define LOAD_IMAGEASSET(name)\ -if (m##name##AssetId != StringTable->EmptyString())\ -{\ - S32 assetState = ImageAsset::getAssetById(m##name##AssetId, &m##name##Asset);\ - if (assetState == ImageAsset::Ok )\ - {\ - m##name##Name = StringTable->EmptyString();\ - }\ - else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId, ImageAsset::getAssetErrstrn(assetState).c_str());\ -} - - -#pragma endregion - -#pragma region Arrayed Asset Macros - -//Arrayed Assets -#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]; \ - StringTableEntry m##name##AssetId[max];\ - AssetPtr m##name##Asset[max];\ - GFXTextureProfile * m##name##Profile[max];\ -public: \ - const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\ - void set##name##File(const FileName &_in, const U32& index) { m##name##Name[index] = StringTable->insert(_in.c_str());}\ - const AssetPtr & get##name##Asset(const U32& index) const { return m##name##Asset[index]; }\ - void set##name##Asset(const AssetPtr &_in, const U32& index) { m##name##Asset[index] = _in;}\ - \ - bool _set##name(StringTableEntry _in, const U32& index)\ - {\ - if(m##name##AssetId[index] != _in || m##name##Name[index] != _in)\ - {\ - if(index >= sm##name##Count || index < 0)\ - return false;\ - if (_in == NULL || _in == StringTable->EmptyString())\ - {\ - m##name##Name[index] = StringTable->EmptyString();\ - m##name##AssetId[index] = StringTable->EmptyString();\ - m##name##Asset[index] = NULL;\ - m##name[index].free();\ - m##name[index] = NULL;\ - return true;\ - }\ - else if(_in[0] == '$' || _in[0] == '#')\ - {\ - m##name##Name[index] = _in;\ - m##name##AssetId[index] = StringTable->EmptyString();\ - m##name##Asset[index] = NULL;\ - m##name[index].free();\ - m##name[index] = NULL;\ - return true;\ - }\ - \ - if (AssetDatabase.isDeclaredAsset(_in))\ - {\ - m##name##AssetId[index] = _in;\ - \ - U32 assetState = ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\ - \ - if (ImageAsset::Ok == assetState)\ - {\ - m##name##Name[index] = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - StringTableEntry assetId = ImageAsset::getAssetIdByFilename(_in);\ - if (assetId != StringTable->EmptyString())\ - {\ - m##name##AssetId[index] = assetId;\ - if (ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]) == ImageAsset::Ok)\ - {\ - m##name##Name[index] = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - m##name##Name[index] = _in;\ - m##name##AssetId[index] = StringTable->EmptyString();\ - m##name##Asset[index] = NULL;\ - }\ - }\ - }\ - if (get##name(index) != StringTable->EmptyString() && m##name##Name[index] != StringTable->insert("texhandle"))\ - {\ - 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\ - {\ - m##name[index].free();\ - m##name[index] = NULL;\ - }\ - \ - if(get##name(index) == StringTable->EmptyString())\ - return true;\ - \ - if (m##name##Asset[index].notNull() && m##name##Asset[index]->getStatus() != ImageAsset::Ok)\ - {\ - Con::errorf("%s(%s)::_set%s(%i) - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), index, _in, ImageAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\ - return false; \ - }\ - else if (!m##name[index])\ - {\ - if (GFX->getAdapterType() != NullDevice)\ - Con::errorf("%s(%s)::_set%s(%i) - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), index, _in);\ - return false; \ - }\ - return true;\ - }\ - \ - const StringTableEntry get##name(const U32& index) const\ - {\ - if (m##name##Asset[index] && (m##name##Asset[index]->getImageFile() != StringTable->EmptyString()))\ - if (m##name##Asset[index]->getImageFile()[0] == '#' || m##name##Asset[index]->getImageFile()[0] == '$')\ - return m##name##Asset[index]->getImageFile();\ - else\ - return Platform::makeRelativePathName(m##name##Asset[index]->getImageFile(), Platform::getMainDotCsDir());\ - else if (m##name##AssetId[index] != StringTable->EmptyString())\ - return m##name##AssetId[index];\ - else if (m##name##Name[index] != StringTable->EmptyString())\ - {\ - if (String(m##name##Name[index]).startsWith("#") || String(m##name##Name[index]).startsWith("$"))\ - return StringTable->insert(m##name##Name[index]);\ - else\ - return StringTable->insert(Platform::makeRelativePathName(m##name##Name[index], Platform::getMainDotCsDir()));\ - }\ - else\ - return StringTable->EmptyString();\ - }\ - GFXTexHandle get##name##Resource(const U32& index) \ - {\ - if(index >= sm##name##Count || index < 0)\ - return nullptr;\ - if (m##name##Asset[index] && (m##name##Asset[index]->getImageFile() != 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); } - -#define DECLARE_IMAGEASSET_ARRAY_SETGET(className, name)\ - static bool _set##name##Data(void* obj, const char* index, const char* data)\ - {\ - if (!index) return false;\ - U32 idx = dAtoi(index);\ - if (idx >= sm##name##Count)\ - return false;\ - bool ret = false;\ - className* object = static_cast(obj);\ - ret = object->_set##name(StringTable->insert(data),idx);\ - return ret;\ - } - -#define DECLARE_IMAGEASSET_ARRAY_NET_SETGET(className, name, bitmask)\ - static bool _set##name##Data(void* obj, const char* index, const char* data)\ - {\ - if (!index) return false;\ - U32 idx = dAtoi(index);\ - if (idx >= sm##name##Count)\ - return false;\ - bool ret = false;\ - className* object = static_cast(obj);\ - ret = object->_set##name(StringTable->insert(data),idx);\ - if(ret)\ - object->setMaskBits(bitmask);\ - return ret;\ - } - -#define INIT_IMAGEASSET_ARRAY(name, profile, index) \ -{\ - m##name##Name[index] = StringTable->EmptyString(); \ - m##name##AssetId[index] = StringTable->EmptyString(); \ - m##name##Asset[index] = NULL;\ - m##name[index] = NULL;\ - m##name##Profile[index] = &profile;\ -} - -#define DEF_IMAGEASSET_ARRAY_BINDS(className,name)\ -DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\ -{\ - return object->get##name(index); \ -}\ -DefineEngineMethod(className, get##name##Asset, const char*, (S32 index), , assetText(name, asset reference))\ -{\ - if(index >= className::sm##name##Count || index < 0)\ - return "";\ - return object->m##name##AssetId[index]; \ -}\ -DefineEngineMethod(className, set##name, bool, (const char* map, S32 index), , assetText(name,assignment. first tries asset then flat file.))\ -{\ - return object->_set##name(StringTable->insert(map), index);\ -} - -#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS - -#define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \ - addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs)); \ - addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); - -#else - -#define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \ - addProtectedField(#name, TypeImageFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs), AbstractClassRep::FIELD_HideInInspectors); \ - addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); - -#endif - -#define LOAD_IMAGEASSET_ARRAY(name, index)\ -if (m##name##AssetId[index] != StringTable->EmptyString())\ -{\ - S32 assetState = ImageAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\ - if (assetState == ImageAsset::Ok )\ - {\ - m##name##Name[index] = StringTable->EmptyString();\ - }\ - else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId[index], ImageAsset::getAssetErrstrn(assetState).c_str());\ -} - -#pragma endregion - #pragma region Refactor Asset Macros #define DECLARE_IMAGEASSET_REFACTOR(className, name, profile) \ From a8d7664fc2e22386f370200a95791840697722ec Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 08:31:28 +0000 Subject: [PATCH 33/47] named target material reload clean clean up the previous requirements for namedTarget to display on a material --- Engine/source/materials/materialManager.cpp | 36 --------------------- Engine/source/materials/materialManager.h | 14 ++------ 2 files changed, 2 insertions(+), 48 deletions(-) diff --git a/Engine/source/materials/materialManager.cpp b/Engine/source/materials/materialManager.cpp index 87ce2bef2..86efe3c17 100644 --- a/Engine/source/materials/materialManager.cpp +++ b/Engine/source/materials/materialManager.cpp @@ -61,8 +61,6 @@ MaterialManager::MaterialManager() mLastTime = 0; mDampness = 0.0f; mWarningInst = NULL; - mMatDefToFlush = NULL; - mMatDefToReload = NULL; GFXDevice::getDeviceEventSignal().notify( this, &MaterialManager::_handleGFXEvent ); @@ -75,8 +73,6 @@ MaterialManager::MaterialManager() mUsingDeferred = false; mFlushAndReInit = false; - mMatDefShouldFlush = false; - mMatDefShouldReload = false; mDefaultAnisotropy = 1; Con::addVariable( "$pref::Video::defaultAnisotropy", TypeS32, &mDefaultAnisotropy, @@ -328,12 +324,6 @@ 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; @@ -368,16 +358,8 @@ void MaterialManager::_flushAndReInitInstances() (*iter)->reInit(); } -// Used in the materialEditor. This flushes the material preview object so it can be reloaded easily. -void MaterialManager::flushInstance(BaseMaterialDefinition* target) -{ - mMatDefToFlush = target; - mMatDefShouldFlush = true; -} - void MaterialManager::_flushInstance( BaseMaterialDefinition *target ) { - mMatDefShouldFlush = false; Vector::iterator iter = mMatInstanceList.begin(); while ( iter != mMatInstanceList.end() ) { @@ -388,26 +370,16 @@ void MaterialManager::_flushInstance( BaseMaterialDefinition *target ) } iter++; } - - mMatDefToFlush = NULL; -} - -void MaterialManager::reInitInstance(BaseMaterialDefinition* target) -{ - mMatDefToReload = target; - mMatDefShouldReload = true; } void MaterialManager::_reInitInstance( BaseMaterialDefinition *target ) { - mMatDefShouldReload = false; Vector::iterator iter = mMatInstanceList.begin(); for ( ; iter != mMatInstanceList.end(); iter++ ) { if ( (*iter)->getMaterial() == target ) (*iter)->reInit(); } - mMatDefToReload = NULL; } void MaterialManager::updateTime() @@ -527,14 +499,6 @@ bool MaterialManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ ) case GFXDevice::deStartOfFrame: if ( mFlushAndReInit ) _flushAndReInitInstances(); - if (mMatDefShouldFlush) - { - _flushInstance(mMatDefToFlush); - } - if (mMatDefShouldReload) - { - _reInitInstance(mMatDefToReload); - } break; default: diff --git a/Engine/source/materials/materialManager.h b/Engine/source/materials/materialManager.h index 2d983da7a..8dd4d28a3 100644 --- a/Engine/source/materials/materialManager.h +++ b/Engine/source/materials/materialManager.h @@ -113,15 +113,9 @@ public: /// procedural shaders have been flushed. typedef Signal FlushSignal; - /// 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 ); - - /// Re-initializes the material instances for a specific target material. - void reInitInstance( BaseMaterialDefinition *target ); protected: @@ -158,8 +152,6 @@ 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 MaterialMap; @@ -174,8 +166,6 @@ protected: F32 mDampness; BaseMatInstance* mWarningInst; - BaseMaterialDefinition* mMatDefToFlush; - BaseMaterialDefinition* mMatDefToReload; /// The default max anisotropy used in texture filtering. S32 mDefaultAnisotropy; From c025ea86b4ceaccdc390f4c775bb06e191279394 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 08:59:50 +0000 Subject: [PATCH 34/47] more cleanups cleanup the type removing the refactor tag materialManager restored to its original state --- Engine/source/T3D/assets/ImageAsset.cpp | 8 ++++---- Engine/source/T3D/assets/ImageAsset.h | 6 +++--- Engine/source/gui/controls/guiPopUpCtrl.cpp | 2 +- Engine/source/gui/controls/guiPopUpCtrlEx.cpp | 2 +- Engine/source/gui/core/guiTypes.cpp | 2 +- Engine/source/gui/editor/inspector/group.cpp | 2 +- .../gui/editor/inspector/variableInspector.cpp | 2 +- Engine/source/materials/materialManager.cpp | 4 ++-- Engine/source/materials/materialManager.h | 13 ++++++------- 9 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 1137e9a41..6ee7d1d96 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -67,16 +67,16 @@ IMPLEMENT_CONOBJECT(ImageAsset); IMPLEMENT_STRUCT(AssetPtr, AssetPtrImageAsset,, "") END_IMPLEMENT_STRUCT -ConsoleType(ImageAssetPtr, TypeImageAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) +ConsoleType(ImageAssetPtr, TypeImageAssetPtr, AssetPtr, ASSET_ID_FIELD_PREFIX) -ConsoleGetType(TypeImageAssetPtrRefactor) +ConsoleGetType(TypeImageAssetPtr) { // Fetch asset Id. return (*((AssetPtr*)dptr)).getAssetId(); } -ConsoleSetType(TypeImageAssetPtrRefactor) +ConsoleSetType(TypeImageAssetPtr) { // Was a single argument specified? if (argc == 1) @@ -662,7 +662,7 @@ void GuiInspectorTypeImageAssetPtr::consoleInit() { Parent::consoleInit(); - ConsoleBaseType::getType(TypeImageAssetPtrRefactor)->setInspectorFieldType("GuiInspectorTypeImageAssetPtr"); + ConsoleBaseType::getType(TypeImageAssetPtr)->setInspectorFieldType("GuiInspectorTypeImageAssetPtr"); } GuiControl* GuiInspectorTypeImageAssetPtr::constructEditControl() diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index b363ed8a1..20234ea03 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -227,7 +227,7 @@ protected: }; DECLARE_STRUCT(AssetPtr) -DefineConsoleType(TypeImageAssetPtrRefactor, AssetPtr ) +DefineConsoleType(TypeImageAssetPtr, AssetPtr ) typedef ImageAsset::ImageTypes ImageAssetType; DefineEnumType(ImageAssetType); @@ -317,7 +317,7 @@ public: #define INITPERSISTFIELD_IMAGEASSET_REFACTOR(name, consoleClass, docs) \ - addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); + addProtectedField(assetText(name, Asset), TypeImageAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); #define DECLARE_IMAGEASSET_ARRAY_REFACTOR(className, name, profile, max) \ @@ -404,7 +404,7 @@ public: #define INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ - addProtectedField(assetText(name, Asset), TypeImageAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); + addProtectedField(assetText(name, Asset), TypeImageAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); #define DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(className,name, max)\ DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\ diff --git a/Engine/source/gui/controls/guiPopUpCtrl.cpp b/Engine/source/gui/controls/guiPopUpCtrl.cpp index 9ffa82929..9ec981352 100644 --- a/Engine/source/gui/controls/guiPopUpCtrl.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrl.cpp @@ -299,7 +299,7 @@ void GuiPopUpMenuCtrl::initPersistFields(void) addField("sbUsesNAColor", TypeBool, Offset(mRenderScrollInNA, GuiPopUpMenuCtrl)); addField("reverseTextList", TypeBool, Offset(mReverseTextList, GuiPopUpMenuCtrl)); - addProtectedField("BitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiPopUpMenuCtrl), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"\"."); + addProtectedField("BitmapAsset", TypeImageAssetPtr, Offset(mBitmapAsset, GuiPopUpMenuCtrl), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"\"."); addField("bitmapBounds", TypePoint2I, Offset(mBitmapBounds, GuiPopUpMenuCtrl)); diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp index a33538ef4..7e99f20d9 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.cpp +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.cpp @@ -354,7 +354,7 @@ void GuiPopUpMenuCtrlEx::initPersistFields(void) addField("sbUsesNAColor", TypeBool, Offset(mRenderScrollInNA, GuiPopUpMenuCtrlEx), "Deprecated" "@internal"); addField("reverseTextList", TypeBool, Offset(mReverseTextList, GuiPopUpMenuCtrlEx), "Reverses text list if popup extends up, instead of down"); - addProtectedField("BitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiPopUpMenuCtrlEx), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"Name of bitmap asset to use\"."); + addProtectedField("BitmapAsset", TypeImageAssetPtr, Offset(mBitmapAsset, GuiPopUpMenuCtrlEx), _setBitmaps, &defaultProtectedGetFn, "@brief ""Bitmap"" ""asset \"Name of bitmap asset to use\"."); addField("bitmapBounds", TypePoint2I, Offset(mBitmapBounds, GuiPopUpMenuCtrlEx), "Boundaries of bitmap displayed"); addField("hotTrackCallback", TypeBool, Offset(mHotTrackItems, GuiPopUpMenuCtrlEx), diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index 13135d7ef..bcfcf2123 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -442,7 +442,7 @@ void GuiControlProfile::initPersistFields() "Texture to use for rendering control.", AbstractClassRep::FIELD_HideInInspectors); #endif - addProtectedField("bitmapAsset", TypeImageAssetPtrRefactor, Offset(mBitmapAsset, GuiControlProfile), + addProtectedField("bitmapAsset", TypeImageAssetPtr, Offset(mBitmapAsset, GuiControlProfile), &GuiControlProfile::protectedSetBitmap, &defaultProtectedGetFn, "Texture to use for rendering control."); diff --git a/Engine/source/gui/editor/inspector/group.cpp b/Engine/source/gui/editor/inspector/group.cpp index 2254f38dd..6bd243d60 100644 --- a/Engine/source/gui/editor/inspector/group.cpp +++ b/Engine/source/gui/editor/inspector/group.cpp @@ -663,7 +663,7 @@ void GuiInspectorGroup::addInspectorField(StringTableEntry name, StringTableEntr else if (typeName == StringTable->insert("material")) fieldType = TypeMaterialAssetId; else if (typeName == StringTable->insert("image")) - fieldType = TypeImageAssetPtrRefactor; + fieldType = TypeImageAssetPtr; else if (typeName == StringTable->insert("shape")) fieldType = TypeShapeAssetId; else if (typeName == StringTable->insert("sound")) diff --git a/Engine/source/gui/editor/inspector/variableInspector.cpp b/Engine/source/gui/editor/inspector/variableInspector.cpp index 80195fc00..41a165d32 100644 --- a/Engine/source/gui/editor/inspector/variableInspector.cpp +++ b/Engine/source/gui/editor/inspector/variableInspector.cpp @@ -203,7 +203,7 @@ void GuiVariableInspector::addField(const char* name, const char* label, const c else if (newField->mFieldTypeName == StringTable->insert("material")) fieldTypeMask = TypeMaterialAssetId; else if (newField->mFieldTypeName == StringTable->insert("image")) - fieldTypeMask = TypeImageAssetPtrRefactor; + fieldTypeMask = TypeImageAssetPtr; else if (newField->mFieldTypeName == StringTable->insert("shape")) fieldTypeMask = TypeShapeAssetId; else if (newField->mFieldTypeName == StringTable->insert("bool")) diff --git a/Engine/source/materials/materialManager.cpp b/Engine/source/materials/materialManager.cpp index 86efe3c17..194449ae2 100644 --- a/Engine/source/materials/materialManager.cpp +++ b/Engine/source/materials/materialManager.cpp @@ -358,7 +358,7 @@ void MaterialManager::flushAndReInitInstances() (*iter)->reInit(); } -void MaterialManager::_flushInstance( BaseMaterialDefinition *target ) +void MaterialManager::flushInstance( BaseMaterialDefinition *target ) { Vector::iterator iter = mMatInstanceList.begin(); while ( iter != mMatInstanceList.end() ) @@ -372,7 +372,7 @@ void MaterialManager::_flushInstance( BaseMaterialDefinition *target ) } } -void MaterialManager::_reInitInstance( BaseMaterialDefinition *target ) +void MaterialManager::reInitInstance( BaseMaterialDefinition *target ) { Vector::iterator iter = mMatInstanceList.begin(); for ( ; iter != mMatInstanceList.end(); iter++ ) diff --git a/Engine/source/materials/materialManager.h b/Engine/source/materials/materialManager.h index 8dd4d28a3..3a52363a3 100644 --- a/Engine/source/materials/materialManager.h +++ b/Engine/source/materials/materialManager.h @@ -117,20 +117,19 @@ public: /// 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); + protected: // MatInstance tracks it's instances here 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 ); From ea49af52a56514d9ae42e56461deae73c5a459f4 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 09:00:12 +0000 Subject: [PATCH 35/47] Update materialManager.cpp --- Engine/source/materials/materialManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/materials/materialManager.cpp b/Engine/source/materials/materialManager.cpp index 194449ae2..97dd0b848 100644 --- a/Engine/source/materials/materialManager.cpp +++ b/Engine/source/materials/materialManager.cpp @@ -498,7 +498,7 @@ bool MaterialManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ ) case GFXDevice::deStartOfFrame: if ( mFlushAndReInit ) - _flushAndReInitInstances(); + flushAndReInitInstances(); break; default: From fad397d914ae4f1f08d2b80899b9d911098db83d Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 09:11:40 +0000 Subject: [PATCH 36/47] always cleanup -_- --- Engine/source/materials/materialManager.h | 4 ++++ .../game/tools/worldEditor/gui/objectBuilderGui.ed.gui | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Engine/source/materials/materialManager.h b/Engine/source/materials/materialManager.h index 3a52363a3..6d0fbdd53 100644 --- a/Engine/source/materials/materialManager.h +++ b/Engine/source/materials/materialManager.h @@ -113,6 +113,10 @@ public: /// procedural shaders have been flushed. typedef Signal FlushSignal; + /// 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(); diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index 83595d5d5..c84636946 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -1282,9 +1282,9 @@ function ObjectBuilderGui::addWaterObjectFields(%this) %this.addField("waveSpeed[2]", "TypeFloat", "Wave Speed", "1"); %this.addField("overallWaveMagnitude", "TypeFloat", "Overall Wave Magnitude", "1.0"); - %this.addField("RippleTexAsset", "TypeImageAssetPtrRefactor", "Ripple Texture", "Core_Rendering:ripple_image" ); - %this.addField("DepthGradientTexAsset", "TypeImageAssetPtrRefactor", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_image" ); - %this.addField("FoamTexAsset", "TypeImageAssetPtrRefactor", "Foam Texture", "Core_Rendering:foam_image" ); + %this.addField("RippleTexAsset", "TypeImageAssetPtr", "Ripple Texture", "Core_Rendering:ripple_image" ); + %this.addField("DepthGradientTexAsset", "TypeImageAssetPtr", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_image" ); + %this.addField("FoamTexAsset", "TypeImageAssetPtr", "Foam Texture", "Core_Rendering:foam_image" ); } function ObjectBuilderGui::buildWaterBlock(%this) From 4d146107531d8b5a8a87482e1746d6096393d6cf Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 09:22:22 +0000 Subject: [PATCH 37/47] Update materialEditor.ed.tscript cleanup materialEditor script --- .../materialEditor/scripts/materialEditor.ed.tscript | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript index a9b958d47..ba638b509 100644 --- a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript +++ b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript @@ -864,7 +864,7 @@ function MaterialEditorGui::convertMaterialTextureField(%this, %material, %mapNa for(%index = 0; %index < 4; %index++) { %mapFile = %material.call("get" @ %mapName, %index); - if(%mapFile !$= "" && !isFile(%mapFile)) + if(%mapFile !$= "") { if(isFile(%mapFile)) { @@ -874,9 +874,10 @@ function MaterialEditorGui::convertMaterialTextureField(%this, %material, %mapNa } else { - %assetPtr = %material.call("get" @ %mapName @ "Asset", %index); - if(%assetPtr.isNamedTarget()) + %firstChar = getSubStr( %mapFile, 0, 1 ); + if(%firstChar $= "#" || %firstChar $= "$" ) // we are a named target { + %assetPtr = %material.call("get" @ %mapName @ "Asset", %index); MaterialEditorGui.currentMaterial.call("set" @ %mapName, %assetPtr, %index); } } @@ -1099,7 +1100,6 @@ function MaterialEditorGui::guiSync( %this, %material ) //Diffuse %diffuseMap = (%material).getDiffuseMap(%layer); %diffuseMapText = %diffuseMap !$= "" && %diffuseMap !$=$MaterialEditor::emptyMaterialImage ? (%material).getDiffuseMapAsset(%layer) : "None"; - MaterialEditorPropertiesWindow-->diffuseMapNameText.setText( %diffuseMapText ); MaterialEditorPropertiesWindow-->diffuseMapDisplayBitmap.setBitmap( getAssetPreviewImage(%diffuseMapText) ); From fc30d178af989c2210e63dbe8cf9833fb03ea8d8 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 18:33:37 +0000 Subject: [PATCH 38/47] fix asset refresh on materialAssets --- Engine/source/T3D/assets/ImageAsset.cpp | 5 ++- Engine/source/T3D/assets/ImageAsset.h | 1 + Engine/source/T3D/assets/MaterialAsset.cpp | 38 ++++++---------------- 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 6ee7d1d96..a6ce52446 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -334,7 +334,6 @@ void ImageAsset::onAssetRefresh(void) // Call parent. Parent::onAssetRefresh(); - //mLoadedState = NotLoaded; } //------------------------------------------------------------------------------ @@ -577,7 +576,7 @@ void ImageAsset::onTamlPreWrite(void) return; // Ensure the image-file is collapsed. - mImageFile = getOwned() ? collapseAssetFilePath(mImageFile) : mImageFile; + mImageFile = collapseAssetFilePath(mImageFile); } void ImageAsset::onTamlPostWrite(void) @@ -589,7 +588,7 @@ void ImageAsset::onTamlPostWrite(void) return; // Ensure the image-file is expanded. - mImageFile = getOwned() ? expandAssetFilePath(mImageFile) : mImageFile; + mImageFile = expandAssetFilePath(mImageFile); } const char* ImageAsset::getImageInfo() diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 20234ea03..90cc318f3 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -165,6 +165,7 @@ public: void setImageFile(StringTableEntry pImageFile); inline StringTableEntry getImageFile(void) const { return mImageFile; }; + inline StringTableEntry getRelativeImageFile(void) const { return collapseAssetFilePath(mImageFile); }; void setGenMips(const bool pGenMips); inline bool getGenMips(void) const { return mUseMips; }; diff --git a/Engine/source/T3D/assets/MaterialAsset.cpp b/Engine/source/T3D/assets/MaterialAsset.cpp index 43b876dc1..9bb30145d 100644 --- a/Engine/source/T3D/assets/MaterialAsset.cpp +++ b/Engine/source/T3D/assets/MaterialAsset.cpp @@ -211,39 +211,21 @@ void MaterialAsset::initializeAsset() void MaterialAsset::onAssetRefresh() { - mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath; - - if (mMatDefinitionName == StringTable->EmptyString()) - { - mLoadedState = Failed; + // Ignore if not yet added to the sim. + if (!isProperlyAdded()) return; - } - if (Con::isScriptFile(mScriptPath)) + // Call parent. + Parent::onAssetRefresh(); + + if (mMaterialDefinition) { - //Since we're refreshing, we can assume that the file we're executing WILL have an existing definition. - //But that definition, whatever it is, is the 'correct' one, so we enable the Replace Existing behavior - //when the engine encounters a named object conflict. - String redefineBehaviorPrev = Con::getVariable("$Con::redefineBehavior"); - Con::setVariable("$Con::redefineBehavior", "replaceExisting"); - - if (Con::executeFile(mScriptPath, false, false)) - mLoadedState = ScriptLoaded; - else - mLoadedState = Failed; - - //And now that we've executed, switch back to the prior behavior - Con::setVariable("$Con::redefineBehavior", redefineBehaviorPrev.c_str()); + mMaterialDefinition->flush(); + mMaterialDefinition->reload(); } - - load(); - AssetManager::typeAssetDependsOnHash::Iterator assetDependenciesItr = mpOwningAssetManager->getDependedOnAssets()->find(mpAssetDefinition->mAssetId); - // Iterate all dependencies. - while (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end() && assetDependenciesItr->key == mpAssetDefinition->mAssetId) + else { - StringTableEntry assetId = assetDependenciesItr->value; - AssetBase* dependent = AssetDatabase.acquireAsset(assetId); - dependent->refreshAsset(); + load(); } } From db8c565416270eee48b2054442d5664d70d5c5d8 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 27 Mar 2025 19:34:11 +0000 Subject: [PATCH 39/47] ID10T issue we dont want both fileChanged and resourcechanged.... causes issues --- Engine/source/T3D/assets/ImageAsset.cpp | 13 ------------- Engine/source/T3D/assets/ImageAsset.h | 1 - 2 files changed, 14 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index a6ce52446..6829e82bd 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -363,10 +363,6 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) if (pImageFile == mImageFile) return; - // if we previously loaded, remove the listener for the file. - if (mLoadedState == Ok) - Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); - if (String(pImageFile).startsWith("#") || String(pImageFile).startsWith("$")) { mImageFile = StringTable->insert(pImageFile); @@ -420,7 +416,6 @@ U32 ImageAsset::load() } else { - Torque::FS::AddChangeNotification(mImageFile, this, &ImageAsset::_onFileChanged); mLoadedState = Ok; } @@ -551,14 +546,6 @@ ImageAsset::ImageTypes ImageAsset::getImageTypeFromName(StringTableEntry name) return (ImageTypes)ret; } -void ImageAsset::_onFileChanged(const Torque::Path& path) -{ - if (path != Torque::Path(mImageFile)) - return; - - refreshAsset(); -} - void ImageAsset::_onResourceChanged(const Torque::Path& path) { if (path != Torque::Path(mImageFile)) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 90cc318f3..e372419a2 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -206,7 +206,6 @@ protected: // Asset Base callback void initializeAsset(void) override; void onAssetRefresh(void) override; - void _onFileChanged(const Torque::Path& path); /// Taml callbacks. void onTamlPreWrite(void) override; From bfe2401ebb9821a62e33e2d475dd121f79300232 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 28 Mar 2025 11:14:21 +0000 Subject: [PATCH 40/47] get image metadata adds ability to get image metadata without loading the texture since we are using the getOwned parameter correctly now new assets must have the full path to the image file when being created when the asset becomes owned again the image file path will be updated. --- Engine/source/T3D/assets/ImageAsset.cpp | 122 +++++++++++++++++- Engine/source/T3D/assets/ImageAsset.h | 26 ++-- Engine/source/T3D/assets/assetImporter.cpp | 2 +- .../source/gfx/bitmap/loaders/bitmapSTB.cpp | 2 + .../scripts/assetTypes/image.tscript | 10 +- 5 files changed, 139 insertions(+), 23 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 6829e82bd..f55cae0d9 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -49,6 +49,18 @@ #include "T3D/assets/assetImporter.h" #include "gfx/gfxDrawUtil.h" +#include "gfx/bitmap/ddsFile.h" +#ifdef __clang__ +#define STBIWDEF static inline +#endif +#pragma warning( push ) +#pragma warning( disable : 4505 ) // unreferenced function removed. +#ifndef STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include "stb_image.h" +#endif +#pragma warning(pop) //----------------------------------------------------------------------------- @@ -133,14 +145,17 @@ const String ImageAsset::mErrCodeStrings[] = //----------------------------------------------------------------------------- ImageAsset::ImageAsset() : - mImageFile(StringTable->EmptyString()), - mUseMips(true), - mIsHDRImage(false), - mImageType(Albedo), - mTextureHandle(NULL), - mIsNamedTarget(false) + mImageFile(StringTable->EmptyString()), + mUseMips(true), + mIsHDRImage(false), + mImageType(Albedo), + mTextureHandle(NULL), + mIsNamedTarget(false), + mImageWidth(-1), + mImageHeight(-1), + mImageChannels(-1) { - mLoadedState = AssetErrCode::NotLoaded; + mLoadedState = AssetErrCode::NotLoaded; } //----------------------------------------------------------------------------- @@ -373,6 +388,43 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) mImageFile = getOwned() ? expandAssetFilePath(pImageFile) : StringTable->insert(pImageFile); + if (Torque::FS::IsFile(mImageFile)) + { + if (dStrEndsWith(mImageFile, ".dds")) + { + DDSFile* tempFile = new DDSFile(); + FileStream* ddsFs; + if ((ddsFs = FileStream::createAndOpen(mImageFile, Torque::FS::File::Read)) == NULL) + { + Con::errorf("ImageAsset::setImageFile Failed to open ddsfile: %s", mImageFile); + } + + if (!tempFile->readHeader(*ddsFs)) + { + Con::errorf("ImageAsset::setImageFile Failed to read header of ddsfile: %s", mImageFile); + } + else + { + mImageWidth = tempFile->mWidth; + mImageHeight = tempFile->mHeight; + } + + ddsFs->close(); + delete tempFile; + } + else + { + if (!stbi_info(mImageFile, &mImageWidth, &mImageHeight, &mImageChannels)) + { + StringTableEntry stbErr = stbi_failure_reason(); + if (stbErr == StringTable->EmptyString()) + stbErr = "ImageAsset::Unkown Error!"; + + Con::errorf("ImageAsset::setImageFile STB Get file info failed: %s", stbErr); + } + } + } + refreshAsset(); } @@ -578,6 +630,62 @@ void ImageAsset::onTamlPostWrite(void) mImageFile = expandAssetFilePath(mImageFile); } +void ImageAsset::onTamlCustomWrite(TamlCustomNodes& customNodes) +{ + // Debug Profiling. + PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite); + + // Call parent. + Parent::onTamlCustomWrite(customNodes); + + TamlCustomNode* pImageMetaData = customNodes.addNode(StringTable->insert("ImageMetadata")); + TamlCustomNode* pImageInfoNode = pImageMetaData->addNode(StringTable->insert("ImageInfo")); + + pImageInfoNode->addField(StringTable->insert("ImageWidth"), mImageWidth); + pImageInfoNode->addField(StringTable->insert("ImageHeight"), mImageHeight); + +} + +void ImageAsset::onTamlCustomRead(const TamlCustomNodes& customNodes) +{ + // Debug Profiling. + PROFILE_SCOPE(ImageAsset_OnTamlCustomRead); + + // Call parent. + Parent::onTamlCustomRead(customNodes); + + const TamlCustomNode* pImageMetaDataNode = customNodes.findNode(StringTable->insert("ImageMetadata")); + + if (pImageMetaDataNode != NULL) + { + const TamlCustomNode* pImageInfoNode = pImageMetaDataNode->findNode(StringTable->insert("ImageInfo")); + // Fetch fields. + const TamlCustomFieldVector& fields = pImageInfoNode->getFields(); + // Iterate property fields. + for (TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr) + { + // Fetch field. + const TamlCustomField* pField = *fieldItr; + // Fetch field name. + StringTableEntry fieldName = pField->getFieldName(); + if (fieldName == StringTable->insert("ImageWidth")) + { + pField->getFieldValue(mImageWidth); + } + else if (fieldName == StringTable->insert("ImageHeight")) + { + pField->getFieldValue(mImageHeight); + } + else + { + // Unknown name so warn. + Con::warnf("ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName); + continue; + } + } + } +} + const char* ImageAsset::getImageInfo() { if (isAssetValid()) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index e372419a2..12538064b 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -25,36 +25,36 @@ #ifndef _ASSET_BASE_H_ #include "assets/assetBase.h" #endif - #ifndef _ASSET_DEFINITION_H_ #include "assets/assetDefinition.h" #endif - #ifndef _STRINGUNIT_H_ #include "string/stringUnit.h" #endif - #ifndef _ASSET_FIELD_TYPES_H_ #include "assets/assetFieldTypes.h" #endif #ifndef _ASSET_PTR_H_ #include "assets/assetPtr.h" #endif - +#ifndef _GBITMAP_H_ #include "gfx/bitmap/gBitmap.h" +#endif +#ifndef _GFXTEXTUREHANDLE_H_ #include "gfx/gfxTextureHandle.h" - +#endif +#ifndef _NETCONNECTION_H_ #include "sim/netConnection.h" - -#include -#include "assetMacroHelpers.h" - +#endif +#ifndef _GFXDEVICE_H_ #include "gfx/gfxDevice.h" - +#endif #ifndef _MATTEXTURETARGET_H_ #include "materials/matTextureTarget.h" #endif +#include "assetMacroHelpers.h" + //----------------------------------------------------------------------------- class ImageAsset : public AssetBase { @@ -139,6 +139,10 @@ private: ImageTypes mImageType; HashMap mResourceMap; bool mIsNamedTarget; + S32 mImageWidth; + S32 mImageHeight; + S32 mImageChannels; + void generateTexture(void); public: ImageAsset(); @@ -210,6 +214,8 @@ protected: /// Taml callbacks. void onTamlPreWrite(void) override; void onTamlPostWrite(void) override; + void onTamlCustomWrite(TamlCustomNodes& customNodes) override; + void onTamlCustomRead(const TamlCustomNodes& customNodes) override; protected: // Texture file diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 8d688853e..8fbdc85f9 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2824,7 +2824,7 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str()); - String imageFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension(); + String imageFileName = assetItem->filePath.getFullPath(); String assetPath = targetPath + "/" + imageFileName; String tamlPath = targetPath + "/" + assetName + ".asset.taml"; String originalPath = assetItem->filePath.getFullPath().c_str(); diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index 7a763cd27..710977acd 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -37,9 +37,11 @@ #pragma warning( push ) #pragma warning( disable : 4505 ) // unreferenced function removed. +#ifndef STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_STATIC #include "stb_image.h" +#endif #define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_STATIC diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index 2263d0227..ca1123e12 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -147,7 +147,7 @@ function AssetBrowser::importImageAsset(%this, %assetItem) { assetName = %assetName; versionId = 1; - imageFile = fileName(%filePath); + imageFile = makeFullPath(%filePath); imageType = %assetItem.imageType; }; @@ -238,13 +238,13 @@ function AssetBrowser::generateImageAssetPreviewImage(%this, %previewButton, %fo { assetName = %previewAssetName; versionId = 1; - imageFile = fileName(%previewFilePath); + imageFile = makeFullPath(%previewFilePath); }; - + %previewAssetName = "ToolsModule:" @ %previewAssetName; %previewImgAssetPath = %previewPath @ %previewAsset.assetName @ ".asset.taml"; + %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); - %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); %success = AssetDatabase.addDeclaredAsset(%toolsModuleDef, %previewImgAssetPath); @@ -252,8 +252,8 @@ function AssetBrowser::generateImageAssetPreviewImage(%this, %previewButton, %fo if(!%success) { return false; //failed to register the preview image for some reason? + } } - } %previewButton.bitmapAsset = %previewAssetName; return true; From 9cf17ae9a07deb92a98eb3efad2856846c4a678c Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 28 Mar 2025 12:41:42 +0000 Subject: [PATCH 41/47] Update assetBrowser.tscript remove spam from debug echos --- .../game/tools/assetBrowser/scripts/assetBrowser.tscript | 2 -- 1 file changed, 2 deletions(-) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index b820a3e22..9e4421edd 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -2772,7 +2772,6 @@ function AssetBrowser::importLooseFiles(%this) function getAssetPreviewImage(%asset) { - echo(%asset); if(isFile(%asset)) { %aq = new AssetQuery(); @@ -2794,7 +2793,6 @@ function getAssetPreviewImage(%asset) %moduleName = AssetDatabase.getAssetModule(%asset).ModuleId; %assetName = AssetDatabase.getAssetName(%asset); %previewAssetName = "ToolsModule:" @ %moduleName @ "_" @ %assetName @ "_PreviewImage"; - echo(%previewAssetName); if(AssetDatabase.isDeclaredAsset(%previewAssetName)) { %previewDef = AssetDatabase.acquireAsset(%previewAssetName); From 435462c738f839c9f131dc4280559d6b2849fd13 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 28 Mar 2025 13:00:25 +0000 Subject: [PATCH 42/47] fix the other previewss --- .../scripts/assetTypes/image.tscript | 6 ------ .../scripts/assetTypes/material.tscript | 10 +++++----- .../scripts/assetTypes/shape.tscript | 10 +++++----- .../assetTypes/terrainMaterial.tscript | 6 +++--- ...3140-11ed-aae8-c0cb519281fc_Irradiance.dds | Bin 262276 -> 262276 bytes ...-3140-11ed-aae8-c0cb519281fc_Prefilter.dds | Bin 262276 -> 262276 bytes 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index ca1123e12..b92b65182 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -151,12 +151,6 @@ function AssetBrowser::importImageAsset(%this, %assetItem) imageType = %assetItem.imageType; }; - //No point in indicating the original path data if it was imported in-place - if(!startsWith(makeFullPath(%filePath), getMainDotCsDir())) - { - %newAsset.originalFilePath = %filePath; - } - %assetImportSuccessful = TAMLWrite(%newAsset, %assetPath @ "/" @ %assetName @ ".asset.taml"); //and copy the file into the relevent directory diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript index 42a2f05f2..0846beaa4 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript @@ -515,25 +515,25 @@ function AssetBrowser::generateMaterialAssetPreviewImage(%this, %previewButton, { assetName = %previewAssetName; versionId = 1; - imageFile = fileName(%previewFilePath); + imageFile = makeFullPath(%previewFilePath); }; %previewImgAssetPath = %previewPath @ %previewAsset.assetName @ ".asset.taml"; - %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); + %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); - + %success = AssetDatabase.addDeclaredAsset(%toolsModuleDef, %previewImgAssetPath); if(!%success) { return false; //failed to register the preview image for some reason? + } } - } %previewButton.bitmapAsset = "ToolsModule:" @ %previewAssetName; return true; - } + } } else { diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript index 7ca8a3efe..c333903a2 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript @@ -348,20 +348,20 @@ function AssetBrowser::generateShapeAssetPreviewImage(%this, %previewButton, %fo { assetName = %previewAssetName; versionId = 1; - imageFile = fileName(%previewFilePath); + imageFile = makeFullPath(%previewFilePath); }; %previewImgAssetPath = %previewPath @ %previewAsset.assetName @ ".asset.taml"; - %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); + %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); - + %success = AssetDatabase.addDeclaredAsset(%toolsModuleDef, %previewImgAssetPath); - + if(!%success) { return false; //failed to register the preview image for some reason? - } + } } %previewButton.bitmapAsset = "ToolsModule:" @ %previewAssetName; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript index e67a8274a..2d5d096a1 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript @@ -185,14 +185,14 @@ function AssetBrowser::generateTerrainMaterialAssetPreviewImage(%this, %previewB { assetName = %previewAssetName; versionId = 1; - imageFile = fileName(%previewFilePath); + imageFile = makeFullPath(%previewFilePath); }; %previewImgAssetPath = %previewPath @ %previewAsset.assetName @ ".asset.taml"; - %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); + %assetImportSuccessful = TAMLWrite(%previewAsset, %previewImgAssetPath); %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); - + %success = AssetDatabase.addDeclaredAsset(%toolsModuleDef, %previewImgAssetPath); if(!%success) diff --git a/Templates/BaseGame/game/tools/levels/DefaultEditorLevel/probes/289ad401-3140-11ed-aae8-c0cb519281fc_Irradiance.dds b/Templates/BaseGame/game/tools/levels/DefaultEditorLevel/probes/289ad401-3140-11ed-aae8-c0cb519281fc_Irradiance.dds index 73e2e246e7b759cfe1f518e8f53d3687b6b30490..095d2ec14cc3fa389c93a08129242858e8b4f413 100644 GIT binary patch literal 262276 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ⅅ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 literal 262276 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%0DKHIr!vvU| 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%0Ank*6R)ZXj|1+L`?w#NqPi4<$d1 zLIpksXxlgNN1T7UPyvAFX`_KE`eodf`q?FGzdg zs@BHdN1W4|X*>8_+K-3XwSGW*uU5t0Pe^$vtbU-}%H?n*tMir1ptSGh{Qo1i-b?*0 z_4_HMqCKAvDpBQaekaFwlcFiTX@7wB?gp;Gy6Xb2j^R3`sPY!=kCarU7bt&sR4HrA z!zHDbGL!4~m3GQ%@OgFx`@y{GV&yB)uO3&PW4z`5LE4Km)C%f{TtE09IaqGXL1pLn zYA57jzB6Lm2hX|Y+IHf2SF&p`dLZK7>{1zj#WTu%7+mbB?Ky}X^p8u5n~5Ck@>cXN zM-JXfD46gTaxg6^f6@r#U|1eCPfuG8vi6Ni`Y8Rd#<=L6(CDmxdOc<^a;ZmI(diGp znBEPXt$XyApztHq0K3Qb4X^26+V-Nf6JFFm*1UW!*M}ndV(kycFA3=q`-faHyHV(c zE3_Y?7sP(@miCtR8Thr1!)LU~ykM|)pvK5tRdmAzM}r2n2dWDHNV;k6mqa0Jd9PCjd9QJ zT&V`Y>du?$Ti{}6S?6}p?OJT_8)vx+yWT+#D!KQ$QW*aP&rJ6P@B>d%&lkwSn7HC` zOOS&z-p1Z-$ia|=QVC;_gEdKkq?yRU+&o3|j6n{BAL%R2;ZV~@>qo&q^)C8H;8%JB zeI9sJFU!nD?)6l?CpceE&|8CJ*f-PxrM)QZ1V8Qi`bn)ASW({_TOYFak*WF$?Qg~} zuRdRU2zuC!+ytdw_yc?4OWJZDA^Z!+Xv=lt3$3NSPMpyiX==C)Rs0{(ITQ4+S?VY4*Hdr4&>;(SA=!vd4WkR((s_ z(-cK%0!~q0P#XOMrz@(`l=eKutF!{8JZx5Ur4MbX7rs_rwe3i0j|%^UuvetLSp7e8 zP(ba>_)9;+F}0Wa4CDQrbDbIi>pJgph4FJ%a_#~1xYj!JGycn5rCn3OhVHYj5{!RA z&uaIN;K!a0o;%3F+_+HON65iX-mc!`$ibw9vI$F(gM&#mlGY&yoAZ>-vj{oJm%dE@ zM#GLuAB)A$dZc&51AyJ8H_{h^pXo2@?}A(ObiFV5zMf+5A1CNJ^#-&D=nvT8dP(yv91Q~x}A9MqSowyx5srFZ&XS`j`jcOUNiSu`L5V*xz+j$f$>Dum0 zW&F3e%DNVTo!sBKG8q4K&p!8G;BilHPfo`FgSe`3`@x*?qrG1t2k$4;N;rTVe3jH8 z=^%3Od7dVDwj&4m(^u%lOxsc!3KFq65QO?ko>wvTaq@8wNsb<@Ma{b>Do3ASwe=+~(G5%sc z%lSTrU7Z;B5y~IAUI7Plw<_Qu<=0%5!6C8s+sdE0YS131JfqYHh5l#(u2KpqoxwdZ zeIwT)DF@PD=~IvLOZIVS|4gu#S`1GWCI`&ctcP97k2gzN88x?&_F+}6{lSpFJ*2}+Kr{yjR?IU{m#kQ3wN34PJN>G zBPjjPa$lLLUSg*GpY%YMKS)(aD@St)|4)`5K&}H~|2LEC!j2yUN;_ZLd1Ad6^M7(o z-@l_|&GR9wHdVRak7z>$us7bo@?bBb2j#%NSR*fkgJW_be<#-osb6+8%ZKniVUNxR zHTq8){>$_!?EJ82()(lK@jrSS;SqFvq1RyNFZK-?`Uvnty|~^T zoUg~*cEY=QcH6JiU%zkr6Xg0J_7580tAW)~04%5P(&9m>7o@!)_Yu;+@Pa;0`wn?1 zul|5#PW(hY!%8gdft|KJkT2#Jii_z1xj&bFpl|T&EXai(i|y;>czmc7x9vD-_ep&| z8oe*{yqx#Fl{@yhcfI1ni735Q*F+A!Nf@7y8#$?IU^_{T*1Xi~g%kR-D7)(0xt`kFPxU~SA6WVWzEEn|{+z>#rHthJ(ry#>{~NSt zvTJV+j#aWNbwN4*<-G5zWQ})6ypRz-e}kxE2z(Q7U>KBg(Fb{XiMCunq#Q_l^MI0R z`yZrVNv>NmzEM{FnkRZ1Z+aK+@dDZ+&U6R-Rb7CFa5&03uc__8Db7;PHQ;Z~3C?Vc zdmmSJS4Yt6p62=){K8$sJsmmd>M7{yiX7yR+v}-@93*&G#HAnyW8<^O*F_GVBrHiN zjU04KzL``8Ie0zqjXVM5ph)@#JjD22(`V}!!ROP55ji9tq<6IUk6-DpV&Olv7q=5{ z=udlvp5OK>&Cs2CGum=}ko$-BL@|S0Z;W)MfH%q&OaI?4c4LG1e2r2>=?Y3aa3ay*S7{F?+FTtJ zdR~mD9Dh0PuM>qbx!z8>W@CGz&OzFpi85z`Qf{O^n4vh8W?Yy1PU%*1M)QPoD+X?h;gs!{KbwdEOnN%<4aE0`_6dAeUdA; zYba>AKX5(E`2Xqd?A`#r?J+%*k%MsDMNdoQAmH5}XCepd<4eT%Kn_w8KTfEG9L!0M zOKyoAOv?LQ-iF9QvGh&)U5$B`K2N^{N`KN5y{o-{{9bROFXH+cy)r8}`(r&|+X-v+ zB6?Ta^K`G?3Vb&fcNob2p%QKBUy^ixf9mUV&rrlW0rB>tpW!&XO^&2#6 zmY?N$u(-Next~kKh2K-If^uJwUG1f8qy0-P9w7C=A^br?56Jz%5+#q)p0=2;VxK40 zb7A)nz`I)!l=}Zo=DnEjZ5ekz*cxw?&&Dgc3{c8NXR;D9XiGam{@+|BPI-;%8yVeR z;2EW|y+4t18m~@MKIeLA^$?nfcnsdc2>8@Ktoa}N(8>5G;3aq&e9if{IvkXF2gO}m zoh2Fn)h^RD6Rhn%P6h(@ooAx^6gV3{;wI#vPTU<&FXW)U_eNYzf#i(j5y-*Lyhh#u$U%wpt&E(AJ1*3(g3^y5_6=KT--_9b7h-Xz12H>cgI?11 zCx|#?JH9uW^`Q|sTz{-p2W33+b)woPZMmP6_Cjl-s*UM~21HX{0xPQzu;j5PV|HP> zx}Ony8YdS1`SY};UrxpYzf~G33%M@*g5$xbdLYaHC-?W`V|M+}m>nqXzD}`mmGiz8 z<6oNpc}@8;S1C}mg**s32!LH;_QC+9Q^=9rKT5kp_@4)IUG5XItG$)&w56X*#v6tF zSLJ<&sy-rL?C;d3>KEX*>I5_d7_I+J zB;aWrsuR1?4B9PY{>DyfUiA&$w*|YRI$&-5>tf&ZvU(FwZI)f=1XE-CLupsZ`~Ych z$@tLanE&>$Qbrk-OV|Th{$Qa8I?$GSU{q}X-#<2fZ(#>meBJ@8P3Zg9M2E$Aw~UQ{ zOR`G-DF^a<-DCEnlqa#@Y|QVZT_E+*k4iJ;eXhTtj$j%Wzzgu-TW&AVn z9>z2Nhdtdr+0X-H;)>aR#M$1$-gl6Ll!S%xSCNCa5?zTCkpp+igyfURfs*f?yho6O zwDeuf;4FXAx1iiV=1d>J&OgguTnpaNv;2!E^p~;dv*M70K)F81{e$!`4T;%}!tY#` z?+N`U;%V*GWVID2=Y#O4`DvF`zf$so2K#D}uOa&_NuA5c2tQ#~p1@zk2{+P~{(-aT z-$}IPzCf#q~B<6EWUVL?PJH8rTOI?D%0Mf|^F3YNqddta?7~%c z-k*7sN?hClL?H3w|bykV%(jJiZU>o#+ zSpVfZAje;>2f{uS>%m(@35EWU{v>H{E=78U-jQ-B_lYw9K;|(<)C*V;Pvu|q3wu__ zYPBIdWAYo+chC^%W#?|S3fP8S!Q0>#XC3D;Q061fa20TkWc<_ID_su8|GK-rdoI|{ zljv!V9Q@&V-;>VxOaIYV-VWY_$brm1S)W)v@c?pAKIMnxLdnd(d^hsu&5Iv0eLtCI z!jG_ynJe}Uv+R9?$Xh)~Tl$%A=`C!(lJqBtedH)Um+QldSX_FJo)w20gI9bG?}ioNcny?xq4dN29E%rSP+n1{@wxQhZcs`p zJ!s2yTKb2iJumG#x$l$qzgQ2lFA zd6(;Qy^_x@^9|%a=yf$oZOMDe^DRJ7=3U$ z@y*2R$U)N-CFK?5pkcn}^HoL;N~a&j(ii*3^>_rI?i-}Nm_5B0mi<#Z;i_KO_9w`= zgUC}6>%%&|sQwl>m2A4zyqCzcngafNJ!qu9VB1I4)ZekFp5|}L_*-G3u0Q7z`9oRx zBQM}(6Y<*rwhOcJLqxncYk!z!7tX~y^BUj(r(Kw}9%T6i#lBD2`*NNOy)WcI%7ff5 z2z?>;57KWW{mB!F7Qf1MX@3a2bTDlh$CmOc{e~jG{5H?ErhYZxLBwzL0fv4V>nA$+H$Y zFyqc)DWcE4bK{(hzZt*5`#g5RzyvMfZRFrV;@HF|$U(1^Vkv!*gYNkX=j(wS80p9K zoO;&&@t!934Ow|=(q5GQMVX)Sjoy$ zSo}oh=how`%W=IT-jY;M>dQ3s6FYxg=8?(x@iXL!eoQ~#BaXicl>IH@dGFAc@#3d` zqO5(qj1x#b-V^D1k?+g-E%kw%_w8c-0=ZsDJ5t(}((fqkfepl&h5nIxK<-~KPCeOf1vXZG83^oofTOjumi|5 zP#O1LtO9RlIpThX@n7p{>^TqCj=SyYi5#SPcf@JPLG$>FUL84@ zkx(JwL*yViX?0>={K=D2%BCzu4#ww;=6er0Fw;L{$0zoW+sH6_8i$TcpG<^6*a?Ge z|KcBdXI{#BlSP$m%esVqN$o`-MZJCFMuiV}@ms7td(#!qT&#<_& z`~>&tSDDu-{e?1qd{b#|=l{vL(LN=j4CnhoFaL8r5dLCezY9A~=x^aC5OzV2m_JzV z|K)hgeZW(HVU|Bpt^?9vDE-jVZ!GMAq5SXFSp2{d%WswW>q5T?KY{Rzi2Q=ieNUZ3MjG)G=P9)j*dw-2-0y7eJV(2TYZE&L=DRDu>uoTvd!FkdxW^rG z4@C|td+xb4#{ZC~8?^KvieQ!+L^O;4pYv9f${k`R-h+hQW%?th}>vc!`$L zzUu5v<_Y$k>lB$M_{Cy&L3#HsS3KkYqq`ZIsqAk&E>9igK<*R9#ihnAM-IAqpTxb6 z9DKy-C430PmwMarrPfKmBsM_~4yANUaim~hylMb z7ObHD!VJ#J&vSz^ekASc|MnBKwe!Sf{;16F*c#g($oSrzSl)=t8<6u@%0bUqys#T~ ze;LM2j=S&&l%*}_zpw*DyzyOTb6s!_R(?xR?ne(2H+Y-&SFt>1>DLr`K@E`A_{n$B)Nb}Qp(s}HHowQ$fUv~u< z{}((X+y}v4L>2oX2Y-4NdrC3>tK%xg?Ez?r4kcc~dsQ(Nmr_U!+#I`m4UHv$CnDbU5 zPim{$hDe~uv#*avf0|c02C1G+yB}VVA)xS^zYaDf3%>?fL;cInw~&5gL(Mw(Rg_aa zcXDyR*tr5ZuSC3l6W3*4msk&`(w6z78)JEaOJn{bxlfe-Jt+qRW9xz(XX!tX*e@1G zmhmQOSIBsQTnD87k?WG&zsk5lk(hle^_|SMV?#xU0sBRU|l4epeZQ* zhP#O(o~E7bTJ6lsxQp`%A}{@S*C5wLa6HyPea2tr9Zm39p7)W1WV{6x8UJH(ZQ?G0 zJH0P^mm&wxCJc(-jT}6axH=(-9IS&_bPjUh$h|zpj~qP7wz3$nZT5%k9V@BfY;$vCpiCzbnj8ApB}?fW{vm*e)Xl9eYk zf;^E|xGwSps(?~2^pE8gNcoWdCFy67al^%&LKATbxek05%Uc)zE8!;;_UkTC+B4D~ zka|G)%fxyp=ZEwgUs6YMqU~v(QB~)UYFFCh$u3$Be(CH^Mk@N!b&w2o^5k5pt_fg% z_X5|i;3jvPyEk$W@|<sN;Z`m?t9}B;6lGS_w)!Oy-kI|NUD2tt+3)bzA0v$owF=&zIvY^}X~5OMNjmmVYGe!1rQ# zsnY(Gc}z0D@lWzzH*jCEew_s6IYt>LZ%8(ou!F>TgaP0jwK9=1@*&AK{tdjX&Qyyq z&c&REv8-4(V{xQq&hqwp@T+qiSBMX}Za8Z)?t5HST&uvB-Mj7c%$MD@-7}GcS3FPL z0mgr~r=#Z~SO;%`h%2eyMR8un|M~cLz2AbNgtPH3?89=2Hxk+-2Y)6FO}c~}Sh=sH zv_TFs^Iyu>3OOi~enZcrKixOT^OYCWVR(G7Ct~^2o7L9#y0%QM$4NcrUo5|R6uaK( zwEL(f@c7}cS5ws1po}9{M~eu*u{h_M2Nd}PIY60TDA!f#H~w46S`TD?`Nf#ONaPcU z_<{5ru8!q@$-F=*2hu)}`#dQR(r%RTLAid&`7i!Q*n!dx*c00i$nywNE@hlc#y#Zv zCjBAOE*AYVgZGsFLU~T@nV6p->by*kvW~|5MSGl$?e)OxTINh<+%{*oEkR)EbZMLSDNuR;y?60iylA+B!rQJ z7I+PYA_v7{c}Pui|DG}kIcSvsQN97l!HenN5Gf)aPCZ6%TGqR&gxqD(3`-R z^n7TmU03}${NmGLTxw4}%Z4zP?V-+HZkTggQqQ^p^){PPr>hZlIt!X3s9zqT?zNNm z*=;>Bz6hKRKcU{=QQje}7b-5N$2e~2j*+e}`mFpSQ1I|JH+R^@U zFdNUN9%>aBQU_CSAqaEb^yn;jU+cnnrG<9F%#uC2HCPYk9e31Ez2V~26W(Oh3pAl0 zdl)YSg4}Pd@lv2__!4!17g1Mwg>{1ey%-KsS2LZ8AC;{0)E#df-eFzvzX~I7Zt5*w zrS9Y+>Vma{+3Qv6R{aVSQBmsrz6=A{*k}`TJ#{y4MR!x@EG|;lYE6B~E7ZmQlHX0D z9_~TvR^5+$K>hSjsmE7%fQe{ zT^8yyh9bXNSNsEm-6JEdoBmyaO!fF zGzZY%DV8&k6DGYS)G_S{GgymgwLm49)%r%m)aknv{=n)=zvYNbp|0^a)YrZj9YKAp zMlda9gw|6>Rn(oBOTFMU>P&BfDQjlb7bp%>n8PYXomo%DAJi#31GCaF>SVTt0WZ!f zO+Df-sB5{A`cg9@cdaqh8S6nmbn{oV>k~Hg`+0s*=QtnC$WQAHF5`O@BTKBofvzxq z&5W9XaxjLSjpn58T$@NO%R>IX32(7FP+#src)ImIb(CF^UeKVxg%X^ z2Vj^SK^?^%)Wds7UAiy~&C{aC0`J27)joQXI%20IUq&^5F6!leZ>5;?sJB_wGK0TS zuO=fJM;*2sFs8Mp{>EQ0kmU@00@F-F)DzqRlhyd>@IW^hvW`$E=KD~07?tKxr)Iri z5({sF0mK#U7D|a+fw8K4Pz`s3iKbzoI?QH4s{(bI&P7&G2f0;nIPWd%@^wUhYtwE< zy~}c7jadCXSqHk5KMqD;_$a9N`w01u^ZypO`47BLJc|Hi=XI^G~o<{w) z-jP?WAn*SyOgDd07p@QWS?luusgXO@MC84G+*5%)AN01S9Gt7N<_g&w*9cjXB2WxvBfqle)sK=${JkRu{GF*R%}vf>&LoF2UwV z1?n{nfS21vox6kZ+HZw73#L8PB`f_gJI zA_c9)Kw+2`A5mXE0j5PS^#zXv5A%7NxjMK#ve^2FI!e!ERJ5i92EjmffO^EUVMf~= zeJ;2kMz9r8J@_N_xE4@H;xY9s7Eq__aHv0wK7*+L(~bH-d8rfEhPrQ!XphdAYZXAB zZiKOBOz@rXRqDUZf;awpMib_VN}cHy(dN`QXrAG>W-{+fWUR5`%$?M+qt1YTZSWV~ z?|c6O<_|nV{z=qBb(GoXA0FHQzF@9I&wOl64vd2dZ3p#hehUrcy_+#kBVj&!DfkP_ zW!k2&XtH2u6vHTdG|5L#w)MHwWUY}2$%K_A%vAF(0v`b(Tb)ni?Q_Vz} z;2ttx9We00Cro|6RPa^vr(hwjFQ7h5TE<%H%V*U$bH(aaNt{G|qrw@pEtUG*FHyHO z2lb4~Wz?e1>;#zJp0hp)Yz(~xBhXF8tsnK(no_@EIpflu`Wzon_k2}w2+U6n;rl;I zJ&#iGr~gR(jr{QNUxeAm7kz^|q6c8;IvY4iy^D_4IO=lFqh3*a=D~Xzr>Hx*j(Q?L zSQi2g>OX#Owden`!)NHFzCZ}R;zjiu&^vmF3 z)!}asP@mxMj2h94)EoGT`obIGN&beqnpK#g7>!h1fUZe}r<`+l-M zG*em6zP3)A5$bTBqApZfzW13mk-ADR(T}2jT~%-s^;#Na{Aq>kaoHF>AG{XM36F0o z&zYb4QwyjAaude2s?<3>Nj=67c;7V{Q><60N4J>Yx2K-hdQkB8e*(&SM|%SgLlVteGWxB1_@WE3T6aMkJVRz;k_}hcj1<>LBTnk_D zbMVRTfye$i+6&+v&qjTd1@MsPpsqs(j6J2PMIqc9#8hr@9>Xzq&~+b>K#muZl}(JEAvEj7C8sfA*w95&un0wg9rZg%p~}#yTec33;yC^@W9uKD%8n%Jria-KCcg7 z@$;dV;4^Pd|F@=2OMrT0L3q~d!`qynx(!|Ix(!V;D{$RMU4{|Vv75#H^I6rYYxGA( zIjcM9(y zqSRe;WcISA@!ZAX9jDqM_pL{L?5@z3 zoxr$FfVX%Oyz1lOp`A|MffK8+h4)`fmWJhEkhv#^9WDa#tM#IaxoPM4I zf9s0Oba;3VaJ>@!UYEKG=cBt>9-v8R~zbf z)UoRxylmIQsFwK$dapnAAmCe$;mgzo6YUDrQ7w}Bgz=g|or7~$Q{>y9dB>X1_*Owa zb5k#&Tjo;wzdO9ubyQ9BS?R*w|whnl@XJ$5rk9q{W? z4A1Uy_?){(M}=;{Z(V~r1fRm=+>N?8Z$`$$Aa;U&9}55NRjMVw&Hp^W>Kf1U`QWvl zpLr8`oXhh*gx`NS|5pXxw?uqPxf4MIF$9w4iw9qo1 zdjovSbK#wKlnK%wr!)7$w|gEw-Z}7WR)fFxD)kCNSo3dL3$YgR!ml|M9^?dg8|T2= zs=|l71U}ZB(Q@!03*On&@Bse--|Pdc1@d+`^Sae8^n2uIc;Sce`K`@PDv;<*Ix?+mLw{Mgs&r(sy7U%_kMC-f)n6nKRnfKjeLlkqM6w-BD@ zTkst(hA;OH^JF5txc8XXZ}Gc_^q1hV{T=?~5g|9$_X?gn1)kX@v=cKt@HtL^r#2<} zr}Yt4>k7d4`8TU@vFJDOzqX_*<@{(Ee$JuM{UEsew3U-2bbh-6xxC5*2TKGrX!b`dz{?XT|uGzzK!w*|48n*6Y z<l7b_?CYXxDD3I59sto9e-Ph8JxcmZC;b>T0l-uB2^9ln4y|EIN* z>UgL5d>Pg1PQs75G<=q7sQ0YJRO|YT>+jjzQC;CKeV#`?*adRiu*dsydOS;^+^3T?tcap&vO>O#}z!^Id~w&^Im{Y zQat|`To>dV{z4SKt82fSr_$zg^*{5XOr=ICB@Gf=ThJwEYMo}5Tk#UQ9+SD7*xQX9D zp!83RbEFsX2g!UOktce9w&byjBl>@ew)p-Jpv->|c~Z6U`%F_`f=NrnfyUc;!_A$4 zszdPi#Nppb!k-g>ZR7>|LFR{V^Oo~2#&09f2Sv2QX(9SS@C&Wd#JSKcekplAyajwx z>0FPH4X%R8Wc3JskUzB{_IdAbv^V&Nr~DtgwaVH`+L8xonO0hxN_!rs%HIX2aVq3( zFc0}#*Lfcqua`Ve(*Gs%W(6+hd%r3jl(nGj9~mE!=ZJ=pM?Ic?ILql;h4+`|C}ciF zDcHE4p&#aWs(7{_5Bt1Ty{qYm=E)b6(vb(*4?-T+@SZYXN#?J%B|F~F^>Un^iw6sm z_4pg_@eHS>1h1atQTtMRP5XqlT19SmpKZIg@g-bnk$ppc#=WXfTML!Hp{w=Ah zJui;f^WqV_BI|h1eR^0Q2Fm=+PWrbnzY%wdo&QV|rwD1gVmwmv+_#Vm!2==qAGU#l zM{X^+P0QjFl;{3sd`_J6UY$$uvSh{OBp-wHlP)8l@(n(haoVjh-UpfIC(m6;o(>r| zJ`&^Uso}gOJj~3CrS`n24(mof*{&;fZ&c_cHzPVRG^0?({g^-vxh?;8_&s-cM?;YMVjHKPK{) zPV-)mV|+IkIoBrg7I((@Yh?bI^dHN7waH|QHR5~nbD8%p^U7qNoaC#K=g`IZ^MUk( zJa^v3{evq?KYZ>P>{0RS`r<$E=ER@-bMkA+%jky}IlW(o=gpSh-98U;Qm+652=~RC z-vJ!Vsevk>;2+dM$sbZI#yjXD>r3#9Nqz{)J1Kbho@KsDJs|V8#5wKc|!e(BM$|y#PVso!p1U@eyGCf$_nU7 zdCvBcXQ4-RcizWLnlHWl;Z)fnGYS$Zvw zb_ue71kaQ_2PNZmlDAXvJc|51$+xhbY@hzLC7*|gtBbg+%+Hj0m@+?4=JCor4w>&G z^8+Ps%Ys;5r5kphvb_IC&Kg9_(9f=P*A)7}Q&wz40ka8gS4LWjN#1rd+G9O94zsOTB&Gq)Nb1X7GE%|U{yj$>EiMaS{s>i;+ z%)gL%1J|5=(3JE)=g;@j4TE zB5zmb*~)Vm^1O!3&zE^xGH$$u1dpC7Hw)r_^e5|1R zJ=bsaLo1Kh(~x!IXk4qfFOY|p37&-d^ut#v@7nn<&0)i7NIxW`&*Wr0>q+b!r93yc zId+~}o{tjz!y;}c@_O2VGM`1RUotOP@{)b7RI&N)Brl272Qm*uj=Ma+DDx9#9^=AT z{+V1~k=xd)JljnsbPn|sHGDuCg$o+FXG7xH|g zj62KsmGUq9MV?QR`A3ouF%FhfVSmVe7xCn2-2ZZn_qHyl&3g0xx1FPy8RP@G>bN%0 z4>>%2+&kz8v0kPzA7*=tct_I@*%DVInDoN}SWGw34?SRw>Oeop^CQmmG5Rt3;UKJ7 ze{mnlzb)hY?PGEM>ao0kng1g5{AGTGoDbq$M^Bz#=4;9P9JwCKd@K>4ufg}^IWTEY zi#&kMTu&n#UC4pd%OW4`IM0`p)A-_C_6S(N7lLVI&uP5B$2|px29ZyF*qsA8@Wq`W zqndq~_f79%`k_qX)r7Y6!}Z*KbN@^~4A63FUFe5m>6>+tH~*#jHY))8PEP&*#C>Ly z$FT{N`OnSZAFV~Z9N7>BKye=W9?vK9!({%r%wv>%cXIug`3KTIlJi8ai*g?P5IdhJ z^N-~@6mbq|EcZRm=!I=}9`XOpR%hckvvBy4b;0Nus2AR99Wt5*YJ_)LPlzkO5P6RJ z-wEM58HK5ry^Q!=n`j+#DHRBFS%=K?!FM9RMz{Iv2mO(0)?9yGDjn{$N|_siM^m9{mp~TxW3=tfjHj`D{pW&m3F2_7ZC5uNxbi4e|7HD!n#ddIbWolHOyZ; z_;q+Nap23r$&u617J*u!7pRajz#qZ0J>RMp{DX=)&7z^uSt^AjM^6Wa6A#`QEfBnb z$7&>X>Y79nGV|e=olWJ9q0w^uzEp;8?eX^y&Wc>IhLRu9Ci1)0*lz|c;#sc~r!7sq zZyRx*Bau|=bAJ~qGcK}DnU8~)cuybs2Xl#Qb~QgI9@ZFtcdqbID%ZG!$BA>j7rh)< zjVJ3Wak?v^cfhlOFNni*vL@m8J)g0Xy7tM$dG@acI8rhE_N}Q$`4at7IaDoD z8o&B|;tn~92fW7b24yUB zbG7vw^{g9Hhqyv$Aa!itiY~!_Ju9;bb>@GdUf^rgPy7J?^j7N1snqkDia+;P{I>`2 zyXMUJj(EizcD=T8)ZyC~IZE82BL4He_;u@3r*02*0=p0w*q`|maaMS`>xV_`x-o00AJc{GiDl6< zRy(5E3&F6wk+vMzO*rbWNB8j$@mkvd#2lWj7NIy~j56Eq(GZk_Nf+UuzwByhD= z4V+5dm_|fJXW{Q`9bSS|?6f+BS7t1Zp5#8FuFdz<-4XS6PFZ<R^pdc4IVYBn#rK_n@ApU$s-~2Fy*--=~t5b zW@!f%OjsTNBhQfA-$a4%LZ(Z2iGJjUq&6vO{xRU1(Jokd%d}cz$g!Mc} zIPHtnmORIm7@yEY{W+VDx=zebB6$O49-FXpFY*5}|4p95k>_e8E@AiDf$zzDIKj_< zne|EJwf?|!yzIH@F3S4zd%}C1U?U$i?d#Mxc#hk8YZ&UVGxRKeY{_3G_**;k`>=Wr z&wuaUmN$tsVWJ~X9^YBS|oe2xvdVVkR*v>g6GH)x5^V>9loD9#y-c_JnhfaAv}lVi`@-N@k8z__$S^4E5**& zNqbQ4o26YP_gm8M^aXs{Gk7j(r+&hDj(hx%s!6ZW$PAsPt_v*txf@xN}1=PW&F1T%fr*G-Tul{Xs%>+57Z&zv?`iC zIF*Wq3!)dzzk}aLidq|jQ;0;YjphuzNCd47`DG)6ACfmV#JnE-k-R1!`8Rno6l*s5 z7G%72C8?LTm!~Qe z?PFb_o}e!}*!qqvgL2VX)Xi&2oNB#QNH0>Vu+L!>*GrTt3a064rAmU6*j`m*mc(8Z`7r~hR>x!|AaOGn_m=t6lDA0uQ)K?DJa0TGE_d8){%1AXpWn#GNX%$rmBDTqNnYAtW;_wg$I%mk zxuNPA*U1aJ$vS4(aoAbJC6mZkm`HuvH>rcVpY={FnVMEyccj;#+)%irBXvt!RJ*1* zQgfGDRjPSuN4h*OF6FnA>yfh+^P+ZYb_yrqe+t$iVphxQkDc;OMggl|;j=|M6nB(} zOKYEozqZ6Nv;@Z*rLbciWri6A169C2h9_WwZy7lQ0kEU- z#4H82Gai~Hz}JkQ%|c*P<6AQ~*uc1K#)Gwu&rKDqW_)Vq1S=Z*&A-TZebLxqJ_0k0 z4dz{NHTiCR!cDE8%(+ys|2e9e8DySVR%zpX^J_l$8H>$tKqH2JV~O21jb-MyTn`w_ zZ44PJ&F^Su7^}_iLCaWY{s6vctT%rGs~Nk@`{1j_aq~~GE&cc$&(+JgV|u~Syk7xu zfssF;gPVGG@9Fa%X5t?f%deg7@2`);Ale&)B%SW`2rQeUWU_t ze>vW*jN9yU$Zs^hGxLJ48duE(u#R!gbb{55&+PsbdCLyk<&2Nb-|6Q}W21Qw3@|P? z!P53P{%!r~FCCm54v^R73{{TIAkS_o85VWP_vuOn_`dYxKr$F#u<{%4m?!vMeq*$a z1&lG~N!kUCu{IVq-Zf9rE@F(cvA8k8JWac#G1)u=>c({Q92n-lSHYK%2O%G|j6Jse zwJ=WG^3cWj#(w^x?B|61PBUDAg5V0HSRftTK|e*nqs*6=!Km3T_+9uVYrnaIOdqE; zn|wxRq_|bZ>=e8ouFn2zNw8=nzg5@lK|XJF@~PRmg%?^bKRXoipuaT61;+6|*BK`< zFK-&F1IxmHTiMO}!EBMq){DXJSk^npUuhDKP${-<=(TVd&E6?E6AiR2dfzx6_>|v$ zhy3gUzcf|^J_J8ArUw>*dyHX$so+MVb6^Cx%xE0w3C=bu2HJs>j4=7wjxwW+l7U*_ zAS1W^UOkLlfiUeijK`)1wlHp*VqVlYF4^5vgcRO zSZm&*U7C3+=4Yxg$L{x9ymzf|FROXrbL4nuv}bTU87R%jXTL;Vv`PM=H=LA_FZyaw z>`WrjI)Q7!Vv&W>&i);Nvf=htE~BHljsH`OPByAWXLCDkr_semx6#$yK|9XqX6^*z zvAYGP82!xMU=d@Kc?2wFOta-96M48qyRz|-{hSTZPj_gyMQ{B9_B6gXpXL2V7{8ky za0+?rLhk1qDS=|(_eK}q=d87Yaa|GaVcqk;7(5tmW}RU_d?4Jx3Yi^)zlB3qZnJ6d zXXK%?|JmTW@Ozfmzb!C1e9{`}&mBAxo?`7Zw*+fMp0}LACZR)-#pIV|gbga<8sRdL zcgb5W4o)W1W=-e}6^N6gkAoVYH;jH`Yzge(IW8DW0&Brfjmd!p;4WiOU=q0Acq1?r zT#Wwe2F@hkz706R2-te;ZKHVL71{%gq(FJFoAI2Tm*3uaWTw(?X8d601M3YGbLPprGXTIT!Q|ADWzxfuM_SI5T3zIx^o+JE^P@I6PFXN+d% zD$r%TVSWUr7`<(|C~Ax}57PD-Q*Av`26^~`c2(p-tUC>jz2?tg8}x%%ueuo5Y`xZ( z`5?}33}O8fagg|gO2@|SBy9z_?D2mK(@FWNbHo66$B=nM2uhm6E%j?i0V5alM{^mQ_U z3ZNf9#ol~9dJg~7D(-*87$2Ai?lk%Z#@o-+E-(mOWYh_C0jC?~03=)6F5loanDptcMLb_mDw8%!Wt}&S4C~ZY~j>9?Tg|B_r#FP~C7K zLm}_Y2**+BdqHr0Xhozv=V;PGfylsUG_W~%A-p|0&TNT?<6d;4{}AhQ4Qsw}oq4?0 zI_5LXcX^J_e102Gaa?8`?X$k1IUc;>D{D>#ANZ=9^S~TNBU>(9#_Q$>v{Q_p=2ozn zG2Gk>`ix2Dr(o1rXnqb>GS-+^z*@#O+rDUoo)B{1+BjqDy-vngF+1X}y>1LN{x-$B zF~U#+LVuny-lG4HS^@v%z)a-g1^<@7yPVg!Z@kZXyxXeBxtk;50ak)JlJhw^IIr?o za3|+nh6LJh&ZAZIXU;q1!C!YfAS%80j#dmPWZIsJ3VUug|1a#hvEWmCuEu}txfWdi z-|V^0Mz(;D&)XPx&7xo<!r|(>Bf8JS70I5SFxTZ7=z5i zpc8%j3HY4R!Q28mj27mHpiVy?3SG9G{w3HI<*h@U^Vl1{7+q-|N8Wqm=j#^wHj++0 z>}~SCJ<$un65*npYubh$_%>23T0Yo?e5PvAB7wuKhts0v&4y&4pO5b4yhnp@GJ3QY z`rs}6u5L2bCs;4@Jo7`Rtu?-6vk&+Gz?a*`9lk>5Alk=#x;YZO;>$26fOmYA%$Z%o-kQAJ_9Xdk$C~E5?eRwArHd7X>Odg&vUh- z9~Jtq3wEXG&tBNeqJIamu9gNz8p*a@H4eK%*jdvIf1oxv*LX3|6l}mbk(1&6*1McX z8W-6gz0diAeUbO0c^UU@kqyx$=5Ee8{mr?uezyIv%4iYjYyZA#pab}Sx99${?f2J= zUu=6$+Huv56Sf@7^<3z8q5sm1dFFMn0CtwJr@XAE2f$~I_V#!`^1W*J+fTk%Y<+y$ z_mVk>&rkXy<`giMaakWaYpv(Kx`b7$so6JpHoTSdBWa-lk$TZ~!R?`2k)r5>%Vdz| z<6PH-(5gt7b57YqW~58Bs@Z}J^dr&2{_%n0tS>{5&m*CURtxO@k3uV~W7sX%5c@I&j>O&;>+g8hH?ba1HzI+C;1GX_;MH&&%ggyM zUnI#YVh-i}SwU-;zbgBIcGi01&A>3ex6r5==mbt?zar#kl#%-XWY1NN?a#`xFZ+$> zHjP!bonF$IZR@?f*x$n5_87fv{rHU0#-1OyS$DhTXS1bOkxM6Q~#(6sZ(7 z0;f37HavQab9}FbA4b<=kDg_miy3Xv@4KuUzI3yD=u0aP?J1${Rxi#~9t{n##?$Y6 zL+@A{e5%;_%dZIVD*H^?G2%bPsi08kC zo)GKE9bW}=I+z`Q?R%gbxfkn3UZcOc3oOaLL#!93G2gZy%3}YDeQ1@~ezOkyO$X!B z6#H51liC_T+3Ra(>`JlT_Qvk=gF~>x%7A747qAbPSm(@5K@-126~^DozGAkyCRjP* zu&!ZOd`o<1xzQxhi|@}c%G>Mv7$ZGUm-ayHQ?Wn!f3@cfm3h&_k=H@3j9#?pMoq#>P5eIohxK&ih{i+xV{WJ?tFc z5B}QVK;K<|LvW1mvA;Pu-Iv2`3%-w@=m@UkJ;d{GM^E$x5Ac42!OOm|E#JRlM+p7! zJnNjWD-&4%#J;2;df^bLu}%oPA!IDI*UNJ3i*D1d#=cni9qO~c5cXpW^g<%o!MJbh z;cn=KQnbHdA8{^Rk@?;s_-D9;wS@h|*WtQWQS+T(8SDdLSCxtsw&roJSm^tSMljGA z9Bvf0{S0!E4yZT@JS7TyVDNk&q`c zlyTn_`ZL^z^TCZnD><+1h*k_@HDKpXV;@uyyMLuWKG-gNDO%LuG4Lqlx8@q3u&$4^ z1~QJ((9c%7Z<}A^ex-cdZ7dDyw0*uEHX1RE_;&k!T(96e;tzv$kdv}tbKjT#ir^B~ zhsL2h)+*y`_J^afCqHNZIL(^x`~RqW>v*fm?(J7nEI>d7q`UT9bFLX{Gj9ax?v(Bl zq)P;m7NjMV6lp||l#rGN5h)RA=@3LZ&i9_o@#yROJiqgt^PYdsU*mJnz4nS3;~wK0 z*SJO!{Kg|S3EP6#&ExlJKd~l~Iobqy*t!!GJoRvoN`#HC$S zC2InB!2tTV7m#1xR1tG(;75J)>%gy;;P+@hTZ#Qv?+w`29%j=mPAiNQoeB-cEe2~_td^>*bcyu`V&oBOK(Kx54 zmxDg{1K^bVRc7{2?ML&O6N7w7 zKQ!O8i(@}Q2cR1EW$SzHgT?G~mR&RWdnUUSR`=Cw+(vNOTI8$Rzmzd|MH6EMhs(!4 z^*_aPx5=;P^1Xf`9-4&R9Epp5jGf0msqg;@_(}ad3}ipmezSArcdHJzQRH-R-YP_X zvfgH$nmnt&`?V@e|Nl8}sNcZZ>OP63_6xbqy=?3Qe^A$d5=-fSNB?>2*js)}>n3r_ zFMds)mq~6rwT$@s}Sp~2~Bik$+TQRZ^Kl5CnhLK+aKhZgI z*{Z^NP~?8FUvwbOTkXzL>(E1J>m^ooq8*%V-WIO^0`Q6je#>ZWIwSA-Gr_L8`ap-|&_8@N`18%4N z{WSLd+TKky2|TB~cb)hr8F9ozRX@aSDv^)qJfuj7&&mFtHGJM*HM>W*@VS4*b1+j_ zOFXwOk~cb-^{mM2!9F-P@wb}kRuk-dk!!&|T0e5aD#yBPWPh;#x{*y*l=URO z$7Z*Inn+%|#+!&AXiGj9^?R`2k0tM`L40@4>*jwzyp!9z?$3+d#!qijKN;Pu+YY#f z(ayT|Z|u(S_)epJ@b_Jz-5uIJ#(UOv{_m*K!}=5ZoAHtL7<8}u-OH~IvM(p~2CB!ATG4s@--~9OAYXdJ>=VQZxxr6<=D0_^ zcm-P$f2Z^9>fmkKUpFB?(>TI=W# zX2=77zLm+D@0C{_$T!lUi{O#J>-aI0@!Y6L(jYGC z6S)`o!L~dP+Ar4O`OtAy$;e)-5Y~#U5BA%Pk;Q?(orE9T=~hrPqSLs}J>Wl8rSHh{ z*U?8+DptbJ5%rw<-bUXsOGT@=pR4so3+p1+X_-;qI)$BURJVS{&NixAM*>?duyc%R z)=}1C=Z0(jdVPGMQPVnxU1c=1PGh$kt*uMg{YEG2ckD%@pY_0btSYk~q;-E&S-JkN zy0=w=$OP*Zen*>5(n&13%Q@yyFFBDt2rIwC5RV(Cm-&~J~D><@N4Yn zoXKX;`ciJB-;>26na^z#$U)KTO z(*C=pc_*l|bqR6#e&#cO-xj?KCw9^QG`b8uh24Ig=os+w<9>PKkx^b_^%ncfUEWXd zx=iFL2UsTu7vF$=6nQ7eYsJrh8^-Yx&kZLoZq4g@kw4YPwu)S^s$y$IezrWKmI+3l!2|p>HI3bODp1koMapF$(6ZvZ` zcda@_KHHdlGcUN%aCfRIWlq3Pj#l@=5f{n12<;U*Bh4IrQHR%u4|d|E~EYs_Rfa z%~U~LXhpkIUregLN1x^(`E@Poi!;0$swVy;8N5YZhtc>=PH>82*w^qo+p$UDAuY#V z;{Ke0mAGy;xLHruBZzz3V7o_d1$lF`$hjbIszN?hoa1jrwp%f5Ui@T!>}$kXnXn1i zXJ5r$H9ijf>=C1%Y| zD7Lp@S?jPpj5up`V2%I9_B0G@4afg!`x;T}JB|-F3R;`7BaI@#`%W}UT6NY*#;w_jp2kVkBC|4?Vl?$p^k zsY2kxAAoCj!|%W7o#Z}yR$r@0Jzd9z%|e{EqnR{_3$Ic)?CwofO{vRfq8?oqoI%&C zd~-z*SLO%5J`;S-kO04VnfP`cYr*Rdg}9B*^T8@tYa2kBtdd3hYH=P!Nyl{af$5-xANv03XE@e+?8k<0ZN-iW{l(PKPb@NOS-)_6OSoVB%>8?Z^^Nd;P8{Cf=_2f~ z{NA`Q4}F_BK|c>Qh!gbl(LUTC2a`86Wjzg?N#{wc@vr@{$0J3e6R}V5zYDP`LVuh& z#8;oy$9c~1-#RX=5Y}6TU-8entmO4Y%?&}_GD?1Nng7%I{1I$w_M@%Xgy7rXV9!NL zlUHfHt3VLf3vTl<`J2w;I!10-wXwC?-%DfVdEW|dRuO-h*v!U$y;(Jkd~aoQFQ`al zF4zCMD#`Qll6#K)dB2s~-J^PvmnSCwS!&dDn^Rn|LPd8S+n`SCgFY2#>i$ZVcprtYpuZc zHcV?Rc9>Df`X2ik_vb$ByfBVf&;5Iz^}#S6z0Cccfb;Rx7;h!Vrsn>C6Pq`(GI$@KhkP5s?Ms_GqKSC!#PkJu##9VYe!{^G!QD@ork!t1<7qp9$7# z9`Ax*D4G)n+b@0syT8-b`_i9iZ*r!31O4=@n|U++JJB{M7%lPZ^7;qvuYPl@C=Bh~ z>LUKCv0ENKOk%s28&&UEQ5e(N)joJX#oXHPaNAoOoxN%e*Jr+STIGp!#-DFj^&_LW zPHWU^_KOA1No5#+n!~tG5#vr^r`(GPauWs`Ul7p7Dk?2iuza zLEm@cABM1BXn!;z+$Uy*al>k(aS$*3K>T=h7!LjT#1yivymlkl%PZ(d40sxS6X#E*`{-VNizmqWZQL&$f@Ph5DKzYDKIcvQMh z_d3^G<3=gG`>L?HHo%i2@S!g7dR?D8h)qeIdlU9KvwnbAp8&_!xMdQv3jXJc%E^5( z865SLY1r4?wrVzfvbVjI==y1!L~RF$tLa_lx;1yEdtdog?cdO4YvvblYPt1d3O%eP z?l|gn-#drgd9gSBbIud@Ao+Y*x4M^<{62%5*4x4QlyexJf{gwsXMjs`{_HmwT2fXHiLoZ}OTok-V^{>R~;EhfqX~w_bMoczM7JlcT7U9)3n@ zp3jtOGkT8Ay;szIE1%Pax{4dESTWq>8PZ$1_)ZvAPlZxxM&C8(v05?w=+vy)64}2}Q z8oq_Li@?(-!3bXNe~k`k;@B+zB>HqIV`Kc4@GO7xW(W49_XWC{ZJedvw|;ButX~A!4*;m}+;FmkVD_W{|d9D_?P1Q1Zpg)4g=eNGF(|K3@M%GE&_4dNYc*&{6=ghOx zJ9WLe{$6x4-}Aos7DNUQ>vedcl)}p zs^5ukySQmoGpiv=WjE3BoMkU{Py6Ss?e=>2h(94()Op>T=5L2j73Yof$3{z{nD@C~ zBbp5*ys!OeG&u@?YyG?MZ+5x|{2kQkNUngFa6H6YpG4{gd3g$WDI58_@GT^+lX&2)`5t)S z6!y>A;DOy$#b_tzq<6;uivF?}V$1#Cqub#hPVnzyGsH&varO=Bhwb6hT%Z%Ei?8{K z*Ex^%t)1YDDb+yYl}heKl`D+zUkq{e8^-V;4>}OWK`X#j&hWb@6F2MpZHS?Q_^Av2 zQ^)TTua`4kLIIJyA@sZ29}i(&$w+FAbgrqb@Tdm6FTsni>6G(^_+7w*QWHOvwek}W zBvrkv#>5FX{mxch6yI**r_!K|xD?&b+D;blQ~b~;Fr|C@Z`ggDVqSlLVzfAj@)SQ$ zGzG6);oqRX*4%wf8V zUJkyujvKW<=pN=JI!@fidTN+It_tIVLq_)?-?C9l?Tq0Y1CMA8O%_bzw{BUslOI_};8UK*3O_@5c=}u0g#K;XSRa23daV12&yrg2*bm&dmEd=; zhxyHeFuplq^tB%GyLBF~akMW(JZ=>E(=OJMzqJbE>*_`-YbM9vG7<#ORUYH_U>|)L!1b;A|wZsQ)jO^?q)aMO5$R9Oc zp>Zj}AGaE9tShWf8y^NZ^W!i-NJm_lh3jEchcvO3!aTZlh@%Y*{lN4{DsZH~>MWW^ zGlR9@v+1eB?`19dyx@8g?+dOg_)a3TNs#AB-L4+{=yvxT@aR(Z%N}vHH3$4CBj^1r ze89*47x>*hZY!0OdWg>JlZNrkJ12q9={#QN?;2m}819$#jC9sK z){?JT;XeDOal!1%@g&9}vjg@{+)lFvHl_JIik~gj4C0zr`2W;VH@NNz?YZO+wf&~{ zF=vlgoVYNJd*6%t5A1>{D`rI}bp}d=uh574IZA)2&;f0OvSKzriIdRX;+61w*sJKA zXyUKq{>kc%VP6_;&vj4wbIFT}xdqhwk!jqwlT<3>sM(&pRPKWed{4bE==fj+wv6#Y zkT*04_k$9VPp#jaAJheKo)pvxHGZXW%B3M*z2E3;-C})}`jf6RB;#{l$L1zK%!?JA zylLcYP)GQXyr411rH;Bbk|#Qd^_egpl)B98;6yt)o(FvS1Xl6^mwNJb);ZuC=zLLl zSx+PNgL?hXAnBALM;o}8$>Wbx-?*(ZN0wMQIR0E@Qh?)~3h(C) zM#}(~*Z8cCe?9?E(|Bx8BNF7#&DmEqPE(n@dj{4I{b&y3x;c<_a^pD9JN4waJ!Wg{ zwYbe@BkUaFbo7OFGih4C_ZPvKQu&%wE%zrmCAEt@|YK$ zZSHpe2zhlu^37rJ6|?I41Uz8JEuk8jm7+P_y5RP=i0cP}|6X9<8=*clKZ({Q4_OM2 z>8yL%FBZ*ANB2HIHSd=cp2Mf;m!EK-R};W*ds0U}L%m7ohdLh6^`)%f$~rH2JF?S? z$Lf8cJXUb^@nJo6IsBu392Y!3LCB-j_|5km*EsGk*lP4yJc75Nd0HChk$RrQ3%YJU zpW_F@dd`9{&Kw!;H&U;y73L>8PSLnt`p8!SelLFin9)1HL05y9pX2w)em^M8lLf!2 zW4s>Z)5Y0WC-J(tFdu&dKdtG$c;Dv}}KRUC|{ zfN%CNQYXL%g?E>Yein`A={_2b3q{};>3Bf%GIf0L67>m<@7{v{uH%Q@@N_iZtZ{vf zI|;tmo_a-1)`I8D{*;C|IU~paG)4va%)v0OSw`Ng>u7@C_6y_THb#zMU(~pY-tXnP z&uUx=@~jt)VZvP$Y z%+&9G!b%;#0Qt>X*6F!F_hBV(yb|*BgpWA`yg|no!q;dG53U;P@*z)7>USw3Us~xo zF7f^k;eNJ=y4kP%o^eKrpiZOXz4fdGpO?JJH6EIyIG!=guM!yt&G%T}jN2AG_h;kQ zn(wea9Jj=*f*ptdKj*Y(9>pa1eM|jrF>~(b2o4RMbLVg8%0F0y&{sC(hIKn9(sa*RrHxctM z-m+)m-`iPZ?4$Vq8t{QDxh+)UNFVZ`V`?+`(9g~vDpO=4aq?-k-{@lf!S8Dj*<DpT z!;J$UJ;(8r%zKy&&)|Lflj$cw^F~6cwhE?jhB4I?<`B6Hw7#4UfR&_KaJaOzRU3&aa+wM*i&)enzgY% z#w{`{VmHTqVHU&o0Dt+wS+A-QcWiNbsIB1V7o8d^rTHQXA|+HS?*9V#+pW~YD!b3o zN7>$<>hAVq;Lvy734TKIzY<&GC@Xz|WW4sL5(e7aH1^9`j-8Z~Xz$<4EPhR(wpVIDv-x-g-${PI6S?cQ5 z?62Hp>N@qkG(6|Ms2{B3`;P`E)OpZZ;`zMr0J52}Xa#qgng)I{iTE~$)q(sb8+E=Y z@k0sri8J7Poz*+!X>;5e>Z6cPBY41u5EncT-%{5Hl5)STzzT0e_*>Fq<)`0vMk_1C8iFan$I~0zWtQn zvxU6oGFI1Xb=)_cx}C1ib`A4kiHikKjWceWAM^J##%Z$`_F>#!vkmrY81ISS-xs&Q zEYI-`aWI&$i{r+c9`=Fp4)@Un?&F)(4XbgUhD8lGomvOqs+5~VZG`t<&%NW90vDL> z?(h>wQ#yCt@&4dwRhYy*{SDC;#1UQnt?QP#)gu1O;XWVB=U=DqzA*kj zv(v}@l>J~ZeTOHwFJ?NwyO*(3!Kv5BUf}vKrlb3H@XR;dgI;<1_j- zHvb;HmJiu?-sQP0NB_wd^Ly(2HB<&GpS=)#tc2Bq`z5nF2fu%nTSgUPUw$86X%6zM z+??NHAs!%nxevIX8gg9orgi;Qco-)`yk6>dx<0g>zvqTW_$zh^^HMf@i8wDs>5KRT zp3yVh=m`Bzhznd?$tRYY^|>3-|p?aU0DB{QZ}>^bb)&k=`Tbtn6&z=!U*6a7n8BG%LV3*eHES?^&!PBO0FHu_I8d7t=2z!y3aC*A=k zUBmUwYp-#>_Nw~z?7b-IS7sheocq{|2WNBR6Gr^0}`IXdD>qdSJ z>x6#<`IzKqOQ;Wh$m@>68=8O>{H`Fn3mrtCD^#6<_k53A|HQe4r9bmY1kn=soZvZa+le^IG zX{{w6o8z}YIt-O|JmQN(`Pf5EXEiJH`xj>D^) z>t6I{qx+WDo8wQUu6Ezu$h@UAOh{Vhe+Z876ZvCtrwIyRaqJHsIAl@g(cE`_Cf``e z-#2=l(NRn5-ej$D$)vG{ z`QIQe*7(r>N&KhrslVdCXFThF#((GOiz(=if-nCgyb+&#=n(lzA=L?-!gkw}Cv}Y$ zBL9{6@5z6R|GqLSa2+?r%?RSZWpU%pc-FJyhM5uUl(+$AUhJf}er7K0r*R(yen9Sn zk#RlE%p4ah$K`eMfAT)^zVbPJ;g|Gtwo(^(JDQi@v5LOuk?x=Vb}O4xis$_(yvi@V zhW;PaO_Ouor&~YLXS&P38lA%N_WlZI6O&8c^p`VNYAiTY9j7xBNDOc)lYFxT{p%&% zx9MN5O}^PFX0xA^bF0Kk`G3;Sbsl_Upmh~K|5HCZ_1+=yorO<5C9DUnhcBq>!qRV( zpZVWc?8DjM>pmv0%YkUKSt`T7$^V-2K4;_Bn02s+!u)SX+#ItM>oswc&A0UDgmJ)h_5tk& zCdc(R^I+wAj*shWYJV^;ydT8Mae1BmpS+K}?^-@b#~aze|L0Q=EJU21miTNBJn8=6 z38Sq)?X=XN3P;~X`LLz`Gj;D0-UR;@>W;0sFJ^K5?h-Ggbow$8Ej4|Ljor_<{uAts z_yf=Xg*Y>YKWJ;GU_ww~zXf&j7VsoKh=Pv9I{Hy-DZIUe_?_g@hVBW~1{_)E;e+UN z_zyEQ_KhXG34PK}5pJLd* z@SnN=!hc@i_+R+XGd{M)e>6X;pWz1eP^pUuuSV*8f8jqr{|o$h?V2= zyo0jXdG@BygQBm2>*5u_|GWTe}Lo7!3zE( z{nuv5^U?V4CI0?*{C5NEd-NO3$NnAveV_H;@!#64YyJ)Y)pcsk-_C-4K!3z5*#Ct8 zO5LYD{JmwIPmTX-o?S5`$v^PlXLYsbLi|^7Ai;l+#4R+3n#(m*J+pK)1^kZ|k&of+4N;}3*VgBLkvLJT#0}!-C7)PH+^DbnM)sMa*j?lu zWw1xX&z0|SE5xS+rxx5=aBRV~UorDAnXNPZhzH59;?xEDZg!D}q_=vpKip;x=hyI9 z&eFfu!A|HURTaVOC%9czXZRn5smBU`R^#raIlo=PzA5RiSP1^B`5-@qyfEp%OToUn zk>goIK9J}rNq@f12afW0UH{pFeH!*_{v75H--LWK$uD|D{s{6w$v<>F>hXVnum7ZE zt?NI!?kn}5=^+nF^LI54pmCrz*k&PrO4om;vlc&)!?LQpGIB`_?N=NJ{H#PgtsSky&R$5iWk=XTF|$e)H|zm{a43>f)6AL zdA_GY{NP*oB?I`o#FrXxXuw+HPr)MupGX?^Z|M4OLSCoqzrS-{7Kc1}sRIlM>%Se0 zJOQ7!o{`p?%j=~6Ylgf#;aMaO>%V`7_1}l^sFpj6)L?M!68P72sICrl?~$)P)&0cO zt54z=lhWsZlJnn6eHS;?EW-P1+~Dt4j&BM5yN)YL^E$zqN*aG~pPf{%M%wXtbJR(A zo%5X4O1_7DuQ%~8efd8t{ND0A7Ql1a?3_~vsnZm2KUSH{a?u*#KCP+er9pS#6g=@8 z&UGbqa;cl^I{IszKdGx12ggvX8;5)_>8CnLUu{45(}~T>_=_tl75;BNYhA}*%IkGq ze+O3T{L;s%%#{JpU+_SU5ANc1_2CPja(7e58csdvS0#9&#Fv6Mw!q(lrxq$lUvv?y zNgt$vm3|Jr54_C!gwZF!gEktiLjK3Iej1Gj@8o<*pN8h$FJ>+EAmM-H{s;d<&Ue|! z82T}$sHE`qroq$r8lIP~!}LSvV--BV)$kT7Q*Ub?8A(6Kr%ImV|6~PMJ{kSf98uf zrLV^fbPpdBw?5O~65g+_2b|@7b$vkBfpom6`GdNCFcT~FgfAnn1^q};Z<0FjJK#_n z4=fVar}h1soArxfJ>WWhlSx?rXmkzg8kz^I>w(h0BfS33A%9l$_~-L?&AZlhfq3Jw zIR>lo!NFL`4=++*zwh)_E3H%Z@9_5KM_W6!smCp*9vlOw8x3wUoV;uuamiL^y!wUf zsqw>qXZ3Z~e!Uh}_H`X^YTQxk58~&aH;$N{I4<8qa7+1~QqPcn1kG#HykNmUr4GJ4 zX_n=r&X~Je`j42c@1Y_Imhy{}J*G1b-GBLh8}N zN6OE>@G;*)KJPPT9t{gcO@eCnT|ZZSOe zuKxl$SUJ#59D!cy5OfB$j>l83kHmqwh?_J&MDvC8exdc5blphjkzZhiUpP198|t{T z4ad8O@n8e$LYkkb_bJU+)ct+=u*s!Qr{L{h|~vk|K2vvi|_%Zk4x%A ziOl5DZ0?8f)XTx=y+>W`iJcN%w>RN)`|y6AgIAM>{QJI@6{X`Te(tCPpKqLBHX5V9 zWRhP8fAAIj;hyxZD|r4-dH$BLkIQrYC~jX+ZxWuF#B;BQ{JzY_W%DDxpFy9k&dGVd-Pv6dso06Tf*1e4=;9^Q#v*kKFo*kdXM;m0 z_X2$&dLOvU`)WMkH*9A3N}4C2c_TV+kbFRJVa+oe$Z@GR3NN5t+WAcM=}olbs=*%UiZH7Yoe!e5+1-+c;n-Vv#X=a z<+&BrIpWb()QM6VC(WK*N2xms{~#Cn#h~zd55vZ&D~-lVy{c;14? z>_cCq6xa2NdzSb(8RucUnusoOF6;nwd2@Qd(&zhY&=;!v0kjUQ)>HnS>m)qEbRi#D z;(?psLbLe0)@9TD63sW#`KGQrX#SC|59oZP3H-#0*wSJDg64-5V4aHoh78!d#+ZN~ zbTX_H%6*`DLZ>({(~XMM>$JYkdGern>OJb`iQ&n`M@ygtG##FHPvV?@@Y5G@pEvaj z;OFjut1SXI*#K^Sl;^)Bud84UwW-kh>&OEJQ2&pZZ^8d)s45XxpLFIc?Z1ceIbsWh z^=ILsNE|0|ygcW%=nI_1|4H5|`@81(Z{oPr^Y!mI$XenZ{X6w_KN;r5`aEcUkM8@> z=fw#7;Q#9Tcy=ED+4muRcl$$qJi+S(=aarY!S{vdy9#~4n75w(yrkR*m(ahv9Q1|j zeju&$q5Fd#@I7?D&_%4~i|PI$!3Cr~bT(2d=r`I(|EI>8g&#B&{Hq1)?eGvgfmaAW zuuxbh&KCAJy^Ow2T3&ZA{QYM`zN6$n!i%qnf9nFCwgUY&-5*kd`ursLIZcRf`ogn0 zPM^Yh`o5k-H-n4U@;{G`RdmYXH9ThhG-Gx$@N4tI-cSh5Aj2kZ1Ux zYz5;LYZ}+7M%dp~KjbAh5BrJ5zjqJ&$_IvgM&UQj4Exi+4f*~1LjLpFuwyPzkM5guGO_#Q1nT?pL|sC6QAf1uWl(EQ+A{GaY0JcX6KK>7*pg#Ct^XE=_( z3qB-u!lY(JzTbXuw`cjG)Cpui5S$<-IvMHt|3_h;z=d#MkUSwXx|%J~<4bI{ga2|5 zp5|rl-|x|TIb-KQFX=S=%~m|;&qu4#Z#Ibit`hpLgXl*&Kt8m^FV6ne9Gw-pe*dj) zYGev{NfN)w^DTL5|4?6GSQxKNFiHiuw($Aah5cO;*NdMQK4;3X?^p69;m=n1M}F5g z?E4hlMR?eULVl<2!=K0bdpYE7W*|TKfwl1brH^0t^=qB5X{Kuz_V%E6*_OVJwW>XQ zM6KVd_4l<-OjYy9|Dy9{!*jmE`w3q_>$U1SapJJw_+r?9tni(i-i1<@N>5cYEk zz9I4L6?puK_C)#V`rBHsH4E3dy_qP`1M13oi)Y;m9m!`pf9IlFZ?-(Ta#{zX5PHRb@;QPJ zWD4s<$wNIy%`aZS-*umW=9!3Yr^bmovDS5omROBb>bOiNF6_EB`0&GtGF$Uy^)P zK38z1=RVc`x&D) zb-{D~m59N8e2jY1pF#X2_=@0dx}M)(pNA0F)w(+iS&I&j)OF&})jr2@(R~n|ebH}h z73zU?BM$btzFM!pC|1wq(E6cG&?Cx<)jIuJm%JprG@T!6y!aZ{gfD#3eW11zM`ZCP zsTuI0`l4UA%6g6d-Zz;?QOkZ6JwweK)Hs3eO9F=t^kDRT+&jdLb=^|q1ri@fe_I4y z6pbHhzI#^e^Yp)H{PQ+^@)xj|Lftmumx<2T_E67jozX1ltJOMSCOFA7o~LZ&$-+PU zZ|$tGKTY>5o!~x`_m$6)&uxYu%Lq=toX>ON&t5}kaW8y^Y0;0I#qf|1QP+)+)j*%J zmD@H}%ui2!-;6c((>QtDJh4{(DdtvWjCJ-G!xt&-y{f+BIvk@OUX*^lx#V@izZAWN z>mi?4>tyRXz2%~?NbzihTcQ)1?Lfw}>^dD$Fz=7!Zm&5ij zUqxT{xk7EsN5Q;?eAXd!;JY)Iz;bq?L%7Q-kN(yZ|D|Y0^mGsVgP1Q^FgDZAVn1=Z z#X9+A?T1d?*!#p^BZbSh=Zm_Itm{Z+ zu%$yjvDA~Lo+NpL?uXL%gY?H~JmGoPl285;>h5U%wCiaFJ|M!IVwHdzX7W8V5+G*%Z>quYnIPja5)PGwr;qMsu zRT}yb(xOlPmYv)i1fJhC!1GgrUu@=gi|(f2cY^CxL^o3FuWKDYJ#V57`r%slsRz1G zS|4~I{n=U%RO|Uy$I85xk!F6oBy(jv>koSt^D;c^cYBK00DG1BFE!DrOT#>s0%|C{ zhE-k~b=PW6AO0cq*q1uFVzd36_G$2@5q?Gc6n(?v{XfaW+M^qg6FhMids9Tr{UeV89YBe51wYdDgu?vYM<2$)N?k$XCBeree$;wlsd=5$8)V=36aH!i_|)0q zXEk&u!=H;$cbTK|)2EWsy{dkr@A@hC$$zrKW61`NnVx()&iV@7?Yr#ELXcGI7Ib?C@bu>l4 z<*<_v-Th+V(hI?*TN0O-qn|i4b5~}dmnM8=-M`R`>!;(zI@l)Ew<=&|f6#Gp5!NLF z-t$wH+$@A2*+M_W0Qw!Lfrod2r~HLFPe0I3>Zf_EX7)ulLSK6$Yyoru^1$OPu8yK_ zyN&vAXZoKeqQm!02lj~)y}5r{$+ca_E`#jehD}q)+&iUEUoQi>IG(w|kxI zy#|(F7IbQpxUIdC^aI>PC8In##Y;gYU36+EIQQK*;#2sYon7ddX7Yb?9OhTN3=ixD zFMWI(|Bl@h{&*388qZUn*hK#;D=+#ciRl;XgC2Kh@c&KpZJkj%zCX?RD9`?UpT5gB z5`Zw&j}$LLg!S4%nmmbZlS*&Y8eoOs6ohj~Sfj;?dc#U}ab z?8NAFzDu9nEatjSfv=c@{_zL?a`KNiydLnepY^FP3HjyHUvh@yebIk<&Z-Dc<{kAC z^BHboe`J3;1aIP7^CA7|T~!%t1a)&qm5G*R!s}1|0eCa3(f$1~Iu<_m40!g{(2ri{ z&tT3~1@EGt&U&ACEK^Wlp9`OQ6Y*&+cW=`9g}Tsf(KjgIB~!zgKhlML zJexDcy%kIES9bQhskxp@KpP9jCuZJlQ|}$F`(tN<*A07{>YLUp9s;Yo82ToIVTHcM zeb5~?c`QB|eBga=51JDiit@HLk=5_Sr{(H$=rZoR(9p_ok^;m?JyzvM0&^3;@ zg1S;aEGh_mj})pQxb8M^{Z8PyJK#?a1n*nRx+#8UGI{@U;*1^Me1D3a%=Ka|=S8N858b!-g*VUhDc-!H#E+Pa~|%@mh|~c3AG?hf+@xeyQ#+-oSO%c-0c@wUD1!gn1j^!)q@S=uKo%HLTP4nRLuQiaMX6NAf55 zUW(W-za{!3xtVX20o~u!vHt!N`%SkR{OFv-SsxQu)v!-6AEJ-{l>h4mUc8_9_M%%4 zoy~&a5g(tP=NR#OF8hp=H`dPIY?mXBE6DYm#e~M3JpWzL zBXZH5F6@qkultMLgZ`f!=op=JE&P9dSij|X-W$-3UV;0h2;C$;&-?TAou`dYOFuxw zT}Av?mG~hWb9(Btj}AenKaT$VBlz=N^ylb0oZxqo&uJZQy}ws8j|KUe#&7jJ5Pe;= z&a>?Ea^3Y@HXY}UVjhT|(>B$7HrGeb_3F!d4RxcBvGdG&!5oMcW^??(b#>O9$o1c% z4w!@3@4r_%U(oX)WM7axp%MMAnK-WJHER8N!I^X%dXMif_>tBh`jxfTA<_7h){WkT z)%e9StnO3QJjHy}c{aL7l%AWkojPYJ>l}K>>C}km4CndSWPgtRD*Y4fxc(2AAKu8{ zYS(es!J9p9w_?s+9Ov~#=6==k%hUhAkvM!F^AJwB-IT`Bbbr)8t=3m;O#kE;JTK?r zpASISsxNWM>gWMa?Go-x`gU&F?=n{{!sj%{n*J!_n<26C{t>$d_dy}z{12E< z5r;li4Rlp?PtHr3!kMl zb-qL7nQNKv(Vu$H9_H(I_B%)ClWz<{Pq3?V6O;Oi+RjdV-`X!ie`#s-lu|^? z6R#vyZ=(y*n7H~H{;=@cuxC+ugs?G``|a| zZMDVfIT1Qu9EQ%Ho*&SUctXdC8aL25lHkZq;lXR1p$`42uVX8Pd8o!AA9MbtzE}Vp z=?v@a=-3~@%KfkBhU{RSGSnS>F`UmhjOQ~cbMY#mkN$y|Rh_qL(=W5f|IErwe0;-y zg?OhN^IlJzt>|Z~s=C8#{Ehuy>ZAWp?FoK=Zr-Odaehkj*tP7>wa~qKHg~K$dSbPl z!`@E6oOPY&B{Ta}5&Hfv`5mL9$OFGcKWi~_E9P+hZ#xZQ{ro-nkuQl)J|KSl6u*+# zzU(xQ4e>M6Z+@0~{Q@f|a~<=mZuA*WB7U1j-+I*BM}BiQz+;<*^BlIZzrW+{A|7AB zT*d|TlP4z+?}AN*zw5515r-f5nxMlNB_C@=zIxqW?JWWyfA+j@XI|)MT$h8yb@Q-i z&E@tg>|y4}&ByLEN7|ob*O~7JbHNsyErU6LU$8H>=eWcVI)Bu20Q)lsune|mm^XGn z-$LVvdVWMstk#>=a|o)?=kqdF@I?2lM<}xJaI;G}1y@YJeUR^|e_XKfCK+^||9*kCxs#;-ee(G;fHCw=URUke8RY62kKuq?&-k z?(jZPlj-NZ4qjtNhw=WesRdR+>f+t0_lyF^fuC<(v-dDJv^n?N6P~A=<}Q0X$A2?d z1#>`uHfP%lS?@8&26I3+n0@V$td|o1eTbb!-q8^|(JaQiPWl1JCu(5@N7Qpbb>5)o zM(MdDdVWxDtl&^ue^$>WC>PeF{+j3fjDMo*)W37xq%T4Igv60r$L=Too*uoOJ=iqV zf4;{GUrpnpD_F}u^8b~UxrBY`^P;a))#bVB3GQ*w@|~67{2wr%AVX{wdP9FOSFb-h zQ$5`q>=SLA^KP#AjP!XfcVCIO{N?bl=EvHiFS3aJYPa7a+Mnxi!>`GHa~phhKl$D^ zaMSGYSO<|;Ct)5?U-G!L)>f{=WOOWNu}`m1`n>BrZX)+dQ>?x&I*(h*{_zoZ19{qL ztiF!Zus@q~g89(r&2R0stP_x@9q?|GXP>l>vc7HZwRd4JnrrQK*k8y8zQ*n|#|LwO zH<|tIF|3!P7uX*=*Q`q&86Kcn5?n~fm(S*j2#zFm1w98?<4&!~+jV>@@uHp&`UY!V zXV7t@o-?BHN{MgvoS{ct$G5`zQw&`DI%^9Zj0;$)ON-92@D_!?Ed7lCPi@+;5AuJv z&v?<_;#XIJ13Y2BZx$QM^IX{dn*3w0-GsSwWqIC5xk=(q1SqdS%$zL=jBJ)!l)1HZ5@%qQ>LV|(<04f0=RzFhs|*ow+}m z&&S-z?%2s@*#J+_b0h1rmUvO)%Eejhd1AWGD0N4P$X`Uyi)Vibo`_B zsS{u&E|NT0c#FbY6Fl@k+bMyrbzb_OPjVk=-ur)J=Yo^x2KR`7M zLjD`h$ILCO=+Ce#p(D}UKNmgibdN3e&sa6kpUOkLlfYRDU*mV?^bR5ap2B%<#d(l8 zU0(+sw{H#O_#e&B!R_^RTNKQ1*Vl0)>$~QGV7_}o@~PvjlY_Hd!s_*}SpB+9Sbd%K z|LgZ1f}KkI*aj(iBlpRVhTP1r9I^8N$Ck#xBEe-tJV5-SbOEJE3P%ne%p&=Vp((!dz>;?-fEHcqj9fJJ^q%fiY8! zq3$*@W`k#a8~8izC#UneZ`kLw|CIUWx=vD&btm|9+K<%-_t5#a_EU+mT{#b_!M(CE zpSG4am^$biTNxhTW$e4;e^0Rk@uzy8!*#AxCE|qPRtog5`>2Oj zRp)|-?k+lbOT3B7V_!+j@2u&pa8t!MXKvyV?|uAHBDXw#sgSSZejN|$c)vGR<-gx@Y?r*_xGzVjEE&4S;p^JJapN?lav)jF@$`F3h-VepLme2(Pj8o$`WTI-}~ z+(Or9$6_nfU$LHe@htoMO>~TNQ|DO?PE?Wl&Ia&<72woAcnke0^M(eY!sS+B@Ofyz0E?E&~^tgX+yY_`4;}i_GUtNu6x9laYDN z#jKC*=e>y9OdYt2dx}1{UCh0BtcrwupbGFs3-LQzz~3o{O=xP|?gV_F!qj)psm1V% zI&=IX@%>olc5VdUzK)LOX5!9A%z5+SyPe_ul_q}BxI;a7ZTk9c1K+Cd{Rob5ocv}Q zbJt3Ozf?jOJ}$^-HUB}MCmoOI=Sp<4H4pkA?;|>@S{Lba*22Hkbt}zxOhkRLzq?D7 zC+_|O9r9~b9bE94H=OSx{hxNIOZT~z7(K=7=(jgS-`!>IZW6~JzI_Of=dtsw z;Y~!T!?&fsX%Kqj$JI;pFKK>6z7TgT9r7V0-sl_hAKqfF;2X?4s{v1ZB6+ju(7nhFXVI&s(AQO-Q4$;qVFgvJV@zpk-le{4=@lO z;bzW*%#9e&+=xA_Wq!zG=EmGdXF4Z5$>d!BcJ%!^JP&)&<7`BKUVnIE)$p4ih4|(| z<}3E(dt3>5c@@FmF48yjG1oo4w;Mgeqk*54d2k=X2QaC8Q zPx$@vyNAQyDa`(r8@|>XJcqgAWhCMIorC9k-npfQhI-!JLVj$^kT)xHSw!Dite&%? z`P4E`qgOcJWdwb~x*z1LkY9HMKH#6M6QYxslJAu-!KI68D42xbqZYQ z8}PyJ?VHq_`ceOBfi7fazbJYxPtb`iXHQ_R<4pRnvQp_g=yyYp@;U01ubUUqx%iy= zO!;UA`ajc}k9aOd@O;ljA8olR81}i94|UIF4$+{nPgdrM=;uWD(~4evL39Reey8Ze z>v=)iPij5*iCCErBy-#}u1I83C`q)mvjP0-m1qV0!1F3&v=)5o3)JfyF-PN&Ul}`x zx#_d%8>{R6?x(UovQtq{J3!v6c`iRh4^oe5;XjT34&G1=9jqHpPWTTw!8JS3Z&Tiy zg09k!==^uL*Sf#?4Xv2{0ebEI=+{Z$Ed~eAMr5!QzW%rNYV?(7z=Pl8%vZ(GfgFmy z_uI^0(fu_tmr3R+=;uTCjY)sG)aUh_skiyP{X+jFdbolQX@2Z}{;u=NyV%e11DU9A zRE3w&#A~Rk5X_5L`u^|KJvN~i(hnYc zJUTN?$q$OUwbWYn^HK0x8i0Q_M`!pLabpZ!5Yb-}T~2upM8{M1bDbY+UjID!pRZCc zeh}&ei{78`wl)9C<#obam-}A&b!&&Z9n$x#`{-KnyG5sOEYHnprw9E;^ND+2B!At& zzV(Rvd}XvG>+H;3`H8t3AKA;Ccj?=i4o=n;U7RPVuAfIwF|(V}n;m-%{@gw4{_imt zWE=Wyr~OU%FO+!Ia{R!4bW;ZrFQsEY>;|uAJiMN6y#IW6u-Z-h+>yGD^e4!?%Ix8s z^0wsH1HD4%aX!;Y{W9dQw`G5;&hHjJs?22&KB)Amie7mpE7c>OFRutZPLi9*x^IVlem*6>cs;{Fv*f?6yd5!tT-+?bQ_ud5u+T|Se%J|8h zN^S+_6cl$FGxsQ;pV~>{ZuM&WkLmNQieBJV`XDa559sHdVV}XTmLTrw$lNW>my7WI z-(_A%4Xo%l%beDXp&u+q+~gPaB3mP%>}cwc?=lv|?jd&u4E z*Mdh~fw>)doU-V+JK$)~yQg_hX4$)$S3AIu*`G4^X(fCa&)$yyj{N>vp?-ih!PGpaY?IkiOp?F9Hj0rJZ2@LiC# z_Z_D_&r5FqvYn6nqo}{a&f=B>hit-p?+9_qBI1D7EcvC)6|zi0C>5*z!>=Iq~N>Ej>h>`<49&rUdPiDR2E zH*1R8h8~lP9+TV`^1DT6=`MZuHJv}zT66)YI9t`9@Vhtb_=q_BoU<5RRM+0Y^V0%; z$}8xn?5FP44W7^z>fRTa*YiGoQx%z;EAtWb9BLiMil5I5&qCvV1=(*eyZ4o@GirQc zXCxZ^1UrOz^g6GTes%l;?*oLxd4TbWa%`-8O~ko~VOeLnk~F>1HD5gm&3Y7BLL z7oGUi=u4EwZ{0#yq9T3h$MF|sd5$ikZ&sc2)`9-B{?1|Ur)Rq7vae3!e5`aXz+YTK ze^p`lfWyd(o2l;1S|u`R z9r!p?+`H(oJ)18j`YytQyG@_6=Hag~nli`YuX(G|FD1G?(l0$8U5T3X<77kkHW~h^ zyIC{(26GU!f2_p+ixoYF^Ksvq^*Ap5*z!K|z7l6i+$H;w#ATJ~mv;D__vlCJK;E+z z-s^Gtgd)*$)a`Ej`J)wyw_Z@6k`JZvenOvrMUWrsdeUBgm*`~)FHv-EWG=b%DIJGr z{($c(eFDPx? zC_I{+#Pz=r?+af?bO42?cNqQOPdOjL&uxj$Mith=%NKvRBb=8m{km_Nb)r?#DNh|O zz#NvZnY**V*-SoEg1F~B^!STeeevTb{gT9mG2)o&%;6jjE|4>v^Wo87J&NB`I-Hv# z_m%WvNk6Ur-0Qqf=ElnRlKIk~p@ZC!?<+dSnm4_P=b$`#2e;A38An|rAJ<>zp$flB zcqyWTyPEuW0PnL7|JjAOSmH|2yB5B==-lswf3t)6lV`2`%q5=}@E7OOpMH;i{7&9j zKc0TZGU$2NKo{l<@Qo_yme1gKNS~?P-x6033FnG$OZ`pH1<>_1jc;oF`E;a2fOmZn>i>(*gFX+% z_`B9A$cL4=%}0%1!Mx_?@U%04TO9(&RPeKVz~6p@`1GT&KU%J*SUE1bIMSyhbHehP zMWfZ-+01Kvgx*1W<{US-&$_i$E%3SV;D3V4NPq00g!szx>MH4D(Yi|w`Q3VceQB)d^Sl)H zHH)6Zui^8VI5HN!gDc>iU*kUyDVb0Imwl#(vn|v`=|$gv9_DI};C`LP@68*n;*5s> z`nppST&*zm#Y%1s`UKX}fAdCcDDmG(>h7MJNdMM3cP@BovjDdf98cF%HUCC%Jcrht8LAGujrRJ%=NDT{#BH^d?$43hl8U}V!lmb=3nSIRdfLUWX^@o ztCI)#=OgCC=7PVu9ewOfZcT87_uxq6X(ndzKx|Add(+)m0o z(Jp>w=Gax@I_2a09c5oHNxpH1{j3dj#y7n`z+IBSt6`1_xNlXguJbg-_6>P+$*e{2 z9Ve<4)Y*#BAG@8pNLhH+Oy7k^an8>IPpg$zjee4W@R?80_mwT+EnCdZ%?1kVb9pNz*P&$?Y(=;VkU!Q52c2UZz<*d+1k z=@Xtd$Zs#pT_c}ws-;?_BX0sR9`zFuTFn9)giBmem_u8%WeCWKK7mbIf z#J&X{pz#vvGZS5qSI~=H!gbzA-S<`Qn_SVR&UWyks_-Cu`ob>QmEq47WlrEs=L&q< zisb8a;q&Q!pPIbiS>mmp^v^x8%7QcP@xQQR?kDhRUvSzoU&HlJQ&-b^J4E6{c3d|1s#D2A2#xvqD; z&w3kuEt&_n5MEVJ>@(h+=C?iL)9L;R&9jsK_+rFykNDowf1!B-yIAYEO2>~Q;X5Sp zrl?EQ?|)+M=}q`OM>rp)skgVF59%m&oS~dAncKORzRrH&O6TC?=Jsl-OVL|S2Y9XX z*{93FAF`sos3&~qFMv;$0iJMc_^(}K9pE`9gJ0AOJ^DD}nQUr5JOK7vRXgO}&7qE0 z4tv>M^l?n$cbzj=+TUV#bAL?63NKjrJp<4?FUxVw zC)dx7@XSkxdLddz?k2xm`h&HO=t0)6Q@`BiKBa!qI>6zzj?{dP-$hq+-v3}r&}Vv> zz6_gsL|b@OsGT{R;NN>Z-+lSLg`6eKg*E+r_C2R#Y!te>_3=+h=|?(3y}A$mC_VAt z>s12!w1&W6e_$?wudq>7v0icZ^BgDTeOKY<)6w5{*!!8+oep>qm(1@1e#Cxw&zd)} z((Fk8!e4z7nonDaweF|zu+88B<-iI*PxsqtJXPNx5BYt9uL-|E_vz{L@=q)0OYGa6 z&-2VvTL`~Z#lH4!cw@=pcqc7f7whoQG7}NSNO&|=(FhvkKBx1 z^HakU8t={h7f(R{4$afpZ%(pjVlSEN171f0aD!i1Ux4qUc_EtDqkpgPh8t5q%*uK+ z`(qBy(+AYkJJE-bl6eNrh#&942TbS90l)qr;9uoIS5)Jwb>VesKQRM;nv?%eg$~nuN;urc-chu>rN-uMA^fxgPc-b25W zvw^<4+~8>y!Jn`D4Z$zJA+A`1KI!}1Zx5JzsOxjt(63sLtq8tx13Q>HM*;lY@8%4C z=SKMbJDskvE57EfRp4`_-YNR1qO0+gI?4$AQ)lM<+{BL!wO?o7eb+AlPTIj;tg^75 zXXA5AgFiaNRoBobXop_nHgKoz>^no)m&?N=EdrnWj7wezUmyd#tHjnf^w+LrzH%04 zE%Ow0J^c*tqjlCaUa$M4b$lWCQzvT^eN!3eqsbaA;(n#3hB`^p!@l(Iz@yI*N2Wz@ zFFASKL-e0p!k@3q`!1!voRGZh3%*Y^>gD&`OaJokmEdV7Vg9#%PFM2zQR3uj)G=?; z2Xx47tu9-S?G)@+Uof}md-SsQ!po@79Mtxa3Fz8vRv9B*sL$+I?}YQ)J`U%5{1oc^ znW3J|gs|UJ{DJhZd`O(}A^YjO%-i~z`OuB5_3(Fda-P=EFWN=DiZ1S5bbL?YzZbai zYLK;^w(nRhjo zy6Ir_bW2lbmU)ad(RtT(sf5N)!Th-|t;5VUUWY&0Onsy}yzklMl`Z^?_9&+@^Ba27 z-;|TS;CA%6R7AHX7yYKC!O>+t)@<;_9$Z&FpZy2UcYorw`_!#P=Rx!y1z!+dxeMsd z>b$rlbL%%a!__G2yUI_LtQS>r~R7wOv{7|!)n3;f!+BbJ!a83ObgZs}n>VM#~#Dru|vP*?1 zOV(`3o-IW7tcC1LnQszpgj&%C5Xutd8{$;_({&>Idm7z6`l|DtiTWRhj6^52@=l@qc8Fm(1<*F)z!) zZfU@Lh9LI*3(V;{M0`%>cYesd&L@cHO~TKZ!?|5ae0mo7!0ex`gsRL1R zzX5Xp<qC;$Bfb?-kAUunXe{$Z6`RH?z-{vq@y?Jn1%!Z!H+9QNfc)N6M@pQctknZ1Sn zn)VeBWv`>oY-q(Z^eb6WKZFK+h^#9DPMjmc0(=rWn%f1N++v)Qu<-+-Cfjat*4Ijz3lw-*}Y1im#XVl ze^=`GY~*}B=x>+XT>c#Kq9Wv-Ruf09L%vM)Z$-*%Vs6ya*;}aRX}AxWR;&1K zw#=U!%-o1F)YZIpV%^#m^?2X3TZs50L}=2Iq9XR(_6&Kdm2 zEAjUv4^fl8?`0LfMovFX1!i~Vg61#(9rJ-pl&;SAc#8XX>oPa%_w3KXN5TBu%Ub~b z*qrk;iTZ`dxi?@C`fWCK3nQ2hco=_b3US+A=&O@Aw~jf3C754Mg?F}`%f`$#xSsQUhJLF`)OSA(pVy=B@-TfiiSYmFQr94- z-XyQkj=23}=;hMHPq$FF_9c1tc~yEd$M;U`iSG3K6~&I&LjTw(^tZA@6QScO;ut9v z*JLj$ZI?TTysr*0?#v)fajwyDAz;)0FKFK151Dg2F&6`$eWGe2_~r)AHe zE@c~aQ6=H)85MTZ@9j`GFq-E_=?7Yzy*#T>R#zt>VPe*mS~Zfzd1vlgWy+APiHT9$Z6-i2)^z#bJl?`Idz>C z;Iq#4&H`|iQ`VUYE_57c5;(^x=8OZUIR%}O;6x|M848Ybg3cgtwBvL7gTo!e=?e~V z3OM(I1Dwm9?qEMB!RZ3_a?VCNg590dk-NZqoL?e$f*qV6Bdx*q&bN`JCPdTjm}$<>fjB| z{zz4@n)7-j8_afIi&O?HJ9{FPz)H?5k&0jiXIG>=Sk8GlQVuNZY>$)yOFP>lrNL6{ z+O^;{&eq5^U`gkNNJ-FfwnVbPi1U2J0W+OVkqDUKY>Z@r>CSVJ46uZ=A(9SW?W~WK z0E@d=%y~9)HS3~Kqd0h#v-VFc#yX+UvVvs_vj16n)@{&tVAfAgEwFvohfXQ*rmWpi zCLy7G);dQAbJPE{GbBp?<4$+yRX*>1rw!jcAz_cx*jWv3acVkC!PU-n&ZFQ`xN0i+ zsB^XR5GZt?;DntatRHl2=YH_t(z|0WdbiDk-p&6*dRNVp-n-AEcUj)2Ob&XNVts8c zdS^lB7`-?DN$(h)H@S3<(Yu68@2g#U=SAn7^j35(;;e}X7G+%+>Rbh$Ot!vlcqP@&Bx>NzRwxZ@K9Ip3~ad z%=6t&L+5F56VhZ6_@qxbR*F6VrxqdC2Kp7VU)!#c0?9jEtq z(ewRx^uC49`MdL7i=XFpzW3$`tIBrPGK zTh`~C*o1_pS^J#gV0P9fBr)(n)qwD9enUi@*T+^B%y~3W*1xpAGFGP$H|25H)OqlMn?Z+tw7@@Bm}ai zJ16*@bIx!yWkSN2P7gF+LV`N~TR@@z2B)g?IP2w3Y3C7eF5IN_{Uj&Z83vAWyv}{# zAm<9F2iV8?J<=KM=A4YQ2XoUqFa7=R<@tr_eVwbnD>}O)>U@{ye8=>5jNWm*{a1Qt z{i(O}lH+;l>zJM{hMvx?uP;pJnEcLtp7Ww}s`F%|5bu%lCq5A=$og=wX>d*;A>q|f zztCmyL8Zi3!WH3z@eI>=3_j>mFtuPu_@GYK4k(6wlJz8(S3*K!)-2}-{(ru#QO?KU zH%>1!B6`GW8`b|J|Aqd`uqLMS^V!&YW5I`=#HhX(J>TES?{wvP546kOU`OYtsNHra zTy`sKvDaE&qP0dNT|MA#+gZceouDs-6MB6fM~e4lTZ|GnP+t39sdc+3ueE|(pCVf#BTd+guP zS)JpQKk0j6Iwv_RqjXOMQ~73~K|NZ9K%MMEk3uZFW2 zT!H>q@?Xxs(0?diWiOuhM(!(p-`V*&(iRlG-qQIj>Yp`6%G|{B23Q-)AG;8}tMOdu zeLdc2Ui8lChlyQ&Av^8w?eUl#znC4a^tGI8InN5?bpES7mQz3f^*jq*bK_snv!ZiO z`U;&B@xs;fFqo19kJ{tyB4A;@4EW%h;FE#N;e$3IZ>R};urgdL{33i% zEO~X(w}}Y}mlqtEwgo;AJ3#EfV@?+|W&R@@WZhBwH?-n~v$#bE%*l9WSw!_ae z@wapO+2_mgzdzR^zYDp3*73R~J9 zyOs|>-R^Av0N&{T%)SRcIO(6@Pk;}82@D7v0JB3M2b1B0q2aXfT=*b=a=)aF@WE?o z)ziko2l=x`J4g7uubq3NcEG#N9Z^4UJKp3foKt}Utj24 zD}OqEu4DdH&huQDpU3s{#m}+Q)4A!K`}|&vz9CMZqH{0@Cb?^culs8F#(VK!?YDhi z=s(-8W3LBO{afw2@WCE`d;dZ3r9j=l3iu#3vJK06O3F?e4IfNSE0ER_ zKKRM$@4U_De&n>r^Hp(xTktql{4d*?530D|WN->m#o^!xq6&S%KIs3>U?=RpHlWa7 z{B?=HNxZEJ-iFfSqQAutySSYe)7u%u(Q?Mm@{;3me=8P0iJ$A3KV8uEr_Z;?;`X-E z&w1Hj=gaF0pX0pF@5SgFB>JZ49Jl}`@;t>i*ZY%|kTBh6_-=;}!uD+6L9oA_ZV!SF zezNECFV3z1I{&la!-1s0Q25~2U}rQ0@yYP(q2}~oqE ziA+d%-n9e74xB;!XEe_x?sK1$FKYkaq@D z-j^cBbL;EBKi6?OD>)vw!*a`Qk<)^?=^U5SIpy=k=zAf$3cVG5)z20Boh28<2feoU ze&~P9+r_&ZyuM}VdA3~vdiRLOS~j6`7Qp`#n1DF>718* zz7Tycg|0d29d_xj(1s6UxHyU)?_-u1y0`FtW;FuWd8>HmfhBxPz30^07xDFj56atb z`Aqm=mEDqmkr(iPZQlzYWCgbPOTq`kgQo*G!3Q6Q#)LxfLBXWQ5`V#e{3^9)>R$NZ zHKz$XoRF}dc+diHk*fzLJ1Ncsti=wv7q6lNYsuF%cl|!m|BC)q`MJe*2@dxC;;juIDE;t0IL@wU&w&q$`*+#5zz4tkr}?jd z59$YZ1=8Sy=R+MsC$JZfCw5PK6+YOQdPC|W_~1pS4wh#;4>-%Y${E92@;;K!llV_7 z=krJtelGTZ4eWm9=ZX9;^K#Nk@GHbG(~UmyF`wwxc9}+^r z@;b*k&uMNs{nvAQY4lWd4)K1zKXH+}zA)CdzA(E%_W@SengOn}8d|%-v(^;ra_HX7 zdz2>$30tB5ar3owe9)VvpyfcT7*m&bQcQdCBj%y`5Wb$Io+KbiUX*j-AiH%HzDw z=|82bkE~ma5B?rcnF~w@dKa~Jnm2<@tRKz$zzJ5SwG4dI>S7%M)4dz54Cp_}o8o-{ zw0+aO-+&u@C4Kk92X*aV_*X*02lhzY5B*pAYvMs9BzzL+9M}mT3^@;pR4#^BT(r9m8TQ`PvY{T|0N$T^cVYF z^mcA~=XI{dKNifbpL3q)+~+p;I!5QeKfjlHUh|@>*QK|@Ao~-?h3@*oxZZ4Mer6;j zylXySdZF_t0uO>KteVzV@QgLtx(vFv^L}f!0uOud_HGA<`%Zi7 z!v_)j1>bMrM*D92OZZ`gzp#HEe6TK1B`^;@xGiLa8o&pw6Tb?#fDg*1?no&EAE>;r zk^@rzG1$4%>B+jQn+KA3&@IkKk@`HB`U{EUiv2J35t9EF`iosI_E}!%`rpv`QqJ+e zrSJK4y)YfUWLaZ$|7SRe(?1gW&oFD6&w%UA_U1A0kU826KyS@@#=H)^!8&So0!LVd zt$Coxh4S8=RypYZjJJ|^E_kzVkGC-Nx9oAgSHW3!ZF?Pj(At029tIzb3HSp8;Df56 zqro)zpj_gPa9Q|3Po1A)!w0jRqEUN5{6fhK+)cLW4(Kj&K=}ho4oF;I{6O*hByJ=5 z6UlqYdCz&SWAgjLc35ux{C9TNrN~=3zyB?|S}q@4D%LfBHnO018%}>?@P0GH90JaS zA6A2#q58Mr7v^NMAapNiy=2w{TU%$%Vc;sOmh~d2<2BgOU+l&--=p4NSbyqk>6-^1 z474NmaQL9I|B&4dK4^{q*c?767J4Rl0(;R+ToCrd2ggzdr~E)2!elo-B>4fU0}y+l zk(&>Ycwk%(#OkQT50E&W#Np)p3;jio=ccn-=Owo^FeVb{R4Zs2L!!YnMv%dK}xXbKq=7Zk9nG4O5;C0p^ zGzf7VtElxj_=z>Z`WC#^d(3JK{lD?{^1cDC_NDv!zz3~uuiXefNcL|*GT>JRUiO!R z4?Lma!5#3y7vZ5q784S7q}-A64tyYWfGR)SjrWuIpsL$beu1jbQ*q(AJrK*|i9INC zK(aU%iw9U!Jn_vlZgYgqs z)%?^b2;J{6O|v05%)G`N2QD|8n{R+0m?KR;^iH%ko3+4pR)RGW++ww`-T<%lzGz(w z{a^Cd^{xcPPN-pj_L$Oq6Z{CD)blmoEtCIp30lP z|697|#Sf+{Cj=ieLPmS&yw=Dx`hjm4HH`7#cSbv78EBXf8oR;b<{INWu)6uVQ3SfT z$2w>Qj>kH93=}=_t2xiigznYw8ajfru?|*)5@(v_E$STuA2jvt^A<-QWZIj3r@#;G z(RKhn_{Klde-hjf%nJ6050-~(gkOLU#-tQaSqL8tAzyqibQb?Gw_Pal0jb-O{GQau zO58{6L6HL@|Ap=%hx5Yo>HL3|zCxe>HnuSi>LsCTPvc8H8yt-mxEY*pgpIqvtwuRx zDEJw2VjifOBaD~966Sj2N3f3hqv1gRo@QaQ2RP4cV7>spXAU=g(7mv=-Mk6xZ-uN! zz|X8f*7sm9?^&xOe2_^L;SbQZC;Rrp2ixp!_9^7TUVjJwhw#Cq;FZA^@WJ?SMtCWF z&@DwznE)S1o#4gvfz(^a?ZQ~zR_bWP?^kxevI9j92;Kir(fPkk$BTddf~b995`9&6 zf?x?_seVqw4>Q*29_V?a@sb_}Z#CZ5Gr(TPSNiqfWTSx55_}eF-v=Hwnj4RThB?M~ z1uSW9H+~13nOB%MK>v|u8FLaSav_0eLK*1Z()!gL2yVCTu-*o5_8zk8LjMHcDDTJM zFTPH`C*Xq>c60j;_~03Teg6*lpiA(xKt=eVSJ)Sx3?DR0`6;+fj9`}7C&L!bxge+*1EX6rwKS;iB3e&|}u*rq3ecNrh)rNJ@AA9^Ej zovSy#Fm5v*XB{+W7ze=0=7&fS`Y_C7^KNhf(WRHb&&-F-6zDE?<6^6-wTZRk-E3t+ z{|~+Gy)S{1m!4`@w^zUikN8XbpMnqS1$PEg;e*@4r$a;FgQ_WqlRLl%J>9%PTj!f- zy`ba`Ymtq|G!&rs6P#z_v%gc zb>KVt?fUcJ5xs-H1N=_!qwfdv8>96jV5%`!{~4@gY|u^Ue24L#?tsD%&l{zTL99<3 zU5ux}Vnh{AfQ`)jW@YF<#;jn@1oxPI&C8&BA!{3+1@V8Yn6(fzybCNp^xy2g(Ypj( z;Va_nhCCQ*m$b*g2Sfa+{yFf06I>a{2Orc5e;(=zA7rJxk=z_Uka&^gkEM?%Z@VBC zFaA5bK>2}jeIV!feER<1MAzJO&TG9u&(tSE&qaEcJ{erDm(r($PwN%+x!@+fhQ1hl zMZZOV20WzSslN#RsNbi*1^SFB`d6UnkJiTfe3H@^o~XWf-L)r0Ph4jnG=k8-r&+}8 z39d2Qm>+|eSu4%*(7&6dS>wU)tkKqK@G)ikswM+q?QC&uzWl7Bzn zE{OBN|BG}Nei(w*zZd!q(F;Uzn6Bx)S&!5${XTHK9?}PckLZQ<(cogJI|W>iRj>e5 za$_xcT<@;G3L3`4`WIjYW1X(U2c3;i^zz^mBhBaxo-ppj;)webtxVml5B=v7RoV!C zV@@}(g6>VNpUnQ?0js<9892ggM)Q$feaDD2QXgcS_Ra7?bN|ow{qVu*z>vWE@ImqL z?$9mpft9j0IU7Fc;KmJA9cj+|f%JFe6*p9Tpz?${?L$?Uk(&?V`usoB!$Ob$HMZvT zwt!x@>&LZb;B8Q^DR_terPds5r=QSTft`{1ZNc7Hi=Ds+pl%;tpk7aI1BzwIA%_{nfe?dC=Im7f%xV(LU!Z4e{Oe$4?Yic4ZH#$B!xGJ zYQYEjQ&uFGg%6~jT#3IDJ1!3}8ls?g_peXmv-tgP?R zDuLIzScOx49qVfP8`||?ZT*0DBiLB~Si1>q19e-1_v&Z0j^G&G*6#-wVihQTvIBm2 z0z9Gj;uG)(jRpEi@OInS}2_L*0XdT!LA6VhFp=|izbn@fLS@6M~ zu6?NLN>yEviW}7cC2k~sg47X79YLHAVs#&R`HL6h1H-k~|JRt8T*=TkYMIcZDAr$b zupri85io^QTquf9Xa&Jk{VA<5SVUi=6$R7v=d=v4w7yL%1ymRbNVr{K72zjB72t!P zlOIjafDhWxz1Sk6>I!0g1-bo%-0{P>zZmPIlRUzu^1=U_-k19KY^=L5bkOw2G#{8> zpQ&l!@7gr&O7M&}MY|0AO`9CWv)WYca@Gk*dkYU@NWHk?GErkS3Zb+DSk#lqR_wa^A2Pq%0mCmMrmU(7%-)#iDQR2w|f8zt8=TF)=?VN}DeQkvHD|k#Bto;BU)$Z3$ zfFEo3X*;zSeI&S()35A?e8wpKFj(K%g=K*rF_Mjr;1%XzV=Gw4%~#Gs z3ao_>&YFwJNZ=n@Y1UjYgF2N==x_QadXIyd_7*A=;7g)N4d8#0RQgKQDO@j~~SB#7jM&|Lx!V%B9;8 z=&9)Zp4L-42JX{3Ylp!-T6^svxD#pqF1Vdj{7w{a*WLzS)>>-^z*nHA`n~<`|NB7e ztsQ55TpOnS1d99+IdLssLv z@E4;K5h?5y^DveJbz^2W8BF|9bBFJu10tQh2`-D{x`X~5CM&rv@Q;qUN z4nEi#s2x}iA4vWB$>jOT5%@s*4rTt!4Q}1BfZ>?)hcRh!5L`vr@*P&HQFk0vX-T-$bstl6Rc-y zWwmF(`FIuU!IduGY{a{KjrD8V-P$2g>5uQgeEN*2J#n?ZK}(0uVn>d`I#h9pZF)U8 z1-Wia#8agXz&NUxgAd*|>KKzj$v;Sb`j|Pyd%6HMdiWz zs5}t8@G{lwPr?VD@YA8|&p$E^wjmSx?q&$^e2|ked67_P_p9&w8hacj65bG<; zEf1vc{$ly&|1}@Td0(d0h|+zIR$g1f{!i2*+H!Ct-r#(2piAdocnOnPcjdG`1a`z5 zco1x_<>_}FsHS}MqU#m|8B@W%l*o(%XzrZMO3uIX=n< zA`eo$Pg;ebzlZL}W8gLR%S4#te&fMF+rU=%AdRl)dhkJrDwG=VfvPuY2)(8LQ0k6k zzE|FS5Q`^D{gLFEB;S}juK2&w5397=Q91t@Q6F{QCuvSpp36DEPYY_(dEV8fpQ5v( z>uuU;&k(Q~*4_PJBcym=@Mf&YUSI>f1BGhc8*Gd>(GR>;JLwq&wuevD=k(M}Z6f#p zQHDoBkq=@=yg{^4*(E<~4@LcoV*0b%)zDqyl#l8q^zp2}(t8rYiu(=XKNiPJ_#QqO z=<2UbSgtLO52wY4ui z-B>rqdsKX(KK}vmUZM$;z%fJ-7J_1bYOtLW|SnxQ?+`c6)rqPsfh{lR+Lm!2M=(6OTSzNang zQdp0zz=-y`r#YC8_1^@%8tXU(5Qq;bfsg=>5=J`ggNz{InxP$_Y&NP!PtFv>>jn8ZF9 zPM5<3_~1KpCXr_B8LWaiUk?!BV{Uu#LV0MFfBd&{U^-g$N%mFr zd>_rPO=aDIXy0hCCDEXPV12Z4Pp~Rcfev6fy#6~tMek-{QEjKEA()1DSPx7@o7VzE zcn>weAb3M`y~%SUn1r>VeqLDH?zsufzzS6SBA;7R`z$I~l)g}Z|6a|C%7uqryJR&{ zgO_XoD(;gmT) z+6Ohxy4qR{AJp=`ZQTGL+~|AJ8-@?05BhF@e*b9rAmY{^v<{yQ4TBGEOF5l91U`_u z^o#RBY`%!pCrkZ->N73`Jym>J#glT|i^@(2@%%!3@Ne{k?B`(Y`PuAeH==eEz}DJX z&oHnd-g+NUozG5Sd7?nA!Axy$lmM6CImJojqPda8mNr}aAU3baZE@G@q6n>Sbgfb{GN@MSdDe6w$)Py%y8wzb?A|Htkw5Wc0^~Q(qlo<4^O!E%e!ve%FyR) zHgvB?+*$E~$OFkwH#T0^i$Zs)OOSliWV5Qd1bL9(T0tZM|J5o(gjw}Pe;VzJZsmK& zn+YG>WrytBkq7;$R(=FNs2$wSLXM~TMf8Hil_k$4 zd?5X*QkN$AXT=98&|Uf!;`U;!zfbBE|Ed2l7Het|`zdyw*z+xj<__R_9rSc}Q0S0F zRHy~(B1D54fMG3mo(;T)Dy)Uh=RAu&*Rnq4neTDHpFNLyGQgiab3N%%d^C!`dggf| ztj~HDd9DE!Uz7)ZE*}-rwt4Ea7X2c2gYq+!{U~`u&LHQh!A7SK+(i`Hp8m6U1{Ri=5-_?4cL6ArKLOdAW$IVO5)6?|{tWWDh z&=m3dl&_4|#v=Hjmie8L0sWVnP0d$9sbAh`HL+fU4<7Iu-ahDshkaN0n!^X9?Q-@s z_+XL0s(%xFFfw>H&;UMI6s{WH1RpF)sT%EHxP>X1^`S#D zN#cs)H{`SzRh&6)C*-9c;(kOj{Ix7vFnkNBQA* z&k|25o{N4d4jyFvNhiVxKLNPPOB)(Z)S{h=?zlEnX{y0tMVb#7N0*~ewTBv6Wy)M z`kYG_IqyRE!=7=TM1KB0(nQhuEx1Yt-{8{=fUkM(^IYNL<=|et3$@;dwdVm3V0~EN z$DT2s5cs8MYE(XmK9RqF6;|NQ{Je_xk>@T@_(0+bVjoEUQq?i2x`y`px6!($b#y(< zXB{?XlA%U^8~LJnCXKFG)#o66kvq&D<{9{)hV`j=5A>Hlx3%uPl-GRKedFMRC+u78 zci@9}{XLkZM*TssT5v3Ua4_5}`~`e)D5ZDG@jUn-8~RFqLFx~rZ$ai-NL*3k2;w*7 zZ72NIkIbzf#LvH*Y|Lo(uZi{}l!^OerOEQ$##;6{pgkA0A455?lOMwWzW5y-wP1W$NN78z6h87ngh3EZT!Z1m$LTw{nv>$TnQ?9;RQeQ zJnTsUf5M(nc0>WP5tTq?k0?JP+vS7S+L@^RI*NG4e4ZmeHEBN*VFHy^uHvUbLfykKGOZ#1^T~Z4y6+=-pBBpHOb149N6b=;av}Y>&{Ku zW_Pzw!v{b5$I|(XUJKq8Tn-eny!yDscqy zAH`mjIJ3l+a@q-r@R#(V3m=HT*Ur`Zx48Dc$kmeCzNo!dkSL+@>nx%L*Mom}mU>Eq za_&W5AM%X$1bF@?Q9cb+bk7fNgRZBc>lVEH@4<~o?JvRgSog=kXTeXw4Md4P2RGqm zeht2e7x)Xf8-B>g=e*?^9F-$ST>0{Ys~@h!i>=7d#V)OiUg*GD>>0^FNc`YC?Li`# z@%p8~ZvCsuH*SRf*~TW_2i@1x9o-)+PCQw~5hZ@~xjD&9gAck{x-|g|dY4(rivHf- z-hH5EkM!+C9=valuzk?q4lMSEi5r-qalu#NgT%y@;Z*n_CH0Avg7AUNx5>>1l6RK6 zG?`N={msG$alau}pCtBTZaX2jevo*Z*iko8<#8|jqT+SR?~-^;GX8pP*5a@I=2_?| z$@+xn5l>O@2M_%$luu#(@Cy!08ju1WGt6ZAxV z2=rI=t9!sERHqh$?)!|IR5r)!6DLx4un>80#_fY1MYX|v_@ETsE2W^n*EiYw64Ih*WyyPzhA4uPOrNrIQdD~S|Uro9068WGE=UD32r4Avd|5%KlpKmY5 z=Fa7`6I8spha2aUcz#`~Hk7}o;&N?4iQk1>Kko|HZx_E!^!=e`&}yf&;OV6 zE_4^Vt{_VI2J~D))aMm&5njd1;6kjr9pGZtyTD~c8TNw0C(ja9R&ru1a^YuC?1qnA z`%>hA@TtTdl^?6(%@Ws?JeTCZJ!BPC9osEbCDsGy)BW}^cvc@4?ThMa9Mda7|F4ZU z#$vFhdBP|G{iUzTw$?}e#Ye45);jn=`r1nSp79od{$=dfeIE3I&a~yq@Ij-%$Nrn( zgX==?2LsH(xGnLEa8u-g%*DxD9>ngGk^5sxy7$FMd|Bq6iQgdhVs1M@=7vgMNAfbY zT)VHV8{d<2JYb3acPMoNxWkTdB^8@{(UOZ>s7M}^xr_#Xb;%cd(xsOKA}0?tyjYbGABvu5_<>E`8&Y} zjY9cCmEnUSi3Jkxg%5_O8mWCQAP*$ZBz0*r|4RCtrN1$!|0sULRT1KAZhTSf1hM-i zuTz8Q$vx~xY2x|H?vwbQm+YX@`{IXv=b0Imw_@+T;~DBP`S~kE3zfcC=U&leEmGtN zxYEFw@MsC;@XmjUgO$_s$T79{(ponI0t(7rS9M!a1Y&%tHEoGC-uvqyVNCy z&DnH3QIBFKneE_%SIjPpi?L*)DAv)JTa0u5k6RwdQIxoOXP#H&{y%nwV=cmrSDz*hTQg|(u-qw z-=?nJU)_!ONPb4_K0{j_jqjat<8IqyPG zMQ=stiJa1f-~_zNdEj`W$B*S$PlWpxv7Uzau?n1nyioE%^o0DK7vSC>dA`r}GsRyx z>&7Efs9LMT_f~NYU_E0e83yX6 zj0(mBU^?APzkq|x2p#h5i#f&&!3VcmC(S|N32T&f3Vgy_&N~Y}c-)ud>i{40!zvg6 zAGG$LiOxsb7^u!94B||oYeNsg2RjoRBt8ir>`85$x*9%^x**Na^z@?PY-qN6(J z55rZDgX6H?XM+!t9heS|Ld#6efe#WDp27Md_~KD;GTDNq;B2hYb)b?fJ3+B4#jjLx z2LrmQ@2lcb5}y{mCi+h70;zM`=hhua99imArC;)lK9tBZ^)JSeXubLoqZysC=ySKf zaguqxxfnk9#e9qjI`mC39cc)?a06Yovj3m<%++BbE74nB}LlHvnZk0kfbNne}rfy9$?`;Wr^q8H^{ zNSrmv&Ett(t?a%`_VEiho-2C)RkHZX-dA?nPtZZhePy?czMoIF;04w*$PzsRPIAxl zSeNdK-cxw~09k|a;83ywW20Cyio1pu@rYahUfAt>k-nCVdUYbp_;JQ8{ReQAaW*

*n{Ro25w& z?0$*&s60+ObXIaz#qr;zYD2~8MDK4VTkswGE$2}5^jx9`8+k70UgY~|=su0-Lf^qi zmyxUoz-7b0`^g#&&9RoB3!f;t@CZK_ewvMRf0niA8<9iu{XQnXtm28vE>L+X$zN5Z zdR_TDZQQ)4#0#FMEAn-otNw_yU^%3JIp{r!Jg*Pz?C za;IsV&EbPhW(V^dumo0NW9TpQ6mRk#v}z*Hdev=>r?%v%?|Ao4)^oJAhUoXnhjp!%N0@0WPL)N_d6 zCw7zMcYbj5I-d~NPi8;f#_m({Rs21P+lZgH2!Brbbt0!HlO0~dTF&oqqWTZB7P|I_ zy9TrFN7Vm*u#cyhr(YC{d+u|e4*-QfL{11F$mc)m^4m(HSNr*Wi9bl(K;l)(pDDxl zzsk*LO5K6fE6#T7A;nKr{Z1D2zDYkw<~g2MJfZiF_BTqrV5d=;P8KyMCpJf`pLw-; zKlI;^HK0NN>h3(nomLy`UDo0!RH2{I2mOnaP52&s&mJC)A06;__kRi>Gzq>DC`SC~ z^U$PF8hmh9(npD<;e*a;pQKiB`JfJT&CLhW->CZD%kguGFH5{!{QmO9`&+Xg#i#~u z2&z1f^7|67j#Ru)|?5;vet-9UK(=nNB9v&$c2|7CxAeba_%U_+V<9mUinU@`1`bwxZg4Fz+w< z9`XAn-Y@w!@%v7AW<=wCB1a`(BXKzu&;5-3UBS8A2a3I~{5$2xDf>;?^&{XWrN;-k z@?M>Hb*_c(-N_brW!)7m(+TVXcFeKvjy0!#-U~kI4T{_thTSlZwX!GYfRB(hehL)( zP{ofvVZ9qaRmGFld#HTlY3y2+w-$Rx;-3;foaFOV1CFCA zxiNgu*uKoZ9zL-AYwc|4ALcfe6zqb>5RDt;pM8ItFbeC`|MXH-7#CGt4xT&+Wk9t9_+v#J)rP`k|RnU zD7`WPRQ}|AP}v3RLE%efr+mv=@>3GW6gx-dmmBe3A{Ql2{utfx&+=UQ+%%#?s&7{5 z1660D=46ZlztFoy%khq@$f{sn_e;EA>NF0y`Fe@JN<4NA@%oS1 z*QLaD_kiN3E4{4zHSyy_?%zk1$RM8I>xs#AIqyREyRp{p;OFhB9%z*V<+=Jj#SdNK zgU(=Yq*EVoAok;MQ2a>w`=SpdZnT5^#2J21>JlVwDD@3_#fzTN>PPDjKXdzEuj14f zgYK$-?RM}PqQ!H;D~z%FC!owhdDpnfm=l&+}!O7q~!KdJZmf>GR z1L1=!k_RPig%3OhA4uDtiw|y$bI5tYYF{RspG5*YUKG<9iRC9a!zEw#P5?h ztl0hHhbg;H+2azw5xqYcX*-JNO5ZCxuLtK|>32ETLf>{&g|y^(TdGEyMbYPJ3f{@O zIVgOg=of-i5E$JvyfY#D)mMZ zFO_=v9d1ADZ*D(hC8nNKgx*8xT2=mm(g$n6;$#iZg3L}e8bkjx?z{_`r#Zo_f@Hw2 za_6Hpv`#Q-m$;AB-ueJ+M|Xmnw=VZJ<+J)z+R*vWFHu$KGV$2xvz0BgC=Q|@z>xok3zN!{n#irFAdUn}u%neQfXaEW_K98~J-)~DQ(@(T4Bn|tk_VFdVyPRE{GiOmXq|F~ z8^G!N_d^P$DPysf4SFlpVK0GkJr;q#ppeL)15-jNPeDsKDWGYE4QEiV)T{w zmHT`oZY6%I;t?$B}KE1s06x%n7A zruup=`ylsQzvJA-PNRpp75!0A?k|^n>SfN9%%_j@b8IfL>Lahl|C4z`lGm4bt-P<| zW963%A76;B@}4TsEB8wZJte=B`#q&TNb1U^ZcOSEiU-#FOCUGy4HXI9%RX#Q?!=9+ z=(9-v$Y}QAW9Kez+99vSeeREgk2r;+_qWL$R-wDpyUP6xGJjL*StMU2=T_>QB#)i@ zyyoU#c~7Z#QSVuh@1ycr3gtcJ{Zt)HD$k`JM(U^~55CEFt#2T5bh2H|UWOdq<-gPa z9&)r~XnXK?B|npkC--L`8brR%yqA60#(kD6`MgJ+63%!~?yHges)X*>JF)wQg}#!P zk#ig8`eq8E6`Y<)8GkT?-ZlZ%pX9uXToSs*`8ReyW}Ke#o`1cE=VI?Cb+I`y%>GIJ{3NE1u0X#^U+`gX2PVnH z<8Vd&JMD(-gUp}(DyenSBJ^m{$j;1$?1Sh(HJ7|2pDXv3NjzTOU*22JtJHPJ&uMI4 zK%8&Sf6pX7KR5mIdM|lDL8<$aelo!?&8bXoj@LDAvu=;h11L(_Q4<7kXfC5c)&57K72os1JeH@=Uvq$s5(~RXQ6A(bD7M~ zbMtA=_fz$2@;-ujy_dXS{2m6m7w50{G4!Adup4%lnrHtyDD^yjnL;|1eM!grQuiL! z@NFf78?(36eI`o-*9NAs4~3HECH_i0K7V9IW;ynumvc7C2ht}j_f(1gQs=q|?;-D< z7d_?u6smq7c^|>}d;Rr&q^>VFN`J_CXpT2t!yYYfzG;}ee>bYy?g2M3y?|;zajguC$UlDYWCq|=Df@Z`yl#I`lJ;fl;u6d4iowd zee-_L3%}oa@8Qn1m%iys#WC39YL4+n;~HZCm|*sb-h)uy+;14Xzs!@6xgrzE-z;Z8 zCVNx8!`TPN-s(F8UzmXf+>A+FE745s$3C3MoRL|SeUN)>WsZ#4Glk&;RgWQhC{EYd z`^MidR=0n#_lfuYNS*(sVZfM9r3>>5jHj5uLq33czG{B!0wc-j0Oli~^&D8wJZW6Z zeylND(pf&)?a97&%cp@f{}j6Mx8@n3={t$a#>s zlhiATT_*ZS_*UNc;_r3-9Nqx?D*Y}O!}WUA=p0j3|EuN{ex$c&q8)ai@sR!*D08S* z7=?|l>_dvV!1x#(%G9Z`>_ejUJU8X=`|drOYkV2LzU;$%e`WuA_92|OBAmiL9L^k< znaDnfeIWN1EBj8#Md|BM=RxVG`1}8N=ZbdMPic4Yo;~#6qIJ*%-8oFt=$0JG^UeB= zOm;&qlJ7nU%3S!5jV4S8Cm&&6ZdPL->{&e1nB$p(4n&MB)z*JuUSx9A@c>ES)7`soG= zzxavbe8YOC;Wb*b57(G4BT0yZa+~5w@Co8KFR>3|SIPZXAB1~{kFyW&We(5uu@91` z5r08X}AAH z?BTrjLEhs(MVV*!DyQHBPb|K_50v>;QZFuZ&gAzC5ZzOGz&gycyAfQ%e9Ng|ma!^2 zFaHPQE@K6JF_AiuMeM^Ms>5fo52@U@{WJ2iuKze40@TTeyM&Lh4{v1-&NSEu(G%CQ z52}tU_dev75C7@=%lseJFSV8Tp5gY{KjhB)QT-DOcs_>dpo>76&!OU1+D4ugWR($^5Il?VmKfAVt?kqOb`1Y z^zXt4w^j~i?DjLJthf!u(a|--0(kc?Io3HMB!5c(ANMChY;?v>6?882H zAEYlP_dbYUEPkNaQKC04whz+(+*vE2jpO@D9ZWg5&t2s~8}MA}AXL9=71pY*Sk=R- zzKB|&4nX>Tq&`mG_l(=`A$=B7 z|0(tM5-*qj{hG{$>B_!Hf40n(l)2HT^ucuK!xzTw(R)LdP&K`Web{6*WzsYGI-l)p z%RcP%xAnivK0J_UB=&LlL7fZfqn3S;xRJyWr0?Z?IT5pqg)gN4N$MYk&t-0f)VoUF zL;6&uu2A|K<+AO6MG#9E2VE^sa+J}mJA}RK?1RWjkq=@=NxVto!4mHkIU(nxgFC-W@;j3ER`o8bE=cO! zB+o7NZBlP6^^MEvQ&D{llK+xASgDVe`dKwENu3LkyD}$t7E>w4zz1@_PBm`jEyQ^+ zkP21Uhx*?4qjh33-@0$$5C1*vL!+dWzd48$uUhVc>EOh&Iq~1>IdnDg0`F~Z9{R8_V{lJn}ZR*YwdXlX9Hugj2dTrx& z05#`vmf02n3zL$PIN~@`h$bIt{Qp=r>gNqwMiEV!|!@gSho_ z_CeK&9)%xHCf$?tWON^fMD0n5LyDgz@n^9kr2a$6z1w+T%kA?JIVN@ek|&iq?kUt? zFXMeAzb<)JRmZ3Dx~jfM)%8hzuG9laU$4vqDeKOakU11Gf10}pb=7wvbu=d4_8#^@ z&4EA6J}k7Zw>Gj5>K^j1*@x{|)4#C~QXdyd-jZ~heRwBxXw<(Dds6a;l4p^=2g!R& zzFX?sB`+-X%+imf>Q_}Ay1ci_WA|q*bttk{^@*w;N%l+n*xq*Q(hInKs}0<~%SGJA zun9WIyaJhXD09)vn0vX2jrtDrAv2NpKVj)Qmj-t%T5AAhyyano+RE~r(qo?MT( z{Q>+ei*q6SAot%$zpvDL%e)Pl(;;=UQa`8atk?2BDvv)Ml)5Xa$GXR@%aQsW*$=7r zk-iVr|9hPOFZp&k5BIos*lz7kIuP-P-1{j$)Z0bx9a@T1>;fOC`)O}tAN|MnKaOw`-c?>fD|5UI`@M-cF4>84a4*T$K<^!2t_Ce}jZgS^ZNxiGoxvKisB>uki ztFNLe;w`?f^eGK@`CHYSsJf-j{C0b=J>Ac@g6%+6w;=T?Qm-g=s!|s#`z!M^D!cRZ z#D4sqKIPx|9)0La@635fa_h~%G1?kS*au}tPh}r!S;x$->_aQ2SvFxG&iQ)y*1``R z{g?Y6gdZ|Pn}es=hv&)bonRl{&m0krKgfQR%zAN5k-w7n`8GT%d1bG{wN znFRKBevfnlTXNrTV=(s|UYVzKjU)Fy$MWG~7fYUB?82P+7L_mjz#e7$*`KOJBRcRs z?#sM7a{%9CmHYlZ$b#R^?@3*Pk{_yWQpItv0n>@!Wq|TtVt0w275hu_kYb;U9n#AC zd6Zta*!k@1R9+#}H1sO@*G8H7Gpq1DB)?df`_60fca;2gKzT3GW8xP}UO_%z>^`xB zbKhUSpW7H!J+g{dsd}R|?mf*Jp-sV)@JqSOeHl96L*m$_+?GIsGj zM6Zi|8~+}c7B^OY`cKH0x3z9ecw?@KJD)wBDF_*Sk6rHlfHt>z?&JHcwr;XshCaRM zTkXjAxH5Ba#*2Ip<$sjo{c?W~@w4(mncF4vT6(&3{zkfUJ7oT=#2Y^~T14-wUSMTg z&+$Em1@u5~zQ^U6_h)S8dx+eT_=xabUVr}qcRqD}SO2QHb4}O>nIj={E>$1EYM!^E zy1NPca>VWT+H5tqUgvxKIY&OTf5!7UzK8IK_#46>@_jlHEgHk;ivATpTl^=n7u7t) zn*82_R2e=F%KRGL9K}r;$a`z5bp_`|`a~{AifwV}QX0C5ToQR8@e#5A)O^Moe6Gx2 zl73q0qmua>QYSBSBUPSY1p85yDM_iEm-gOot=sq>n}XK{2XbzOKg1sqKScZwnKvPJ zhx8Fjeclwh50)2*_y4Lo<6l{;ID@KBe39z=w?LWmC~+mp|g137C&F+l+0weSMztozLPp-Wyh)SBYh+{(l6bazkh{3he^idxi}@op~pe) zMYrLLzP=OQYUtrzJ;eT!xwz6-CH*t1PhtUoN7cpl1Upit-Ubvq zLh9-z{xVccjn2JN_qE;1_ju2(GnM<(412V1H{av8(85qj^qeqtv}E_FRcoYfIk z&m#3XqW^>si=AE;5cPdAsk zr!L}tj@Ui&{Ux3%eTw2=iaq=d_olth=VaI$eZTTKWip;gFTnRH?$SZ(bS3_v_(R#F zs=r><-S>biABI2G{1O#!{KOt_Cqb|5j7{k_pED@q=k(g3)agmQKO{&|Te;Qt51B9Yht literal 262276 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 Uw|7SP) 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Ž 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%0AUO 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 From 6eac6d767b6cfed29eb3b6c744d2667bc528dcf2 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 28 Mar 2025 14:05:03 +0000 Subject: [PATCH 43/47] cleanup areas checking for named tex target in materials --- Engine/source/materials/processedMaterial.cpp | 2 +- Engine/source/materials/processedShaderMaterial.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/materials/processedMaterial.cpp b/Engine/source/materials/processedMaterial.cpp index bf172bd7e..ea2a0aa86 100644 --- a/Engine/source/materials/processedMaterial.cpp +++ b/Engine/source/materials/processedMaterial.cpp @@ -398,7 +398,7 @@ void ProcessedMaterial::_setStageData() 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. - if (!String(mMaterial->getDiffuseMapAsset(i)->getImageFile()).startsWith("#") && !String(mMaterial->getDiffuseMapAsset(i)->getImageFile()).startsWith("$")) + if (!mMaterial->getDiffuseMapAsset(i)->isNamedTarget()) mMaterial->logError("Failed to load diffuse map %s for stage %i", mMaterial->getDiffuseMapAsset(i)->getImageFile(), i); mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile)); diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index c1bab8dfa..98a9e569a 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -229,7 +229,7 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features, mInstancingState = new InstancingState(); mInstancingState->setFormat( _getRPD( 0 )->shader->getInstancingFormat(), mVertexFormat ); } - if (mMaterial && mMaterial->getDiffuseMapAsset(0).notNull() && String(mMaterial->getDiffuseMapAsset(0)->getImageFile()).startsWith("#")) + if (mMaterial && mMaterial->getDiffuseMapAsset(0).notNull() && mMaterial->getDiffuseMapAsset(0)->isNamedTarget()) { NamedTexTarget *texTarget = mMaterial->getDiffuseMapAsset(0)->getNamedTarget(); RenderPassData* rpd = getPass(0); From b707b2e2b78a5b46e0cef4a855cd94d018e8e42d Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 28 Mar 2025 15:32:16 +0000 Subject: [PATCH 44/47] final rev add safeties to getters getTextureBitmap/ functions to return member variable that is collected when the image is set --- Engine/source/T3D/assets/ImageAsset.cpp | 9 +++++++++ Engine/source/T3D/assets/ImageAsset.h | 13 +++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index f55cae0d9..04ff2e11c 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -153,6 +153,7 @@ ImageAsset::ImageAsset() : mIsNamedTarget(false), mImageWidth(-1), mImageHeight(-1), + mImageDepth(-1), mImageChannels(-1) { mLoadedState = AssetErrCode::NotLoaded; @@ -423,6 +424,9 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) Con::errorf("ImageAsset::setImageFile STB Get file info failed: %s", stbErr); } } + + // we only support 2d textures..... for no ;) + mImageDepth = 1; } refreshAsset(); @@ -643,6 +647,7 @@ void ImageAsset::onTamlCustomWrite(TamlCustomNodes& customNodes) pImageInfoNode->addField(StringTable->insert("ImageWidth"), mImageWidth); pImageInfoNode->addField(StringTable->insert("ImageHeight"), mImageHeight); + pImageInfoNode->addField(StringTable->insert("ImageDepth"), mImageDepth); } @@ -676,6 +681,10 @@ void ImageAsset::onTamlCustomRead(const TamlCustomNodes& customNodes) { pField->getFieldValue(mImageHeight); } + else if (fieldName == StringTable->insert("ImageDepth")) + { + pField->getFieldValue(mImageDepth); + } else { // Unknown name so warn. diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 12538064b..9844b92b2 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -141,6 +141,7 @@ private: bool mIsNamedTarget; S32 mImageWidth; S32 mImageHeight; + S32 mImageDepth; S32 mImageChannels; void generateTexture(void); @@ -186,13 +187,13 @@ public: void setImageType(ImageTypes type) { mImageType = type; } ImageTypes getImageType() { return mImageType; } - inline U32 getTextureWidth(void) const { return mTextureHandle->getWidth(); } - inline U32 getTextureHeight(void) const { return mTextureHandle->getHeight(); } - inline U32 getTextureDepth(void) const { return mTextureHandle->getDepth(); } + inline U32 getTextureWidth(void) const { return isAssetValid() ? mTextureHandle->getWidth() : 0; } + inline U32 getTextureHeight(void) const { return isAssetValid() ? mTextureHandle->getHeight() : 0; } + inline U32 getTextureDepth(void) const { return isAssetValid() ? mTextureHandle->getDepth() : 0; } - inline U32 getTextureBitmapWidth(void) const { return mTextureHandle->getBitmapWidth(); } - inline U32 getTextureBitmapHeight(void) const { return mTextureHandle->getBitmapHeight(); } - inline U32 getTextureBitmapDepth(void) const { return mTextureHandle->getBitmapDepth(); } + inline U32 getTextureBitmapWidth(void) const { return mImageWidth; } + inline U32 getTextureBitmapHeight(void) const { return mImageHeight; } + inline U32 getTextureBitmapDepth(void) const { return mImageDepth; } bool isAssetValid(void) const override { return !mTextureHandle.isNull(); } bool isNamedTarget(void) const { return mIsNamedTarget; } From 73ad92b7578ab81b8ec1b2246a3c2e00c5627261 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 30 Mar 2025 11:22:42 +0100 Subject: [PATCH 45/47] review notes from Az Should render fallback for namedTarget if namedTarget fails Add safety around namedtarget getTexture to stop assert Missing assets should revert to fallback image and print a warning to console Remove REFACTOR tag from all macros. --- Engine/source/T3D/accumulationVolume.cpp | 2 +- Engine/source/T3D/accumulationVolume.h | 2 +- Engine/source/T3D/assets/ImageAsset.cpp | 18 ++++-- Engine/source/T3D/assets/ImageAsset.h | 34 ++++++++--- Engine/source/T3D/fx/particle.cpp | 4 +- Engine/source/T3D/fx/particle.h | 4 +- Engine/source/T3D/fx/precipitation.cpp | 4 +- Engine/source/T3D/fx/precipitation.h | 4 +- Engine/source/T3D/fx/splash.cpp | 2 +- Engine/source/T3D/fx/splash.h | 2 +- Engine/source/T3D/gameMode.cpp | 2 +- Engine/source/T3D/gameMode.h | 2 +- Engine/source/T3D/levelInfo.cpp | 2 +- Engine/source/T3D/levelInfo.h | 2 +- Engine/source/T3D/lightFlareData.cpp | 2 +- Engine/source/T3D/lightFlareData.h | 2 +- Engine/source/afx/ce/afxBillboard.cpp | 2 +- Engine/source/afx/ce/afxBillboard.h | 2 +- Engine/source/afx/ce/afxZodiac.cpp | 2 +- Engine/source/afx/ce/afxZodiac.h | 2 +- Engine/source/afx/ce/afxZodiacPlane.cpp | 2 +- Engine/source/afx/ce/afxZodiacPlane.h | 2 +- Engine/source/environment/VolumetricFog.cpp | 2 +- Engine/source/environment/VolumetricFog.h | 2 +- Engine/source/environment/basicClouds.cpp | 2 +- Engine/source/environment/basicClouds.h | 2 +- Engine/source/environment/cloudLayer.cpp | 2 +- Engine/source/environment/cloudLayer.h | 2 +- Engine/source/environment/waterObject.cpp | 6 +- Engine/source/environment/waterObject.h | 6 +- Engine/source/gfx/sim/cubemapData.cpp | 4 +- Engine/source/gfx/sim/cubemapData.h | 4 +- .../gui/buttons/guiBitmapButtonCtrl.cpp | 2 +- .../source/gui/buttons/guiIconButtonCtrl.cpp | 2 +- Engine/source/gui/buttons/guiIconButtonCtrl.h | 2 +- .../gui/buttons/guiToolboxButtonCtrl.cpp | 6 +- .../source/gui/buttons/guiToolboxButtonCtrl.h | 6 +- Engine/source/gui/controls/guiBitmapCtrl.cpp | 2 +- Engine/source/gui/controls/guiBitmapCtrl.h | 2 +- .../gui/controls/guiGameSettingsCtrl.cpp | 6 +- .../source/gui/controls/guiGameSettingsCtrl.h | 6 +- Engine/source/gui/controls/guiPopUpCtrl.h | 2 +- Engine/source/gui/controls/guiPopUpCtrlEx.h | 2 +- Engine/source/gui/core/guiTypes.cpp | 2 +- Engine/source/gui/core/guiTypes.h | 4 +- .../source/gui/game/guiChunkedBitmapCtrl.cpp | 2 +- Engine/source/gui/game/guiChunkedBitmapCtrl.h | 2 +- .../source/gui/game/guiProgressBitmapCtrl.cpp | 2 +- .../source/gui/game/guiProgressBitmapCtrl.h | 2 +- .../source/gui/worldEditor/guiMissionArea.cpp | 2 +- .../source/gui/worldEditor/guiMissionArea.h | 2 +- Engine/source/gui/worldEditor/worldEditor.cpp | 6 +- Engine/source/gui/worldEditor/worldEditor.h | 6 +- .../source/materials/materialDefinition.cpp | 48 ++++++++-------- Engine/source/materials/materialDefinition.h | 24 ++++---- .../materials/processedShaderMaterial.cpp | 57 +++++++++---------- Engine/source/postFx/postEffect.cpp | 2 +- Engine/source/postFx/postEffect.h | 2 +- Engine/source/terrain/terrMaterial.cpp | 10 ++-- Engine/source/terrain/terrMaterial.h | 10 ++-- 60 files changed, 189 insertions(+), 164 deletions(-) diff --git a/Engine/source/T3D/accumulationVolume.cpp b/Engine/source/T3D/accumulationVolume.cpp index dfada6d06..682125ef5 100644 --- a/Engine/source/T3D/accumulationVolume.cpp +++ b/Engine/source/T3D/accumulationVolume.cpp @@ -93,7 +93,7 @@ AccumulationVolume::~AccumulationVolume() void AccumulationVolume::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, AccumulationVolume, "Accumulation texture.") + INITPERSISTFIELD_IMAGEASSET(Texture, AccumulationVolume, "Accumulation texture.") Parent::initPersistFields(); } diff --git a/Engine/source/T3D/accumulationVolume.h b/Engine/source/T3D/accumulationVolume.h index 53c24843c..0c5fe4fe1 100644 --- a/Engine/source/T3D/accumulationVolume.h +++ b/Engine/source/T3D/accumulationVolume.h @@ -61,7 +61,7 @@ class AccumulationVolume : public ScenePolyhedralSpace // SceneSpace. void _renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat ) override; - DECLARE_IMAGEASSET_NET_REFACTOR(AccumulationVolume, Texture, GFXStaticTextureSRGBProfile, -1) + DECLARE_IMAGEASSET_NET(AccumulationVolume, Texture, GFXStaticTextureSRGBProfile, -1) public: diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 04ff2e11c..e26533524 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -484,16 +484,22 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) if (isNamedTarget()) { - GFXTexHandle tex = getNamedTarget()->getTexture(); - if(tex.isNull()) + GFXTexHandle tex; + AssetPtr fallbackAsset; + ImageAsset::getAssetById(smNamedTargetAssetFallback, &fallbackAsset); + if (getNamedTarget().isValid()) { - AssetPtr fallbackAsset; - ImageAsset::getAssetById(smNamedTargetAssetFallback, &fallbackAsset); - return fallbackAsset->getTexture(); + tex = getNamedTarget()->getTexture(); + if (tex.isNull()) + { + return fallbackAsset->getTexture(); + } + + return tex; } else { - return tex; + return fallbackAsset->getTexture(); } } diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 9844b92b2..6dc97f933 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -241,7 +241,7 @@ DefineEnumType(ImageAssetType); #pragma region Refactor Asset Macros -#define DECLARE_IMAGEASSET_REFACTOR(className, name, profile) \ +#define DECLARE_IMAGEASSET(className, name, profile) \ private: \ AssetPtr m##name##Asset; \ public: \ @@ -268,6 +268,11 @@ public: imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + imageAssetId = ImageAsset::smNoImageAssetFallback; \ + } \ m##name##Asset = imageAssetId; \ } \ else \ @@ -282,7 +287,7 @@ public: static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} -#define DECLARE_IMAGEASSET_NET_REFACTOR(className, name, profile, mask) \ +#define DECLARE_IMAGEASSET_NET(className, name, profile, mask) \ private: \ AssetPtr m##name##Asset; \ public: \ @@ -308,6 +313,11 @@ public: imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + imageAssetId = ImageAsset::smNoImageAssetFallback; \ + } \ m##name##Asset = imageAssetId; \ } \ else \ @@ -323,11 +333,11 @@ public: static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data)); return false;} -#define INITPERSISTFIELD_IMAGEASSET_REFACTOR(name, consoleClass, docs) \ +#define INITPERSISTFIELD_IMAGEASSET(name, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); -#define DECLARE_IMAGEASSET_ARRAY_REFACTOR(className, name, profile, max) \ +#define DECLARE_IMAGEASSET_ARRAY(className, name, profile, max) \ private: \ AssetPtr m##name##Asset[max]; \ public: \ @@ -353,6 +363,11 @@ public: imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + imageAssetId = ImageAsset::smNoImageAssetFallback; \ + } \ m##name##Asset[index] = imageAssetId; \ } \ else \ @@ -368,7 +383,7 @@ public: static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} -#define DECLARE_IMAGEASSET_ARRAY_NET_REFACTOR(className, name, profile, max, mask) \ +#define DECLARE_IMAGEASSET_ARRAY_NET(className, name, profile, max, mask) \ private: \ AssetPtr m##name##Asset[max]; \ public: \ @@ -394,6 +409,11 @@ public: imageAssetId = AssetDatabase.addPrivateAsset(privateImage); \ } \ } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + imageAssetId = ImageAsset::smNoImageAssetFallback; \ + } \ m##name##Asset[index] = imageAssetId; \ } \ else \ @@ -410,10 +430,10 @@ public: static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;} -#define INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ +#define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeImageAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); -#define DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(className,name, max)\ +#define DEF_IMAGEASSET_ARRAY_BINDS(className,name, max)\ DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\ {\ return object->get##name##Asset(index).notNull() ? object->get##name##Asset(index)->getImageFile() : ""; \ diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index 1f6c3685e..b2457dfea 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -148,7 +148,7 @@ void ParticleData::initPersistFields() { docsURL; addGroup("Basic"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, ParticleData, "Texture to use for this particle."); + INITPERSISTFIELD_IMAGEASSET(Texture, ParticleData, "Texture to use for this particle."); addField("useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData), "@brief Controls how particles blend with the scene.\n\n" "If true, particles blend like ParticleBlendStyle NORMAL, if false, " @@ -233,7 +233,7 @@ void ParticleData::initPersistFields() endGroup("Over Time"); addGroup("AFX"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(TextureExt, ParticleData, ""); + INITPERSISTFIELD_IMAGEASSET(TextureExt, ParticleData, ""); addField("constrainPos", TypeBool, Offset(constrain_pos, ParticleData)); addFieldV("angle", TypeRangedF32, Offset(start_angle, ParticleData), &CommonValidators::DegreeRange); addFieldV("angleVariance", TypeRangedF32, Offset(angle_variance, ParticleData), &CommonValidators::DegreeRange); diff --git a/Engine/source/T3D/fx/particle.h b/Engine/source/T3D/fx/particle.h index 033a864a4..e1ead31af 100644 --- a/Engine/source/T3D/fx/particle.h +++ b/Engine/source/T3D/fx/particle.h @@ -86,7 +86,7 @@ class ParticleData : public SimDataBlock StringTableEntry animTexFramesString; Vector animTexFrames; - DECLARE_IMAGEASSET_REFACTOR(ParticleData, Texture, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(ParticleData, Texture, GFXStaticTextureSRGBProfile) static bool protectedSetSizes(void* object, const char* index, const char* data); static bool protectedSetTimes(void* object, const char* index, const char* data); @@ -114,7 +114,7 @@ public: F32 spinBias; bool randomizeSpinDir; public: - DECLARE_IMAGEASSET_REFACTOR(ParticleData, TextureExt,GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(ParticleData, TextureExt,GFXStaticTextureSRGBProfile) bool constrain_pos; F32 start_angle; diff --git a/Engine/source/T3D/fx/precipitation.cpp b/Engine/source/T3D/fx/precipitation.cpp index 3d00ed805..9953b2228 100644 --- a/Engine/source/T3D/fx/precipitation.cpp +++ b/Engine/source/T3D/fx/precipitation.cpp @@ -142,7 +142,7 @@ void PrecipitationData::initPersistFields() docsURL; INITPERSISTFIELD_SOUNDASSET(Sound, PrecipitationData, "Looping SFXProfile effect to play while Precipitation is active."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Drop, PrecipitationData, "@brief Texture for drop particles.\n\n" + INITPERSISTFIELD_IMAGEASSET(Drop, PrecipitationData, "@brief Texture for drop particles.\n\n" "The drop texture can contain several different drop sub-textures " "arranged in a grid. There must be the same number of rows as columns. A " "random frame will be chosen for each drop."); @@ -150,7 +150,7 @@ void PrecipitationData::initPersistFields() addField( "dropShader", TypeString, Offset(mDropShaderName, PrecipitationData), "The name of the shader used for raindrops." ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Splash, PrecipitationData, "@brief Texture for splash particles.\n\n" + INITPERSISTFIELD_IMAGEASSET(Splash, PrecipitationData, "@brief Texture for splash particles.\n\n" "The splash texture can contain several different splash sub-textures " "arranged in a grid. There must be the same number of rows as columns. A " "random frame will be chosen for each splash."); diff --git a/Engine/source/T3D/fx/precipitation.h b/Engine/source/T3D/fx/precipitation.h index 676f7df31..96fe3844e 100644 --- a/Engine/source/T3D/fx/precipitation.h +++ b/Engine/source/T3D/fx/precipitation.h @@ -49,11 +49,11 @@ class PrecipitationData : public GameBaseData DECLARE_SOUNDASSET(PrecipitationData, Sound); DECLARE_ASSET_SETGET(PrecipitationData, Sound); - DECLARE_IMAGEASSET_REFACTOR(PrecipitationData, Drop, GFXStaticTextureSRGBProfile) ///< Texture for drop particles + DECLARE_IMAGEASSET(PrecipitationData, Drop, GFXStaticTextureSRGBProfile) ///< Texture for drop particles StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops - DECLARE_IMAGEASSET_REFACTOR(PrecipitationData, Splash, GFXStaticTextureSRGBProfile) ///< Texture for splash particles + DECLARE_IMAGEASSET(PrecipitationData, Splash, GFXStaticTextureSRGBProfile) ///< Texture for splash particles StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops diff --git a/Engine/source/T3D/fx/splash.cpp b/Engine/source/T3D/fx/splash.cpp index 5139f479a..3b3639c38 100644 --- a/Engine/source/T3D/fx/splash.cpp +++ b/Engine/source/T3D/fx/splash.cpp @@ -128,7 +128,7 @@ void SplashData::initPersistFields() addFieldV("times", TypeRangedF32, Offset(times, SplashData), &CommonValidators::NormalizedFloat, NUM_TIME_KEYS, "Times to transition through the splash effect. Up to 4 allowed. Values are 0.0 - 1.0, and corrispond to the life of the particle where 0 is first created and 1 is end of lifespace.\n" ); addField("colors", TypeColorF, Offset(colors, SplashData), NUM_TIME_KEYS, "Color values to set the splash effect, rgba. Up to 4 allowed. Will transition through colors based on values set in the times value. Example: colors[0] = \"0.6 1.0 1.0 0.5\".\n" ); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Texture, NUM_TEX, SplashData, "Image to use as the texture for the splash effect.\n"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, NUM_TEX, SplashData, "Image to use as the texture for the splash effect.\n"); addFieldV("texWrap", TypeRangedF32, Offset(texWrap, SplashData), &CommonValidators::NormalizedFloat, "Amount to wrap the texture around the splash ring, 0.0f - 1.0f.\n"); addFieldV("texFactor", TypeRangedF32, Offset(texFactor, SplashData), &CommonValidators::NormalizedFloat, "Factor in which to apply the texture to the splash ring, 0.0f - 1.0f.\n"); diff --git a/Engine/source/T3D/fx/splash.h b/Engine/source/T3D/fx/splash.h index 84ce47202..8ac072b9b 100644 --- a/Engine/source/T3D/fx/splash.h +++ b/Engine/source/T3D/fx/splash.h @@ -122,7 +122,7 @@ public: F32 times[ NUM_TIME_KEYS ]; LinearColorF colors[ NUM_TIME_KEYS ]; - DECLARE_IMAGEASSET_ARRAY_REFACTOR(SplashData, Texture, GFXStaticTextureSRGBProfile, NUM_TEX) + DECLARE_IMAGEASSET_ARRAY(SplashData, Texture, GFXStaticTextureSRGBProfile, NUM_TEX) ExplosionData* explosion; S32 explosionId; diff --git a/Engine/source/T3D/gameMode.cpp b/Engine/source/T3D/gameMode.cpp index db550b4f2..32776bc4d 100644 --- a/Engine/source/T3D/gameMode.cpp +++ b/Engine/source/T3D/gameMode.cpp @@ -62,7 +62,7 @@ void GameMode::initPersistFields() addField("gameModeName", TypeString, Offset(mGameModeName, GameMode), "Human-readable name of the gamemode"); addField("description", TypeString, Offset(mGameModeDesc, GameMode), "Description of the gamemode"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(PreviewImage, GameMode, "Preview Image"); + INITPERSISTFIELD_IMAGEASSET(PreviewImage, GameMode, "Preview Image"); addField("active", TypeBool, Offset(mIsActive, GameMode), "Is the gamemode active"); addField("alwaysActive", TypeBool, Offset(mIsAlwaysActive, GameMode), "Is the gamemode always active"); diff --git a/Engine/source/T3D/gameMode.h b/Engine/source/T3D/gameMode.h index 1efa9602c..465a614f2 100644 --- a/Engine/source/T3D/gameMode.h +++ b/Engine/source/T3D/gameMode.h @@ -21,7 +21,7 @@ private: StringTableEntry mGameModeName; StringTableEntry mGameModeDesc; - DECLARE_IMAGEASSET_REFACTOR(GameMode, PreviewImage, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(GameMode, PreviewImage, GFXStaticTextureSRGBProfile) bool mIsActive; bool mIsAlwaysActive; diff --git a/Engine/source/T3D/levelInfo.cpp b/Engine/source/T3D/levelInfo.cpp index 485223468..82d3b55c5 100644 --- a/Engine/source/T3D/levelInfo.cpp +++ b/Engine/source/T3D/levelInfo.cpp @@ -169,7 +169,7 @@ void LevelInfo::initPersistFields() //addField( "advancedLightmapSupport", TypeBool, Offset( mAdvancedLightmapSupport, LevelInfo ), // "Enable expanded support for mixing static and dynamic lighting (more costly)" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(AccuTexture, LevelInfo, "Accumulation texture."); + INITPERSISTFIELD_IMAGEASSET(AccuTexture, LevelInfo, "Accumulation texture."); endGroup( "Lighting" ); diff --git a/Engine/source/T3D/levelInfo.h b/Engine/source/T3D/levelInfo.h index d6a28155e..593910dd4 100644 --- a/Engine/source/T3D/levelInfo.h +++ b/Engine/source/T3D/levelInfo.h @@ -106,7 +106,7 @@ class LevelInfo : public NetObject void _onLMActivate(const char *lm, bool enable); protected: - DECLARE_IMAGEASSET_REFACTOR(LevelInfo, AccuTexture, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(LevelInfo, AccuTexture, GFXStaticTextureSRGBProfile) public: diff --git a/Engine/source/T3D/lightFlareData.cpp b/Engine/source/T3D/lightFlareData.cpp index 59fc369d7..0ee3821d6 100644 --- a/Engine/source/T3D/lightFlareData.cpp +++ b/Engine/source/T3D/lightFlareData.cpp @@ -159,7 +159,7 @@ void LightFlareData::initPersistFields() addField( "flareEnabled", TypeBool, Offset( mFlareEnabled, LightFlareData ), "Allows the user to disable this flare globally for any lights referencing it." ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(FlareTexture, LightFlareData, "The texture / sprite sheet for this flare."); + INITPERSISTFIELD_IMAGEASSET(FlareTexture, LightFlareData, "The texture / sprite sheet for this flare."); addArray( "Elements", MAX_ELEMENTS ); diff --git a/Engine/source/T3D/lightFlareData.h b/Engine/source/T3D/lightFlareData.h index 952d8f56a..e31c8c752 100644 --- a/Engine/source/T3D/lightFlareData.h +++ b/Engine/source/T3D/lightFlareData.h @@ -118,7 +118,7 @@ protected: F32 mScale; bool mFlareEnabled; - DECLARE_IMAGEASSET_REFACTOR(LightFlareData, FlareTexture, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(LightFlareData, FlareTexture, GFXStaticTextureSRGBProfile) F32 mOcclusionRadius; bool mRenderReflectPass; diff --git a/Engine/source/afx/ce/afxBillboard.cpp b/Engine/source/afx/ce/afxBillboard.cpp index 9e07ab51d..9134c0354 100644 --- a/Engine/source/afx/ce/afxBillboard.cpp +++ b/Engine/source/afx/ce/afxBillboard.cpp @@ -95,7 +95,7 @@ void afxBillboardData::initPersistFields() "The color assigned to the quadrangle geometry. The way it combines with the given " "texture varies according to the setting of the textureFunction field."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxBillboardData, "An image to use as the billboard's texture."); + INITPERSISTFIELD_IMAGEASSET(Texture, afxBillboardData, "An image to use as the billboard's texture."); addField("dimensions", TypePoint2F, myOffset(dimensions), "A value-pair that specifies the horizontal and vertical dimensions of the billboard " diff --git a/Engine/source/afx/ce/afxBillboard.h b/Engine/source/afx/ce/afxBillboard.h index 1884e6800..34e278206 100644 --- a/Engine/source/afx/ce/afxBillboard.h +++ b/Engine/source/afx/ce/afxBillboard.h @@ -47,7 +47,7 @@ public: }; public: - DECLARE_IMAGEASSET_REFACTOR(afxBillboardData, Texture, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(afxBillboardData, Texture, GFXStaticTextureSRGBProfile) LinearColorF color; diff --git a/Engine/source/afx/ce/afxZodiac.cpp b/Engine/source/afx/ce/afxZodiac.cpp index 88d9d9fec..2df200230 100644 --- a/Engine/source/afx/ce/afxZodiac.cpp +++ b/Engine/source/afx/ce/afxZodiac.cpp @@ -155,7 +155,7 @@ EndImplementEnumType; void afxZodiacData::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxZodiacData, "An image to use as the zodiac's texture."); + INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacData, "An image to use as the zodiac's texture."); addField("radius", TypeF32, Offset(radius_xy, afxZodiacData), "The zodiac's radius in scene units."); addField("verticalRange", TypePoint2F, Offset(vert_range, afxZodiacData), diff --git a/Engine/source/afx/ce/afxZodiac.h b/Engine/source/afx/ce/afxZodiac.h index 9163f2d4b..501dfc034 100644 --- a/Engine/source/afx/ce/afxZodiac.h +++ b/Engine/source/afx/ce/afxZodiac.h @@ -57,7 +57,7 @@ public: static void convertGradientRangeFromDegrees(Point2F& gradrange, const Point2F& gradrange_deg); public: - DECLARE_IMAGEASSET_REFACTOR(afxZodiacData, Texture, AFX_GFXZodiacTextureProfile) + DECLARE_IMAGEASSET(afxZodiacData, Texture, AFX_GFXZodiacTextureProfile) F32 radius_xy; Point2F vert_range; diff --git a/Engine/source/afx/ce/afxZodiacPlane.cpp b/Engine/source/afx/ce/afxZodiacPlane.cpp index fe59d9c0b..c57eeda05 100644 --- a/Engine/source/afx/ce/afxZodiacPlane.cpp +++ b/Engine/source/afx/ce/afxZodiacPlane.cpp @@ -110,7 +110,7 @@ EndImplementEnumType; void afxZodiacPlaneData::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, afxZodiacPlaneData, "An image to use as the zodiac's texture."); + INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacPlaneData, "An image to use as the zodiac's texture."); addFieldV("radius", TypeRangedF32, myOffset(radius_xy), &CommonValidators::PositiveFloat, "The zodiac's radius in scene units."); diff --git a/Engine/source/afx/ce/afxZodiacPlane.h b/Engine/source/afx/ce/afxZodiacPlane.h index 0ce187d89..9e7cef512 100644 --- a/Engine/source/afx/ce/afxZodiacPlane.h +++ b/Engine/source/afx/ce/afxZodiacPlane.h @@ -57,7 +57,7 @@ public: }; public: - DECLARE_IMAGEASSET_REFACTOR(afxZodiacPlaneData, Texture, AFX_GFXZodiacTextureProfile) + DECLARE_IMAGEASSET(afxZodiacPlaneData, Texture, AFX_GFXZodiacTextureProfile) F32 radius_xy; F32 start_ang; diff --git a/Engine/source/environment/VolumetricFog.cpp b/Engine/source/environment/VolumetricFog.cpp index ea742a656..05ee73da0 100644 --- a/Engine/source/environment/VolumetricFog.cpp +++ b/Engine/source/environment/VolumetricFog.cpp @@ -181,7 +181,7 @@ void VolumetricFog::initPersistFields() endGroup("VolumetricFogData"); addGroup("VolumetricFogModulation"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, VolumetricFog, "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation."); + INITPERSISTFIELD_IMAGEASSET(Texture, VolumetricFog, "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation."); addFieldV("tiles", TypeRangedF32, Offset(mTexTiles, VolumetricFog), &CommonValidators::PositiveFloat, "How many times the texture is mapped to the object."); diff --git a/Engine/source/environment/VolumetricFog.h b/Engine/source/environment/VolumetricFog.h index 80a349cb6..42f085eab 100644 --- a/Engine/source/environment/VolumetricFog.h +++ b/Engine/source/environment/VolumetricFog.h @@ -162,7 +162,7 @@ class VolumetricFog : public SceneObject F32 mInvScale; // Fog Modulation data - DECLARE_IMAGEASSET_NET_REFACTOR(VolumetricFog, Texture, GFXStaticTextureSRGBProfile, FogModulationMask) + DECLARE_IMAGEASSET_NET(VolumetricFog, Texture, GFXStaticTextureSRGBProfile, FogModulationMask) bool mIsTextured; F32 mTexTiles; diff --git a/Engine/source/environment/basicClouds.cpp b/Engine/source/environment/basicClouds.cpp index 83e38a11f..02286bccc 100644 --- a/Engine/source/environment/basicClouds.cpp +++ b/Engine/source/environment/basicClouds.cpp @@ -174,7 +174,7 @@ void BasicClouds::initPersistFields() addField( "layerEnabled", TypeBool, Offset( mLayerEnabled, BasicClouds ), TEX_COUNT, "Enable or disable rendering of this layer." ); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Texture, TEX_COUNT, BasicClouds, "Texture for this layer."); + INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, TEX_COUNT, BasicClouds, "Texture for this layer."); addFieldV( "texScale", TypeRangedF32, Offset( mTexScale, BasicClouds ), &CommonValidators::PositiveFloat, TEX_COUNT, "Texture repeat for this layer." ); diff --git a/Engine/source/environment/basicClouds.h b/Engine/source/environment/basicClouds.h index 8157212ff..1fb2d06e0 100644 --- a/Engine/source/environment/basicClouds.h +++ b/Engine/source/environment/basicClouds.h @@ -94,7 +94,7 @@ protected: static U32 smVertCount; static U32 smTriangleCount; - DECLARE_IMAGEASSET_ARRAY_NET_REFACTOR(BasicClouds, Texture, GFXStaticTextureSRGBProfile, TEX_COUNT, -1) + DECLARE_IMAGEASSET_ARRAY_NET(BasicClouds, Texture, GFXStaticTextureSRGBProfile, TEX_COUNT, -1) GFXStateBlockRef mStateblock; diff --git a/Engine/source/environment/cloudLayer.cpp b/Engine/source/environment/cloudLayer.cpp index f63893e30..f65782c12 100644 --- a/Engine/source/environment/cloudLayer.cpp +++ b/Engine/source/environment/cloudLayer.cpp @@ -190,7 +190,7 @@ void CloudLayer::initPersistFields() docsURL; addGroup( "CloudLayer" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Texture, CloudLayer, "An RGBA texture which should contain normals and opacity (density).") + INITPERSISTFIELD_IMAGEASSET(Texture, CloudLayer, "An RGBA texture which should contain normals and opacity (density).") addArray( "Textures", TEX_COUNT ); diff --git a/Engine/source/environment/cloudLayer.h b/Engine/source/environment/cloudLayer.h index a07e00c14..3f7dca6b4 100644 --- a/Engine/source/environment/cloudLayer.h +++ b/Engine/source/environment/cloudLayer.h @@ -98,7 +98,7 @@ protected: public: - DECLARE_IMAGEASSET_NET_REFACTOR(CloudLayer,Texture, GFXStaticTextureSRGBProfile, CloudLayerMask) + DECLARE_IMAGEASSET_NET(CloudLayer,Texture, GFXStaticTextureSRGBProfile, CloudLayerMask) GFXShaderRef mShader; diff --git a/Engine/source/environment/waterObject.cpp b/Engine/source/environment/waterObject.cpp index ac666a274..b18fc4037 100644 --- a/Engine/source/environment/waterObject.cpp +++ b/Engine/source/environment/waterObject.cpp @@ -296,7 +296,7 @@ void WaterObject::initPersistFields() addFieldV( "overallWaveMagnitude", TypeRangedF32, Offset( mOverallWaveMagnitude, WaterObject ), &CommonValidators::PositiveFloat, "Master variable affecting entire body" " of water's undulation" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(RippleTex, WaterObject, "Normal map used to simulate small surface ripples"); + INITPERSISTFIELD_IMAGEASSET(RippleTex, WaterObject, "Normal map used to simulate small surface ripples"); addArray( "Ripples (texture animation)", MAX_WAVES ); @@ -310,7 +310,7 @@ void WaterObject::initPersistFields() addFieldV( "overallRippleMagnitude", TypeRangedF32, Offset( mOverallRippleMagnitude, WaterObject ), &CommonValidators::PositiveFloat, "Master variable affecting entire surface"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(FoamTex, WaterObject, "Diffuse texture for foam in shallow water (advanced lighting only)"); + INITPERSISTFIELD_IMAGEASSET(FoamTex, WaterObject, "Diffuse texture for foam in shallow water (advanced lighting only)"); addArray( "Foam", MAX_FOAM ); @@ -362,7 +362,7 @@ void WaterObject::initPersistFields() addGroup( "Misc" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(DepthGradientTex, WaterObject, "1D texture defining the base water color by depth"); + INITPERSISTFIELD_IMAGEASSET(DepthGradientTex, WaterObject, "1D texture defining the base water color by depth"); addFieldV( "depthGradientMax", TypeRangedF32, Offset( mDepthGradientMax, WaterObject ), &CommonValidators::PositiveFloat, "Depth in world units, the max range of the color gradient texture." ); diff --git a/Engine/source/environment/waterObject.h b/Engine/source/environment/waterObject.h index ceb490bdf..c925f4a07 100644 --- a/Engine/source/environment/waterObject.h +++ b/Engine/source/environment/waterObject.h @@ -269,9 +269,9 @@ protected: F32 mDepthGradientMax; // Other textures - DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, RippleTex, GFXStaticTextureProfile, TextureMask) - DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, FoamTex, GFXStaticTextureSRGBProfile, TextureMask) - DECLARE_IMAGEASSET_NET_REFACTOR(WaterObject, DepthGradientTex, GFXStaticTextureSRGBProfile, TextureMask) + DECLARE_IMAGEASSET_NET(WaterObject, RippleTex, GFXStaticTextureProfile, TextureMask) + DECLARE_IMAGEASSET_NET(WaterObject, FoamTex, GFXStaticTextureSRGBProfile, TextureMask) + DECLARE_IMAGEASSET_NET(WaterObject, DepthGradientTex, GFXStaticTextureSRGBProfile, TextureMask) StringTableEntry mCubemapName; diff --git a/Engine/source/gfx/sim/cubemapData.cpp b/Engine/source/gfx/sim/cubemapData.cpp index 494ba1852..d257027b2 100644 --- a/Engine/source/gfx/sim/cubemapData.cpp +++ b/Engine/source/gfx/sim/cubemapData.cpp @@ -70,7 +70,7 @@ ConsoleDocClass( CubemapData, void CubemapData::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(CubeMapFace, 6, CubemapData, "@brief The 6 cubemap face textures for a static cubemap.\n\n" + INITPERSISTFIELD_IMAGEASSET_ARRAY(CubeMapFace, 6, CubemapData, "@brief The 6 cubemap face textures for a static cubemap.\n\n" "They are in the following order:\n" " - cubeFace[0] is -X\n" " - cubeFace[1] is +X\n" @@ -79,7 +79,7 @@ void CubemapData::initPersistFields() " - cubeFace[4] is -Y\n" " - cubeFace[5] is +Y\n"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(CubeMap, CubemapData, "@brief Cubemap dds Image Asset.\n\n"); + INITPERSISTFIELD_IMAGEASSET(CubeMap, CubemapData, "@brief Cubemap dds Image Asset.\n\n"); } bool CubemapData::onAdd() diff --git a/Engine/source/gfx/sim/cubemapData.h b/Engine/source/gfx/sim/cubemapData.h index 8fea60641..2d2385deb 100644 --- a/Engine/source/gfx/sim/cubemapData.h +++ b/Engine/source/gfx/sim/cubemapData.h @@ -73,9 +73,9 @@ public: GFXTexHandle* getCubeFaceTexture(U32 faceIdx) { return &mCubeMapFaceTex[faceIdx]; } protected: - DECLARE_IMAGEASSET_REFACTOR(CubemapData, CubeMap, GFXStaticTextureSRGBProfile); + DECLARE_IMAGEASSET(CubemapData, CubeMap, GFXStaticTextureSRGBProfile); - DECLARE_IMAGEASSET_ARRAY_REFACTOR(CubemapData, CubeMapFace, GFXStaticTextureSRGBProfile, 6); + DECLARE_IMAGEASSET_ARRAY(CubemapData, CubeMapFace, GFXStaticTextureSRGBProfile, 6); GFXTexHandle mCubeMapFaceTex[6]; GFXTexHandle mDepthBuff; diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp index 139c8f65d..e6f063428 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp @@ -141,7 +141,7 @@ void GuiBitmapButtonCtrl::initPersistFields() docsURL; addGroup( "Bitmap" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiBitmapButtonCtrl,"Texture file to display on this button.\n" + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiBitmapButtonCtrl,"Texture file to display on this button.\n" "If useStates is false, this will be the file that renders on the control. Otherwise, this will " "specify the default texture name to which the various state and modifier suffixes are appended " "to find the per-state and per-modifier (if enabled) textures.") diff --git a/Engine/source/gui/buttons/guiIconButtonCtrl.cpp b/Engine/source/gui/buttons/guiIconButtonCtrl.cpp index eeb5dc6e3..9d0093802 100644 --- a/Engine/source/gui/buttons/guiIconButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiIconButtonCtrl.cpp @@ -127,7 +127,7 @@ void GuiIconButtonCtrl::initPersistFields() addField( "buttonMargin", TypePoint2I, Offset( mButtonMargin, GuiIconButtonCtrl ),"Margin area around the button.\n"); addProtectedField( "iconBitmap", TypeImageFilename, Offset( mBitmapAsset, GuiIconButtonCtrl ), &_setBitmapData, &defaultProtectedGetFn, "Bitmap file for the icon to display on the button.\n", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiIconButtonCtrl, "Bitmap file for the icon to display on the button.\n"); + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiIconButtonCtrl, "Bitmap file for the icon to display on the button.\n"); addField( "iconLocation", TYPEID< IconLocation >(), Offset( mIconLocation, GuiIconButtonCtrl ),"Where to place the icon on the control. Options are 0 (None), 1 (Left), 2 (Right), 3 (Center).\n"); addField( "sizeIconToButton", TypeBool, Offset( mFitBitmapToButton, GuiIconButtonCtrl ),"If true, the icon will be scaled to be the same size as the button.\n"); diff --git a/Engine/source/gui/buttons/guiIconButtonCtrl.h b/Engine/source/gui/buttons/guiIconButtonCtrl.h index da5b08ca2..786997bb1 100644 --- a/Engine/source/gui/buttons/guiIconButtonCtrl.h +++ b/Engine/source/gui/buttons/guiIconButtonCtrl.h @@ -42,7 +42,7 @@ private: protected: - DECLARE_IMAGEASSET_REFACTOR(GuiIconButtonCtrl, Bitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiIconButtonCtrl, Bitmap, GFXDefaultGUIProfile) S32 mIconLocation; S32 mTextLocation; diff --git a/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp b/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp index 1becb6f49..a2b711956 100644 --- a/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiToolboxButtonCtrl.cpp @@ -55,9 +55,9 @@ GuiToolboxButtonCtrl::GuiToolboxButtonCtrl() void GuiToolboxButtonCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(NormalBitmap, GuiToolboxButtonCtrl, ""); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(LoweredBitmap, GuiToolboxButtonCtrl, ""); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(HoverBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET(NormalBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET(LoweredBitmap, GuiToolboxButtonCtrl, ""); + INITPERSISTFIELD_IMAGEASSET(HoverBitmap, GuiToolboxButtonCtrl, ""); Parent::initPersistFields(); } diff --git a/Engine/source/gui/buttons/guiToolboxButtonCtrl.h b/Engine/source/gui/buttons/guiToolboxButtonCtrl.h index c5319e9dd..893fc156d 100644 --- a/Engine/source/gui/buttons/guiToolboxButtonCtrl.h +++ b/Engine/source/gui/buttons/guiToolboxButtonCtrl.h @@ -39,9 +39,9 @@ private: protected: - DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, NormalBitmap, GFXDefaultGUIProfile) - DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, LoweredBitmap, GFXDefaultGUIProfile) - DECLARE_IMAGEASSET_REFACTOR(GuiToolboxButtonCtrl, HoverBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, NormalBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, LoweredBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiToolboxButtonCtrl, HoverBitmap, GFXDefaultGUIProfile) void renderButton(GFXTexHandle texture, Point2I &offset, const RectI& updateRect); void renderStateRect( GFXTexHandle texture, const RectI& rect ); diff --git a/Engine/source/gui/controls/guiBitmapCtrl.cpp b/Engine/source/gui/controls/guiBitmapCtrl.cpp index 5c42b0894..bcf667361 100644 --- a/Engine/source/gui/controls/guiBitmapCtrl.cpp +++ b/Engine/source/gui/controls/guiBitmapCtrl.cpp @@ -70,7 +70,7 @@ void GuiBitmapCtrl::initPersistFields() docsURL; addGroup("Bitmap"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiBitmapCtrl, "The bitmap to render in this BitmapCtrl.") + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiBitmapCtrl, "The bitmap to render in this BitmapCtrl.") addField("color", TypeColorI, Offset(mColor, GuiBitmapCtrl), "color mul"); addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl), "If true, the bitmap is tiled inside the control rather than stretched to fit."); diff --git a/Engine/source/gui/controls/guiBitmapCtrl.h b/Engine/source/gui/controls/guiBitmapCtrl.h index c953fb3b1..adf6f5322 100644 --- a/Engine/source/gui/controls/guiBitmapCtrl.h +++ b/Engine/source/gui/controls/guiBitmapCtrl.h @@ -39,7 +39,7 @@ protected: /// Name of the bitmap file. If this is 'texhandle' the bitmap is not loaded /// from a file but rather set explicitly on the control. - DECLARE_IMAGEASSET_REFACTOR(GuiBitmapCtrl, Bitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiBitmapCtrl, Bitmap, GFXDefaultGUIProfile) Point2I mStartPoint; ColorI mColor; diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp index c79769318..b782f3024 100644 --- a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp @@ -826,9 +826,9 @@ IMPLEMENT_CALLBACK(GuiGameSettingsCtrl, onAxisEvent, void, (const char* device, void GuiGameSettingsCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(KeybindBitmap, GuiGameSettingsCtrl, "Bitmap used to display the bound key for this keybind option."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(PreviousBitmap, GuiGameSettingsCtrl, "Bitmap used for the previous button when in list mode."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(NextBitmap, GuiGameSettingsCtrl, "Bitmap used for the next button when in list mode."); + INITPERSISTFIELD_IMAGEASSET(KeybindBitmap, GuiGameSettingsCtrl, "Bitmap used to display the bound key for this keybind option."); + INITPERSISTFIELD_IMAGEASSET(PreviousBitmap, GuiGameSettingsCtrl, "Bitmap used for the previous button when in list mode."); + INITPERSISTFIELD_IMAGEASSET(NextBitmap, GuiGameSettingsCtrl, "Bitmap used for the next button when in list mode."); addFieldV("arrowSize", TypeRangedS32, Offset(mArrowSize, GuiGameSettingsCtrl), &CommonValidators::PositiveInt, "Size of the arrow buttons' extents"); diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.h b/Engine/source/gui/controls/guiGameSettingsCtrl.h index dbcdc5efc..6c2f69d70 100644 --- a/Engine/source/gui/controls/guiGameSettingsCtrl.h +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.h @@ -72,9 +72,9 @@ protected: Point2F mRange; ///< When working as a slider, this sets our min/max range //Keybind option - DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, KeybindBitmap, GFXDefaultGUIProfile) - DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, PreviousBitmap, GFXDefaultGUIProfile) - DECLARE_IMAGEASSET_REFACTOR(GuiGameSettingsCtrl, NextBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, KeybindBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, PreviousBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, NextBitmap, GFXDefaultGUIProfile) S32 mArrowSize; S32 mColumnSplit; //Padding between the leftmost edge of the control, and the left side of the 'option'. diff --git a/Engine/source/gui/controls/guiPopUpCtrl.h b/Engine/source/gui/controls/guiPopUpCtrl.h index 3f7f5c02b..0528612ea 100644 --- a/Engine/source/gui/controls/guiPopUpCtrl.h +++ b/Engine/source/gui/controls/guiPopUpCtrl.h @@ -126,7 +126,7 @@ protected: NumBitmapModes = 2 }; - DECLARE_IMAGEASSET_ARRAY_REFACTOR(GuiPopUpMenuCtrl, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) + DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrl, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) Point2I mBitmapBounds; // Added S32 mIdMax; diff --git a/Engine/source/gui/controls/guiPopUpCtrlEx.h b/Engine/source/gui/controls/guiPopUpCtrlEx.h index 9e8fddc87..b6501d991 100644 --- a/Engine/source/gui/controls/guiPopUpCtrlEx.h +++ b/Engine/source/gui/controls/guiPopUpCtrlEx.h @@ -131,7 +131,7 @@ class GuiPopUpMenuCtrlEx : public GuiTextCtrl NumBitmapModes = 2 }; - DECLARE_IMAGEASSET_ARRAY_REFACTOR(GuiPopUpMenuCtrlEx, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) + DECLARE_IMAGEASSET_ARRAY(GuiPopUpMenuCtrlEx, Bitmap, GFXDefaultGUIProfile, NumBitmapModes) Point2I mBitmapBounds; // Added diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index bcfcf2123..5bccfce36 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -91,7 +91,7 @@ void GuiCursor::initPersistFields() addField("hotSpot", TypePoint2I, Offset(mHotSpot, GuiCursor), "The location of the cursor's hot spot (which pixel carries the click)."); addField("renderOffset",TypePoint2F, Offset(mRenderOffset, GuiCursor), "Offset of the bitmap, where 0 signifies left edge of the bitmap, 1, the right. Similarly for the Y-component."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiCursor, "name of the bitmap for the cursor."); + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiCursor, "name of the bitmap for the cursor."); Parent::initPersistFields(); } diff --git a/Engine/source/gui/core/guiTypes.h b/Engine/source/gui/core/guiTypes.h index 4ede98303..9c21e54de 100644 --- a/Engine/source/gui/core/guiTypes.h +++ b/Engine/source/gui/core/guiTypes.h @@ -348,7 +348,7 @@ class GuiCursor : public SimObject private: typedef SimObject Parent; - DECLARE_IMAGEASSET_REFACTOR(GuiCursor, Bitmap, GFXGuiCursorProfile) + DECLARE_IMAGEASSET(GuiCursor, Bitmap, GFXGuiCursorProfile) Point2I mHotSpot; Point2F mRenderOffset; @@ -458,7 +458,7 @@ public: /// public: - DECLARE_IMAGEASSET_REFACTOR(GuiControlProfile, Bitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiControlProfile, Bitmap, GFXDefaultGUIProfile) GFXTexHandle mBitmap; StringTableEntry mBitmapName; diff --git a/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp b/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp index 07883e246..b926205f9 100644 --- a/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp +++ b/Engine/source/gui/game/guiChunkedBitmapCtrl.cpp @@ -67,7 +67,7 @@ void GuiChunkedBitmapCtrl::initPersistFields() { docsURL; addGroup("GuiChunkedBitmapCtrl"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiChunkedBitmapCtrl, "This is the bitmap to render to the control."); + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiChunkedBitmapCtrl, "This is the bitmap to render to the control."); addField( "useVariable", TypeBool, Offset( mUseVariable, GuiChunkedBitmapCtrl ), "This decides whether to use the \"bitmap\" file " "or a bitmap stored in \"variable\""); diff --git a/Engine/source/gui/game/guiChunkedBitmapCtrl.h b/Engine/source/gui/game/guiChunkedBitmapCtrl.h index 077087991..e12e0c4c1 100644 --- a/Engine/source/gui/game/guiChunkedBitmapCtrl.h +++ b/Engine/source/gui/game/guiChunkedBitmapCtrl.h @@ -17,7 +17,7 @@ private: protected: - DECLARE_IMAGEASSET_REFACTOR(GuiChunkedBitmapCtrl, Bitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiChunkedBitmapCtrl, Bitmap, GFXDefaultGUIProfile) bool mUseVariable; bool mTile; diff --git a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp index 183634028..4689d70c5 100644 --- a/Engine/source/gui/game/guiProgressBitmapCtrl.cpp +++ b/Engine/source/gui/game/guiProgressBitmapCtrl.cpp @@ -131,7 +131,7 @@ GuiProgressBitmapCtrl::GuiProgressBitmapCtrl() void GuiProgressBitmapCtrl::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(Bitmap, GuiProgressBitmapCtrl, "Bitmap file to use for rendering the progress bar.\n\n" + INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiProgressBitmapCtrl, "Bitmap file to use for rendering the progress bar.\n\n" "If the profile assigned to the control already has a bitmap assigned, this property need not be " "set in which case the bitmap from the profile is used."); diff --git a/Engine/source/gui/game/guiProgressBitmapCtrl.h b/Engine/source/gui/game/guiProgressBitmapCtrl.h index 6d8f1bd52..c134ae1a8 100644 --- a/Engine/source/gui/game/guiProgressBitmapCtrl.h +++ b/Engine/source/gui/game/guiProgressBitmapCtrl.h @@ -47,7 +47,7 @@ class GuiProgressBitmapCtrl : public GuiTextCtrl F32 mProgress; - DECLARE_IMAGEASSET_REFACTOR(GuiProgressBitmapCtrl, Bitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiProgressBitmapCtrl, Bitmap, GFXDefaultGUIProfile) bool mUseVariable; bool mTile; diff --git a/Engine/source/gui/worldEditor/guiMissionArea.cpp b/Engine/source/gui/worldEditor/guiMissionArea.cpp index c951ea8b9..8963911da 100644 --- a/Engine/source/gui/worldEditor/guiMissionArea.cpp +++ b/Engine/source/gui/worldEditor/guiMissionArea.cpp @@ -88,7 +88,7 @@ void GuiMissionAreaCtrl::initPersistFields() docsURL; addField( "squareBitmap", TypeBool, Offset(mSquareBitmap, GuiMissionAreaCtrl)); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(HandleBitmap, GuiMissionAreaCtrl, "Bitmap for the mission area handles.\n"); + INITPERSISTFIELD_IMAGEASSET(HandleBitmap, GuiMissionAreaCtrl, "Bitmap for the mission area handles.\n"); addField( "missionBoundsColor", TypeColorI, Offset(mMissionBoundsColor, GuiMissionAreaCtrl)); addField( "cameraColor", TypeColorI, Offset(mCameraColor, GuiMissionAreaCtrl)); diff --git a/Engine/source/gui/worldEditor/guiMissionArea.h b/Engine/source/gui/worldEditor/guiMissionArea.h index 6400e248d..302bda930 100644 --- a/Engine/source/gui/worldEditor/guiMissionArea.h +++ b/Engine/source/gui/worldEditor/guiMissionArea.h @@ -63,7 +63,7 @@ protected: GFXStateBlockRef mBlendStateBlock; GFXStateBlockRef mSolidStateBlock; - DECLARE_IMAGEASSET_REFACTOR(GuiMissionAreaCtrl, HandleBitmap, GFXDefaultGUIProfile) + DECLARE_IMAGEASSET(GuiMissionAreaCtrl, HandleBitmap, GFXDefaultGUIProfile) Point2I mHandleTextureSize; Point2F mHandleTextureHalfSize; diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index d32f24d44..d4008a95b 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -2839,9 +2839,9 @@ void WorldEditor::initPersistFields() addField( "renderObjHandle", TypeBool, Offset(mRenderObjHandle, WorldEditor) ); addField( "renderSelectionBox", TypeBool, Offset(mRenderSelectionBox, WorldEditor) ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(SelectHandle, WorldEditor, ""); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(DefaultHandle, WorldEditor, ""); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(LockedHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET(SelectHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET(DefaultHandle, WorldEditor, ""); + INITPERSISTFIELD_IMAGEASSET(LockedHandle, WorldEditor, ""); endGroup( "Rendering" ); diff --git a/Engine/source/gui/worldEditor/worldEditor.h b/Engine/source/gui/worldEditor/worldEditor.h index f11e23c1a..40cc888a1 100644 --- a/Engine/source/gui/worldEditor/worldEditor.h +++ b/Engine/source/gui/worldEditor/worldEditor.h @@ -328,9 +328,9 @@ class WorldEditor : public EditTSCtrl ColorI mPopupBackgroundColor; ColorI mPopupTextColor; - DECLARE_IMAGEASSET_REFACTOR(WorldEditor, SelectHandle, GFXStaticTextureSRGBProfile) - DECLARE_IMAGEASSET_REFACTOR(WorldEditor, DefaultHandle, GFXStaticTextureSRGBProfile) - DECLARE_IMAGEASSET_REFACTOR(WorldEditor, LockedHandle, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(WorldEditor, SelectHandle, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(WorldEditor, DefaultHandle, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(WorldEditor, LockedHandle, GFXStaticTextureSRGBProfile) ColorI mObjectTextColor; bool mObjectsUseBoxCenter; diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 98bdb9729..0e32056d1 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -242,28 +242,28 @@ void Material::initPersistFields() addArray("Stages", MAX_STAGES); addGroup("Basic Texture Maps"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DiffuseMap, MAX_STAGES, Material, "Albedo"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(DiffuseMap, MAX_STAGES, Material, "Albedo"); addField("diffuseColor", TypeColorF, Offset(mDiffuse, Material), MAX_STAGES, "This color is multiplied against the diffuse texture color. If no diffuse texture " "is present this is the material color."); addField("diffuseMapSRGB", TypeBool, Offset(mDiffuseMapSRGB, Material), MAX_STAGES, "Enable sRGB for the diffuse color texture map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(NormalMap, MAX_STAGES, Material, "NormalMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(NormalMap, MAX_STAGES, Material, "NormalMap"); endGroup("Basic Texture Maps"); addGroup("Light Influence Maps"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(ORMConfigMap, MAX_STAGES, Material, "AO|Roughness|metalness map"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(ORMConfigMap, MAX_STAGES, Material, "AO|Roughness|metalness map"); addField("isSRGb", TypeBool, Offset(mIsSRGb, Material), MAX_STAGES, "Substance Designer Workaround."); addField("invertRoughness", TypeBool, Offset(mInvertRoughness, Material), MAX_STAGES, "Treat Roughness as Roughness"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(AOMap, MAX_STAGES, Material, "AOMap"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(RoughMap, MAX_STAGES, Material, "RoughMap (also needs MetalMap)"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(MetalMap, MAX_STAGES, Material, "MetalMap (also needs RoughMap)"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(GlowMap, MAX_STAGES, Material, "GlowMap (needs Albedo)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(AOMap, MAX_STAGES, Material, "AOMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(RoughMap, MAX_STAGES, Material, "RoughMap (also needs MetalMap)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(MetalMap, MAX_STAGES, Material, "MetalMap (also needs RoughMap)"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(GlowMap, MAX_STAGES, Material, "GlowMap (needs Albedo)"); addFieldV("AOChan", TypeRangedS32, Offset(mAOChan, Material), &bmpChanRange, MAX_STAGES, "The input channel AO maps use."); @@ -281,18 +281,18 @@ void Material::initPersistFields() endGroup("Light Influence Maps"); addGroup("Advanced Texture Maps"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DetailMap, MAX_STAGES, Material, "DetailMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailMap, MAX_STAGES, Material, "DetailMap"); addField("detailScale", TypePoint2F, Offset(mDetailScale, Material), MAX_STAGES, "The scale factor for the detail map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(DetailNormalMap, MAX_STAGES, Material, "DetailNormalMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailNormalMap, MAX_STAGES, Material, "DetailNormalMap"); addFieldV("detailNormalMapStrength", TypeRangedF32, Offset(mDetailNormalMapStrength, Material), &CommonValidators::PositiveFloat, MAX_STAGES, "Used to scale the strength of the detail normal map when blended with the base normal map."); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(OverlayMap, MAX_STAGES, Material, "Overlay"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(LightMap, MAX_STAGES, Material, "LightMap"); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(ToneMap, MAX_STAGES, Material, "ToneMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(OverlayMap, MAX_STAGES, Material, "Overlay"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(LightMap, MAX_STAGES, Material, "LightMap"); + INITPERSISTFIELD_IMAGEASSET_ARRAY(ToneMap, MAX_STAGES, Material, "ToneMap"); endGroup("Advanced Texture Maps"); addGroup("Accumulation Properties"); @@ -807,15 +807,15 @@ bool Material::_setAccuEnabled(void* object, const char* index, const char* data //material.getDiffuseMap(%layer); //returns the raw file referenced //material.getDiffuseMapAsset(%layer); //returns the asset id //material.setDiffuseMap(%texture, %layer); //tries to set the asset and failing that attempts a flat file reference -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DiffuseMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, NormalMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailNormalMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, OverlayMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, LightMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ToneMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, DetailMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, ORMConfigMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, RoughMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, AOMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, MetalMap, Material::Constants::MAX_STAGES) -DEF_IMAGEASSET_ARRAY_BINDS_REFACTOR(Material, GlowMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, DiffuseMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, NormalMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailNormalMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, OverlayMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, LightMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, ToneMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, ORMConfigMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, RoughMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap, Material::Constants::MAX_STAGES) +DEF_IMAGEASSET_ARRAY_BINDS(Material, GlowMap, Material::Constants::MAX_STAGES) diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 994c11ffe..b76aadd6f 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -208,18 +208,18 @@ public: //----------------------------------------------------------------------- // Data //----------------------------------------------------------------------- - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DiffuseMap, GFXStaticTextureSRGBProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, NormalMap, GFXNormalMapProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailNormalMap, GFXNormalMapProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, OverlayMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, LightMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ToneMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, DetailMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, ORMConfigMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, AOMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, RoughMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, MetalMap, GFXStaticTextureProfile, MAX_STAGES) - DECLARE_IMAGEASSET_ARRAY_REFACTOR(Material, GlowMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, DiffuseMap, GFXStaticTextureSRGBProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, NormalMap, GFXNormalMapProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, DetailNormalMap, GFXNormalMapProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, OverlayMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, LightMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, ToneMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, DetailMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, ORMConfigMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, AOMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, RoughMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, MetalMap, GFXStaticTextureProfile, MAX_STAGES) + DECLARE_IMAGEASSET_ARRAY(Material, GlowMap, GFXStaticTextureProfile, MAX_STAGES) bool mDiffuseMapSRGB[MAX_STAGES]; // SRGB diffuse bool mIsSRGb[MAX_STAGES]; // SRGB ORM diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 98a9e569a..e4c09d132 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -875,13 +875,14 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S case Material::TexTarget: { texTarget = rpd->mTexSlot[i].texTarget; + texObject = mMaterial->getDiffuseMapAsset(0)->getTexture(&GFXStaticTextureSRGBProfile); if ( !texTarget ) { // try again. texTarget = mMaterial->getDiffuseMapAsset(0)->getNamedTarget(); if (!texTarget) { - GFX->setTexture(i, NULL); + GFX->setTexture(i, texObject); break; } else @@ -889,8 +890,6 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S rpd->mTexSlot[i].texTarget = texTarget; } } - - texObject = texTarget->getTexture(); // If no texture is available then map the default 2x2 // black texture to it. This at least will ensure that @@ -1281,35 +1280,35 @@ void ProcessedShaderMaterial::setNodeTransforms(const MatrixF *transforms, const void ProcessedShaderMaterial::setCustomShaderData(Vector &shaderData, const U32 pass) { - PROFILE_SCOPE(ProcessedShaderMaterial_setCustomShaderData); + PROFILE_SCOPE(ProcessedShaderMaterial_setCustomShaderData); - GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); - ShaderConstHandles* handles = _getShaderConstHandles(pass); + GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass); + ShaderConstHandles* handles = _getShaderConstHandles(pass); - for (U32 i = 0; i < shaderData.size(); i++) - { - //roll through and try setting our data! - for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) - { - if (handles->mCustomHandles[h].handleName == shaderData[i].getHandleName()) - { - if (handles->mCustomHandles[h].handle->isValid()) - { - CustomShaderBindingData::UniformType type = shaderData[i].getType(); + for (U32 i = 0; i < shaderData.size(); i++) + { + //roll through and try setting our data! + for (U32 h = 0; h < handles->mCustomHandles.size(); ++h) + { + if (handles->mCustomHandles[h].handleName == shaderData[i].getHandleName()) + { + if (handles->mCustomHandles[h].handle->isValid()) + { + CustomShaderBindingData::UniformType type = shaderData[i].getType(); - if (type == CustomShaderBindingData::Float) - shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat()); - else if (type == CustomShaderBindingData::Float2) - shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat2()); - else if (type == CustomShaderBindingData::Float3) - shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat3()); - else if (type == CustomShaderBindingData::Float4) - shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat4()); - break; - } - } - } - } + if (type == CustomShaderBindingData::Float) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat()); + else if (type == CustomShaderBindingData::Float2) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat2()); + else if (type == CustomShaderBindingData::Float3) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat3()); + else if (type == CustomShaderBindingData::Float4) + shaderConsts->setSafe(handles->mCustomHandles[h].handle, shaderData[i].getFloat4()); + break; + } + } + } + } } void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const SceneData& sgData, U32 pass) diff --git a/Engine/source/postFx/postEffect.cpp b/Engine/source/postFx/postEffect.cpp index 8c87d601a..ef9ef2fa6 100644 --- a/Engine/source/postFx/postEffect.cpp +++ b/Engine/source/postFx/postEffect.cpp @@ -553,7 +553,7 @@ void PostEffect::initPersistFields() "Specifies how the viewport should be set up for a target texture." ); addProtectedField("Texture", TypeImageFilename, Offset(mTextureAsset, PostEffect), _setTextureData, &defaultProtectedGetFn, NumTextures, "Input textures to this effect(samplers).\n", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_IMAGEASSET_ARRAY_REFACTOR(Texture, NumTextures, PostEffect, "Input textures to this effect ( samplers ).\n" + INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, NumTextures, PostEffect, "Input textures to this effect ( samplers ).\n" "@see PFXTextureIdentifiers"); addField("textureSRGB", TypeBool, Offset(mTexSRGB, PostEffect), NumTextures, diff --git a/Engine/source/postFx/postEffect.h b/Engine/source/postFx/postEffect.h index 4f9a1c2c8..456b7578d 100644 --- a/Engine/source/postFx/postEffect.h +++ b/Engine/source/postFx/postEffect.h @@ -90,7 +90,7 @@ public: protected: - DECLARE_IMAGEASSET_ARRAY_REFACTOR(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures); + DECLARE_IMAGEASSET_ARRAY(PostEffect, Texture, GFXStaticTextureSRGBProfile, NumTextures); GFXTextureProfile* mTextureProfile[NumTextures]; GFXTexHandle mTexture[NumTextures]; diff --git a/Engine/source/terrain/terrMaterial.cpp b/Engine/source/terrain/terrMaterial.cpp index 694ce7dee..33e625f99 100644 --- a/Engine/source/terrain/terrMaterial.cpp +++ b/Engine/source/terrain/terrMaterial.cpp @@ -92,10 +92,10 @@ FRangeValidator hardnessValidator(0.0f, 0.999f); void TerrainMaterial::initPersistFields() { docsURL; - INITPERSISTFIELD_IMAGEASSET_REFACTOR(DiffuseMap, TerrainMaterial,"Base Albedo stretched over the whole map"); + INITPERSISTFIELD_IMAGEASSET(DiffuseMap, TerrainMaterial,"Base Albedo stretched over the whole map"); addFieldV( "diffuseSize", TypeRangedF32, Offset( mDiffuseSize, TerrainMaterial ), &CommonValidators::PositiveFloat, "Used to scale the diffuse map to the material square" ); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(NormalMap, TerrainMaterial,"NormalMap"); + INITPERSISTFIELD_IMAGEASSET(NormalMap, TerrainMaterial,"NormalMap"); addFieldV( "parallaxScale", TypeRangedF32, Offset( mParallaxScale, TerrainMaterial ), &CommonValidators::PositiveFloat, "Used to scale the height from the normal map to give some self " "occlusion effect (aka parallax) to the terrain material" ); @@ -109,20 +109,20 @@ void TerrainMaterial::initPersistFields() addFieldV("blendHeightHardness", TypeRangedF32, Offset(mBlendHardness, TerrainMaterial), &hardnessValidator, "How sharply this layer blends with other textures." "0->1, soft->hard."); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(DetailMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo up close."); + INITPERSISTFIELD_IMAGEASSET(DetailMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo up close."); addFieldV( "detailSize", TypeRangedF32, Offset( mDetailSize, TerrainMaterial ), &CommonValidators::PositiveFloat, "Used to scale the detail map to the material square" ); addFieldV( "detailStrength", TypeRangedF32, Offset( mDetailStrength, TerrainMaterial ), &CommonValidators::PositiveFloat, "Exponentially sharpens or lightens the detail map rendering on the material" ); addFieldV( "detailDistance", TypeRangedF32, Offset( mDetailDistance, TerrainMaterial ), &CommonValidators::PositiveFloat, "Changes how far camera can see the detail map rendering on the material" ); addField( "useSideProjection", TypeBool, Offset( mSideProjection, TerrainMaterial ),"Makes that terrain material project along the sides of steep " "slopes instead of projected downwards"); - INITPERSISTFIELD_IMAGEASSET_REFACTOR(ORMConfigMap, TerrainMaterial, "AO|Roughness|metalness map (uses DetailMap UV Coords)"); + INITPERSISTFIELD_IMAGEASSET(ORMConfigMap, TerrainMaterial, "AO|Roughness|metalness map (uses DetailMap UV Coords)"); addField("isSRGB", TypeBool, Offset(mIsSRGB, TerrainMaterial), "Is the PBR Config map's image in sRGB format?"); addField("invertRoughness", TypeBool, Offset(mInvertRoughness, TerrainMaterial), "Should the roughness channel of the PBR Config map be inverted?"); //Macro maps additions - INITPERSISTFIELD_IMAGEASSET_REFACTOR(MacroMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo at a distance."); + INITPERSISTFIELD_IMAGEASSET(MacroMap, TerrainMaterial, "Raises and lowers the RGB result of the Base Albedo at a distance."); addFieldV( "macroSize", TypeRangedF32, Offset( mMacroSize, TerrainMaterial ), &CommonValidators::PositiveFloat, "Used to scale the Macro map to the material square" ); addFieldV( "macroStrength", TypeRangedF32, Offset( mMacroStrength, TerrainMaterial ), &CommonValidators::PositiveFloat, "Exponentially sharpens or lightens the Macro map rendering on the material" ); addFieldV( "macroDistance", TypeRangedF32, Offset( mMacroDistance, TerrainMaterial ), &CommonValidators::PositiveFloat, "Changes how far camera can see the Macro map rendering on the material" ); diff --git a/Engine/source/terrain/terrMaterial.h b/Engine/source/terrain/terrMaterial.h index c119f57b1..19c712128 100644 --- a/Engine/source/terrain/terrMaterial.h +++ b/Engine/source/terrain/terrMaterial.h @@ -38,17 +38,17 @@ class TerrainMaterial : public SimObject protected: /// - DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, DiffuseMap, GFXStaticTextureSRGBProfile) + DECLARE_IMAGEASSET(TerrainMaterial, DiffuseMap, GFXStaticTextureSRGBProfile) /// The size of the diffuse base map in meters /// used to generate its texture coordinates. F32 mDiffuseSize; /// - DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, NormalMap, GFXNormalMapProfile) + DECLARE_IMAGEASSET(TerrainMaterial, NormalMap, GFXNormalMapProfile) /// - DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, DetailMap, GFXStaticTextureProfile) + DECLARE_IMAGEASSET(TerrainMaterial, DetailMap, GFXStaticTextureProfile) /// The size of the detail map in meters used /// to generate the texture coordinates for the @@ -62,7 +62,7 @@ protected: F32 mDetailDistance; /// - DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, ORMConfigMap, GFXStaticTextureProfile) + DECLARE_IMAGEASSET(TerrainMaterial, ORMConfigMap, GFXStaticTextureProfile) bool mIsSRGB; bool mInvertRoughness; @@ -73,7 +73,7 @@ protected: /// planes. bool mSideProjection; - DECLARE_IMAGEASSET_REFACTOR(TerrainMaterial, MacroMap, GFXStaticTextureProfile) + DECLARE_IMAGEASSET(TerrainMaterial, MacroMap, GFXStaticTextureProfile) F32 mMacroSize; F32 mMacroStrength; From 774bd874b5795934703dfae671083e0a858830e1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 30 Mar 2025 11:44:55 +0100 Subject: [PATCH 46/47] Update ImageAsset.cpp early out of generateTexture --- Engine/source/T3D/assets/ImageAsset.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index e26533524..5f234fc0b 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -531,6 +531,10 @@ GFXTexHandle ImageAsset::getTexture(GFXTextureProfile* requestedProfile) void ImageAsset::generateTexture(void) { + // already have a generated texture, get out. + if (mTextureHandle.isValid()) + return; + // implement some defaults, eventually SRGB should be optional. U32 flags = GFXTextureProfile::Static | GFXTextureProfile::SRGB; From 79e046d379d74b07d27541ed61424a672357089f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 30 Mar 2025 12:22:17 +0100 Subject: [PATCH 47/47] Update processedShaderMaterial.cpp requires extra safety when the diffusemap asset is null, this is something that will be fixed by the material asset refactor --- Engine/source/materials/processedShaderMaterial.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index e4c09d132..b7cdd89b5 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -875,6 +875,12 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S case Material::TexTarget: { texTarget = rpd->mTexSlot[i].texTarget; + if (!mMaterial->getDiffuseMapAsset(0).notNull()) + { + GFX->setTexture(i, NULL); + break; + } + texObject = mMaterial->getDiffuseMapAsset(0)->getTexture(&GFXStaticTextureSRGBProfile); if ( !texTarget ) {