From 50f74368b330007484292470ce1b164482da2db1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 15 Jun 2025 22:07:12 +0100 Subject: [PATCH 01/23] various fixes around preview assets and imageassets text field Imageasset text field now displays correctly in inspector previews now use assets again assetBrowser hides previewCache folder --- Engine/source/T3D/assets/ImageAsset.h | 32 +++++++++++------ Engine/source/console/console.cpp | 17 +++++++++ .../assetBrowser/scripts/assetBrowser.tscript | 4 +-- .../scripts/assetTypes/image.tscript | 32 ++++++++++++++--- .../scripts/assetTypes/material.tscript | 35 ++++++++++++++---- .../scripts/assetTypes/shape.tscript | 36 ++++++++++++------- 6 files changed, 121 insertions(+), 35 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 082ddb04f..c60523b81 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -233,10 +233,10 @@ DefineEnumType(ImageAssetType); #pragma region Refactor Asset Macros -#define DECLARE_IMAGEASSET(className, name, profile) \ +#define DECLARE_IMAGEASSET(className, name, profile) \ private: \ - AssetPtr m##name##Asset;\ - String m##name##File;\ + AssetPtr m##name##Asset; \ + StringTableEntry m##name##File = StringTable->EmptyString(); \ public: \ void _set##name(StringTableEntry _in){ \ if(m##name##Asset.getAssetId() == _in) \ @@ -244,6 +244,7 @@ public: if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset = NULL; \ + m##name##File = ""; \ return; \ } \ if(!AssetDatabase.isDeclaredAsset(_in)) \ @@ -271,10 +272,12 @@ public: imageAssetId = ImageAsset::smNoImageAssetFallback; \ } \ m##name##Asset = imageAssetId; \ + m##name##File = _in; \ } \ else \ { \ m##name##Asset = _in; \ + m##name##File = get##name##File(); \ } \ }; \ \ @@ -285,10 +288,10 @@ public: StringTableEntry get##name##File(){ return m##name##Asset.notNull() ? m##name##Asset->getImageFile() : ""; } -#define DECLARE_IMAGEASSET_NET(className, name, profile, mask) \ +#define DECLARE_IMAGEASSET_NET(className, name, profile, mask) \ private: \ AssetPtr m##name##Asset; \ - String m##name##File;\ + StringTableEntry m##name##File = StringTable->EmptyString(); \ public: \ void _set##name(StringTableEntry _in){ \ if(m##name##Asset.getAssetId() == _in) \ @@ -296,6 +299,7 @@ public: if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset = NULL; \ + m##name##File = ""; \ setMaskBits(mask); \ return; \ } \ @@ -324,10 +328,12 @@ public: imageAssetId = ImageAsset::smNoImageAssetFallback; \ } \ m##name##Asset = imageAssetId; \ + m##name##File = _in; \ } \ else \ { \ m##name##Asset = _in; \ + m##name##File = get##name##File(); \ } \ setMaskBits(mask); \ }; \ @@ -339,15 +345,15 @@ public: StringTableEntry get##name##File(){ return m##name##Asset.notNull() ? m##name##Asset->getImageFile() : ""; } -#define INITPERSISTFIELD_IMAGEASSET(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.)); \ addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, file docs.)); -#define DECLARE_IMAGEASSET_ARRAY(className, name, profile, max) \ +#define DECLARE_IMAGEASSET_ARRAY(className, name, profile, max) \ private: \ AssetPtr m##name##Asset[max]; \ - String m##name##File[max];\ + StringTableEntry m##name##File[max] = {StringTable->EmptyString() }; \ public: \ void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ @@ -355,6 +361,7 @@ public: if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset[index] = NULL; \ + m##name##File[index] = ""; \ return; \ } \ if(!AssetDatabase.isDeclaredAsset(_in)) \ @@ -382,10 +389,12 @@ public: imageAssetId = ImageAsset::smNoImageAssetFallback; \ } \ m##name##Asset[index] = imageAssetId; \ + m##name##File[index] = _in; \ } \ else \ { \ m##name##Asset[index] = _in; \ + m##name##File[index] = get##name##File(index); \ } \ }; \ \ @@ -397,10 +406,10 @@ public: StringTableEntry get##name##File(const U32& idx){ return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getImageFile() : ""; } -#define DECLARE_IMAGEASSET_ARRAY_NET(className, name, profile, max, mask) \ +#define DECLARE_IMAGEASSET_ARRAY_NET(className, name, profile, max, mask) \ private: \ AssetPtr m##name##Asset[max]; \ - String m##name##File[max];\ + StringTableEntry m##name##File[max] = {StringTable->EmptyString() }; \ public: \ void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ @@ -408,6 +417,7 @@ public: if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset[index] = NULL; \ + m##name##File[index] = ""; \ setMaskBits(mask); \ return; \ } \ @@ -436,10 +446,12 @@ public: imageAssetId = ImageAsset::smNoImageAssetFallback; \ } \ m##name##Asset[index] = imageAssetId; \ + m##name##File[index] = _in; \ } \ else \ { \ m##name##Asset[index] = _in; \ + m##name##File[index] = get##name##File(index); \ } \ setMaskBits(mask); \ }; \ diff --git a/Engine/source/console/console.cpp b/Engine/source/console/console.cpp index eb967f35e..4b9316e6f 100644 --- a/Engine/source/console/console.cpp +++ b/Engine/source/console/console.cpp @@ -2226,6 +2226,23 @@ bool stripRepeatSlashes(char* pDstPath, const char* pSrcPath, S32 dstSize) //----------------------------------------------------------------------------- +DefineEngineFunction(expandPath, const char*, (const char* path),, "(string path) - Expands an expando or relative path into a full path.") +{ + char* ret = Con::getReturnBuffer(1024); + Con::expandPath(ret, 1024, path); + return ret; +} + +//----------------------------------------------------------------------------- + +DefineEngineFunction(collapsePath, const char*, (const char* path), , "(string path) - Collapses a path into either an expando path or a relative path.") +{ + char* ret = Con::getReturnBuffer(1024); + Con::collapsePath(ret, 1024, path); + return ret; +} + + DefineEngineFunction( log, void, ( const char* message ),, "@brief Logs a message to the console.\n\n" "@param message The message text.\n" diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index d53e8a4cb..04b12ab3d 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -258,7 +258,7 @@ function AssetBrowser::initialize(%this) if(!isObject(%this.dirHandler)) { - %this.dirHandler = makedirectoryHandler(%this-->filterTree, "cache,shaderCache", ""); + %this.dirHandler = makedirectoryHandler(%this-->filterTree, "cache,shaderCache,previewCache", ""); %this.dirHandler.currentAddress = "data/"; } @@ -1613,7 +1613,7 @@ function AssetBrowser::doRebuildAssetArray(%this) else { //got it. - if(%folderName $= "shaderCache" || %folderName $= "cache" || %folderName $= ".git") + if(%folderName $= "shaderCache" || %folderName $= "cache" || %folderName $= ".git" || %folderName $= "previewCache") continue; if(!%this.coreModulesFilter && %folderName $= "core" && %breadcrumbPath $= "") diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index f571f2aa6..1aa34f78c 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -42,29 +42,53 @@ function ImageAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat if(%forceRegenerate $= "") %forceRegenerate = false; - %previewPath = "tools/resources/previewCache/" @ %previewButton.moduleName @ "/"; + %previewPath = "tools/resources/previewCache/" @ %previewButton.moduleName @ "/"; if(!IsDirectory(%previewPath)) { $CurrentAssetBrowser.dirHandler.createFolder(%previewPath); } - %previewFilePath = %previewPath @ %this.assetName @ ".png"; + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.png"; if(!isFile(%previewFilePath) || (compareFileTimes(%this.getImagePath(), %previewFilePath) == 1)) { %generatePreview = true; } + %previewAssetName = "ToolsModule:" @ %this.assetName @ "_Preview"; + if(%generatePreview || %forceRegenerate) { %success = saveScaledImage(%this.getImagePath(), %previewFilePath, EditorSettings.value("Assets/Browser/PreviewImageSize")); if(%success) - %previewButton.setBitmap(%previewFilePath); - + { + + if(!AssetDatabase.isDeclaredAsset(%previewAssetName)) + { + %preview_Asset = new ImageAsset() + { + assetName = %this.assetName @ "_Preview"; + versionId = 1; + imageFile = makeFullPath(%previewFilePath); + }; + + TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); + %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); + AssetDatabase.addDeclaredAsset(%toolsModuleDef, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); + } + + %previewButton.bitmapAsset = %previewAssetName; + } + return %success; } + else + { + %previewButton.bitmapAsset = %previewAssetName; + return true; + } return false; } diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript index bd88e1274..33456e96a 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript @@ -101,8 +101,7 @@ function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegene if(%forceRegenerate $= "") %forceRegenerate = false; - %module = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(AssetDatabase.getAssetFilePath(%this.getAssetId())))); - %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/"; + %previewPath = "tools/resources/previewCache/" @ %previewButton.moduleName @ "/"; if(!IsDirectory(%previewPath)) { @@ -111,7 +110,8 @@ function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegene %generatePreview = false; - %previewFilePath = %previewPath @ %this.assetName @ ".png"; + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.png"; + if(!isFile(%previewFilePath)) { %generatePreview = true; @@ -126,6 +126,8 @@ function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegene } } + %previewAssetName = "ToolsModule:" @ %this.assetName @ "_Preview"; + if(%generatePreview || %forceRegenerate) { if(isObject(%this.materialDefinitionName)) @@ -137,22 +139,41 @@ function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegene %diffuseMapAsset = AssetDatabase.acquireAsset(%diffuseMapAssetId); AssetDatabase.releaseAsset(%diffuseMapAssetId); } + %previewShapeDef = AssetDatabase.acquireAsset("ToolsModule:previewSphereShape"); %generatedFilePath = %previewShapeDef.generateCachedPreviewImage(256, %this.materialDefinitionName); pathCopy(%generatedFilePath, %previewFilePath, false); fileDelete(%generatedFilePath); - if(isFile(%previewFilePath)) + if(!AssetDatabase.isDeclaredAsset(%previewAssetName)) { - %previewButton.setBitmap(%previewFilePath); - return true; + %preview_Asset = new ImageAsset() + { + assetName = %this.assetName @ "_Preview"; + versionId = 1; + imageFile = makeFullPath(%previewFilePath); + }; + + TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); + %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); + AssetDatabase.addDeclaredAsset(%toolsModuleDef, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); } + %previewButton.bitmapAsset = %previewAssetName; + return true; + } + else + { return false; } } - + else + { + %previewButton.bitmapAsset = %previewAssetName; + return true; + } + return false; } diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript index 855ba712c..d91ea925d 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript @@ -111,23 +111,21 @@ function ShapeAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat if(%forceRegenerate $= "") %forceRegenerate = false; - %assetId = %this.getAssetId(); - - %module = %previewButton.assetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%this.getShapePath()))); - %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/"; + %previewPath = "tools/resources/previewCache/" @ %previewButton.moduleName @ "/"; if(!IsDirectory(%previewPath)) { - %previewButton.assetBrowser.dirHandler.createFolder(%previewPath); + $CurrentAssetBrowser.dirHandler.createFolder(%previewPath); } - %generatePreview = false; + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.png"; - %previewFilePath = %previewPath @ %this.assetName @ ".png"; if(!isFile(%previewFilePath) || (compareFileTimes(%this.getShapePath(), %previewFilePath) == 1)) { %generatePreview = true; } + + %previewAssetName = "ToolsModule:" @ %this.assetName @ "_Preview"; if(%generatePreview || %forceRegenerate) { @@ -146,14 +144,28 @@ function ShapeAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat pathCopy(%filePath, %previewFilePath, false); fileDelete(%filePath); //cleanup - - if(isFile(%previewFilePath)) + + if(!AssetDatabase.isDeclaredAsset(%previewAssetName)) { - %previewButton.setBitmap(%previewFilePath); - return true; + %preview_Asset = new ImageAsset() + { + assetName = %this.assetName @ "_Preview"; + versionId = 1; + imageFile = makeFullPath(%previewFilePath); + }; + + TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); + %toolsModuleDef = ModuleDatabase.findModule("ToolsModule",1); + AssetDatabase.addDeclaredAsset(%toolsModuleDef, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); } - return false; + %previewButton.bitmapAsset = %previewAssetName; + return true; + } + else + { + %previewButton.bitmapAsset = %previewAssetName; + return true; } return false; From fc9f221ac07ef49a477fb1d689a84705ecbd646d Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Mon, 16 Jun 2025 08:33:11 +0100 Subject: [PATCH 02/23] Prepend symbol for image files Prepend image filenames in imageassets with "@" symbol so expand and collapse works correctly for files relative to that asset.taml file. --- Engine/source/T3D/assets/assetImporter.cpp | 2 +- Engine/source/assets/assetBase.cpp | 22 ++++++++++++++++--- .../scripts/assetTypes/image.tscript | 2 +- .../scripts/assetTypes/material.tscript | 2 +- .../scripts/assetTypes/shape.tscript | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index eca044509..2a6ee089f 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2825,7 +2825,7 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str()); String imageFileName = assetItem->filePath.getFullFileName(); - String assetPath = targetPath + "/" + imageFileName; + String assetPath = "@" + imageFileName; String tamlPath = targetPath + "/" + assetName + ".asset.taml"; String originalPath = assetItem->filePath.getFullPath().c_str(); diff --git a/Engine/source/assets/assetBase.cpp b/Engine/source/assets/assetBase.cpp index dba9f142a..fcb9b5051 100644 --- a/Engine/source/assets/assetBase.cpp +++ b/Engine/source/assets/assetBase.cpp @@ -226,9 +226,20 @@ StringTableEntry AssetBase::expandAssetFilePath(const char* pAssetFilePath) cons assetBasePathHint = NULL; } - // Expand the path with the asset base-path hint. char assetFilePathBuffer[1024]; - Con::expandPath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath, assetBasePathHint); + + if (*pAssetFilePath != '@') + { + // Expand the path with the asset base-path hint. + Con::expandPath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath, assetBasePathHint); + return StringTable->insert(assetFilePathBuffer); + } + + if(!getOwned()) + return StringTable->insert(pAssetFilePath); + + // Format expanded path taking into account any missing slash. + dSprintf(assetFilePathBuffer, sizeof(assetFilePathBuffer), "%s/%s", mpOwningAssetManager->getAssetPath(getAssetId()), pAssetFilePath + (pAssetFilePath[1] == '/' ? 2 : 1)); return StringTable->insert(assetFilePathBuffer); } @@ -254,6 +265,11 @@ StringTableEntry AssetBase::collapseAssetFilePath(const char* pAssetFilePath) co char assetFilePathBuffer[1024]; + if (*pAssetFilePath == '@') + { + return StringTable->insert(pAssetFilePath); + } + // Is the asset not owned or private? if (!getOwned() || getAssetPrivate()) { @@ -272,7 +288,7 @@ StringTableEntry AssetBase::collapseAssetFilePath(const char* pAssetFilePath) co StringTableEntry relativePath = Platform::makeRelativePathName(pAssetFilePath, assetBasePath); // Format the collapsed path. - dSprintf(assetFilePathBuffer, sizeof(assetFilePathBuffer), "%s", relativePath); + dSprintf(assetFilePathBuffer, sizeof(assetFilePathBuffer), "@%s", relativePath); } else { diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index 1aa34f78c..eb29fb365 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -71,7 +71,7 @@ function ImageAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat { assetName = %this.assetName @ "_Preview"; versionId = 1; - imageFile = makeFullPath(%previewFilePath); + imageFile = "@" @ %this.assetName @ "_Preview.png"; }; TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript index 33456e96a..78d611b5f 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript @@ -152,7 +152,7 @@ function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegene { assetName = %this.assetName @ "_Preview"; versionId = 1; - imageFile = makeFullPath(%previewFilePath); + imageFile = "@" @ %this.assetName @ "_Preview.png"; }; TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript index d91ea925d..be6d0087e 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript @@ -151,7 +151,7 @@ function ShapeAsset::generatePreviewImage(%this, %previewButton, %forceRegenerat { assetName = %this.assetName @ "_Preview"; versionId = 1; - imageFile = makeFullPath(%previewFilePath); + imageFile = "@" @ %this.assetName @ "_Preview.png"; }; TamlWrite(%preview_Asset, expandPath("^ToolsModule/resources/previewCache/" @ %previewButton.moduleName @ "/" @ %preview_Asset.AssetName @ ".asset.taml")); From 67f217ada125bae06d96e521049351e7a574b974 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 17 Jun 2025 12:20:47 +0100 Subject: [PATCH 03/23] Update assetImporter.cpp asset importing for images shouldnt execute a file copy, original file path is enough as it is relative to exe --- Engine/source/T3D/assets/assetImporter.cpp | 27 ++-------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 2a6ee089f..5d0c55d78 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2829,25 +2829,14 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) String tamlPath = targetPath + "/" + assetName + ".asset.taml"; String originalPath = assetItem->filePath.getFullPath().c_str(); - char qualifiedFromFile[2048]; - char qualifiedToFile[2048]; - -#ifndef TORQUE_SECURE_VFS - Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); - Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); -#else - dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile)); - dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile)); -#endif - newAsset->setAssetName(assetName); newAsset->setImageFile(assetPath.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 - if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile)) + if (!isReimport) { - newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile); + newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, originalPath.c_str()); } if (assetItem->typeHint != String::EmptyString) @@ -2870,18 +2859,6 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) return ""; } - if (!isReimport) - { - bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - - if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) - { - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str()); - activityLog.push_back(importLogBuffer); - return ""; - } - } - return tamlPath; } From 3d77b59b7157f50c7d2b91036f651a3795d35d9e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 17 Jun 2025 14:57:18 +0100 Subject: [PATCH 04/23] Update assetImporter.cpp refresh asset so image asset can write out its image metadata --- Engine/source/T3D/assets/assetImporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 5d0c55d78..726f490de 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2805,6 +2805,7 @@ void AssetImporter::acquireAssets(AssetImportObject* assetItem) if (AssetDatabase.isDeclaredAsset(assetId)) { AssetDatabase.acquireAsset(assetId); + AssetDatabase.refreshAsset(assetId); AssetDatabase.releaseAsset(assetId); } } From 48b512ef73dc9a111616f7bb84f02fbb8f7eed61 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 17 Jun 2025 15:06:07 +0100 Subject: [PATCH 05/23] move population of image metadata to onAssetRefresh --- Engine/source/T3D/assets/ImageAsset.cpp | 87 +++++++++++++------------ Engine/source/T3D/assets/ImageAsset.h | 2 +- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 7e0cf1952..99dc97eb9 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -345,6 +345,8 @@ void ImageAsset::initializeAsset(void) return; mImageFile = expandAssetFilePath(mImageFile); + + populateImage(); } void ImageAsset::onAssetRefresh(void) @@ -356,6 +358,8 @@ void ImageAsset::onAssetRefresh(void) // Call parent. Parent::onAssetRefresh(); + populateImage(); + } //------------------------------------------------------------------------------ @@ -395,46 +399,6 @@ 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); - } - } - - // we only support 2d textures..... for no ;) - mImageDepth = 1; - } - refreshAsset(); } @@ -675,6 +639,49 @@ void ImageAsset::onTamlCustomRead(const TamlCustomNodes& customNodes) } } +void ImageAsset::populateImage(void) +{ + 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); + } + } + + // we only support 2d textures..... for now ;) + mImageDepth = 1; + } +} + const char* ImageAsset::getImageInfo() { if (isAssetValid()) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index c60523b81..2300e0de6 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -196,7 +196,7 @@ public: static U32 getAssetById(StringTableEntry assetId, AssetPtr* imageAsset); static U32 getAssetById(String assetId, AssetPtr* imageAsset) { return getAssetById(assetId.c_str(), imageAsset); }; - + void populateImage(void); const char* getImageInfo(); protected: From 794a8c900de74f8afd7d9319d1fa17acee2d4832 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Tue, 17 Jun 2025 16:49:07 +0100 Subject: [PATCH 06/23] Update ImageAsset.cpp add change notification on intialize asset use this callback to update information about the image on refresh. Remove notification when the asset is removed and when the imagefile changes --- Engine/source/T3D/assets/ImageAsset.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Engine/source/T3D/assets/ImageAsset.cpp b/Engine/source/T3D/assets/ImageAsset.cpp index 99dc97eb9..bc831a2c8 100644 --- a/Engine/source/T3D/assets/ImageAsset.cpp +++ b/Engine/source/T3D/assets/ImageAsset.cpp @@ -213,6 +213,8 @@ bool ImageAsset::onAdd() void ImageAsset::onRemove() { + Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onResourceChanged); + // Call Parent. Parent::onRemove(); } @@ -346,6 +348,9 @@ void ImageAsset::initializeAsset(void) mImageFile = expandAssetFilePath(mImageFile); + if (getOwned()) + Torque::FS::AddChangeNotification(mImageFile, this, &ImageAsset::_onResourceChanged); + populateImage(); } @@ -389,6 +394,8 @@ void ImageAsset::setImageFile(StringTableEntry pImageFile) if (pImageFile == mImageFile) return; + Torque::FS::RemoveChangeNotification(mImageFile, this, &ImageAsset::_onResourceChanged); + if (String(pImageFile).startsWith("#") || String(pImageFile).startsWith("$")) { mImageFile = StringTable->insert(pImageFile); From 51b1e3b07ea74545444e72ca444f03c1141d48af Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 09:27:47 +0100 Subject: [PATCH 07/23] update cursors GuiCursor needs to be changed to use bitmapAsset guiTypes.GuiCursor safety around rendering getBitmap() --- Engine/source/gui/core/guiTypes.cpp | 4 ++++ .../BaseGame/game/tools/gui/cursors.ed.tscript | 12 ++++++------ .../tools/worldEditor/scripts/cursors.ed.tscript | 16 ++++++++-------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Engine/source/gui/core/guiTypes.cpp b/Engine/source/gui/core/guiTypes.cpp index 79d24b297..f0dbf8ebc 100644 --- a/Engine/source/gui/core/guiTypes.cpp +++ b/Engine/source/gui/core/guiTypes.cpp @@ -116,6 +116,10 @@ void GuiCursor::render(const Point2I &pos) { mExtent.set(getBitmap()->getWidth(), getBitmap()->getHeight()); } + else + { + return; + } // Render the cursor centered according to dimensions of texture S32 texWidth = getBitmap()->getWidth(); diff --git a/Templates/BaseGame/game/tools/gui/cursors.ed.tscript b/Templates/BaseGame/game/tools/gui/cursors.ed.tscript index 7e1ffbf7c..a4fff7628 100644 --- a/Templates/BaseGame/game/tools/gui/cursors.ed.tscript +++ b/Templates/BaseGame/game/tools/gui/cursors.ed.tscript @@ -24,40 +24,40 @@ new GuiCursor(LeftRightCursor) { hotSpot = "0.5 0"; renderOffset = "0.5 0"; - bitmapName = "./Images/leftRight"; + bitmapAsset = "ToolsModule:leftRight_image"; }; new GuiCursor(UpDownCursor) { hotSpot = "1 1"; renderOffset = "0 1"; - bitmapName = "./Images/upDown"; + bitmapAsset = "ToolsModule:upDown_image"; }; new GuiCursor(NWSECursor) { hotSpot = "1 1"; renderOffset = "0.5 0.5"; - bitmapName = "./Images/NWSE"; + bitmapAsset = "ToolsModule:NWSE_image"; }; new GuiCursor(NESWCursor) { hotSpot = "1 1"; renderOffset = "0.5 0.5"; - bitmapName = "./Images/NESW"; + bitmapAsset = "ToolsModule:NESW_image"; }; new GuiCursor(MoveCursor) { hotSpot = "1 1"; renderOffset = "0.5 0.5"; - bitmapName = "./Images/move"; + bitmapAsset = "ToolsModule:move_image"; }; new GuiCursor(TextEditCursor) { hotSpot = "1 1"; renderOffset = "0.5 0.5"; - bitmapName = "./Images/textEdit"; + bitmapAsset = "ToolsModule:textEdit_image"; }; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/cursors.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/cursors.ed.tscript index f281b653a..2a7400884 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/cursors.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/cursors.ed.tscript @@ -27,48 +27,48 @@ new GuiCursor(EditorHandCursor) { hotSpot = "7 0"; - bitmapName = "~/worldEditor/images/CUR_hand.png"; + bitmapAsset = "ToolsModule:CUR_hand_image"; }; new GuiCursor(EditorRotateCursor) { hotSpot = "11 18"; - bitmapName = "~/worldEditor/images/CUR_rotate.png"; + bitmapAsset = "ToolsModule:CUR_rotate_image"; }; new GuiCursor(EditorMoveCursor) { hotSpot = "9 13"; - bitmapName = "~/worldEditor/images/CUR_grab.png"; + bitmapAsset = "ToolsModule:CUR_grab_image"; }; new GuiCursor(EditorArrowCursor) { hotSpot = "0 0"; - bitmapName = "~/worldEditor/images/CUR_3darrow.png"; + bitmapAsset = "ToolsModule:CUR_3darrow_image"; }; new GuiCursor(EditorUpDownCursor) { hotSpot = "5 10"; - bitmapName = "~/worldEditor/images/CUR_3dupdown"; + bitmapAsset = "ToolsModule:CUR_3dupdown_image"; }; new GuiCursor(EditorLeftRightCursor) { hotSpot = "9 5"; - bitmapName = "~/worldEditor/images/CUR_3dleftright"; + bitmapAsset = "ToolsModule:CUR_3dleftright_image"; }; new GuiCursor(EditorDiagRightCursor) { hotSpot = "8 8"; - bitmapName = "~/worldEditor/images/CUR_3ddiagright"; + bitmapAsset = "ToolsModule:CUR_3ddiagright_image"; }; new GuiCursor(EditorDiagLeftCursor) { hotSpot = "8 8"; - bitmapName = "~/worldEditor/images/CUR_3ddiagleft"; + bitmapAsset = "ToolsModule:CUR_3ddiagleft_image"; }; new GuiControl(EmptyControl) From a276ad2505278918d90fa1353842c0435c2d7a4f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 09:29:12 +0100 Subject: [PATCH 08/23] Update cursors.tscript missed UI cursors --- Templates/BaseGame/game/data/UI/scripts/cursors.tscript | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/BaseGame/game/data/UI/scripts/cursors.tscript b/Templates/BaseGame/game/data/UI/scripts/cursors.tscript index ba81636f7..ba54e5bed 100644 --- a/Templates/BaseGame/game/data/UI/scripts/cursors.tscript +++ b/Templates/BaseGame/game/data/UI/scripts/cursors.tscript @@ -26,7 +26,7 @@ if($platform $= "macos") { hotSpot = "4 4"; renderOffset = "0 0"; - bitmapName = "data/ui/images/macCursor"; + bitmapAsset = "UI:macCursor_image"; }; } else @@ -35,6 +35,6 @@ else { hotSpot = "1 1"; renderOffset = "0 0"; - bitmapName = "data/ui/images/defaultCursor"; + bitmapAsset = "UI:defaultCursor_image"; }; } From 6f9c4158d86a44ba185037ae2aa073cc291ec84f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 17:05:35 +0100 Subject: [PATCH 09/23] gui offscreen material test added interaction static guioffscreencanvas to capture mouse events added test shape --- Engine/source/T3D/fps/guiCrossHairHud.cpp | 75 ++++++++++++++++-- Engine/source/gui/core/guiCanvas.cpp | 6 ++ Engine/source/gui/core/guiOffscreenCanvas.cpp | 4 +- Engine/source/gui/core/guiOffscreenCanvas.h | 5 ++ .../ScreenTarget.asset.taml | 11 +++ .../monitor_base_mat.asset.taml | 13 +++ .../monitor_screen_mat.asset.taml | 16 ++++ .../monitor_shape.asset.taml | 6 ++ .../gui_offscreen_test/monitor_shape.fbx | Bin 0 -> 23916 bytes .../gui_offscreen_test/monitor_shape.tscript | 61 ++++++++++++++ 10 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/ScreenTarget.asset.taml create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_screen_mat.asset.taml create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.asset.taml create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.fbx create mode 100644 Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.tscript diff --git a/Engine/source/T3D/fps/guiCrossHairHud.cpp b/Engine/source/T3D/fps/guiCrossHairHud.cpp index eaa318c53..6e6dc2fce 100644 --- a/Engine/source/T3D/fps/guiCrossHairHud.cpp +++ b/Engine/source/T3D/fps/guiCrossHairHud.cpp @@ -30,7 +30,11 @@ #include "T3D/shapeBase.h" #include "gfx/gfxDrawUtil.h" #include "console/engineAPI.h" - +#include "gui/core/guiOffscreenCanvas.h" +#include "T3D/tsStatic.h" +#include "materials/baseMatInstance.h" +#include "materials/matInstance.h" +#include "materials/materialDefinition.h" //----------------------------------------------------------------------------- /// Vary basic cross hair hud. @@ -46,12 +50,14 @@ class GuiCrossHairHud : public GuiBitmapCtrl LinearColorF mDamageFrameColor; Point2I mDamageRectSize; Point2I mDamageOffset; + PlatformTimer* mFrameTime; protected: void drawDamage(Point2I offset, F32 damage, F32 opacity); public: GuiCrossHairHud(); + ~GuiCrossHairHud(); void onRender( Point2I, const RectI &) override; static void initPersistFields(); @@ -95,6 +101,12 @@ GuiCrossHairHud::GuiCrossHairHud() mDamageFrameColor.set( 1.0f, 0.6f, 0.0f, 1.0f ); mDamageRectSize.set(50, 4); mDamageOffset.set(0,32); + mFrameTime = PlatformTimer::create(); +} + +GuiCrossHairHud::~GuiCrossHairHud() +{ + SAFE_DELETE(mFrameTime); } void GuiCrossHairHud::initPersistFields() @@ -114,13 +126,14 @@ void GuiCrossHairHud::initPersistFields() void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) { + GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; // Must have a connection and player control object GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; - GameBase* control = dynamic_cast(conn->getCameraObject()); + /*GameBase* control = dynamic_cast(conn->getCameraObject()); if (!control || !(control->getTypeMask() & ObjectMask) || !conn->isFirstPerson()) - return; + return;*/ // Parent render. Parent::onRender(offset,updateRect); @@ -139,11 +152,61 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) // Collision info. We're going to be running LOS tests and we // don't want to collide with the control object. - static U32 losMask = TerrainObjectType | ShapeBaseObjectType; - control->disableCollision(); + static U32 losMask = TerrainObjectType | ShapeBaseObjectType | StaticShapeObjectType; + //control->disableCollision(); RayInfo info; if (gClientContainer.castRay(camPos, endPos, losMask, &info)) { + // is this a tsstatic? then it could be a offscreen canvas, check the list. + if (TSStatic* ts = dynamic_cast(info.object)) + { + if (mFrameTime->getElapsedMs() > 32) + { + mFrameTime->reset(); + + Point3F newStart, newEnd; + ts->getWorldTransform().mulP(camPos, &newStart); + ts->getWorldTransform().mulP(endPos, &newEnd); + + newStart.convolveInverse(ts->getScale()); + newEnd.convolveInverse(ts->getScale()); + + info.generateTexCoord = true; + if (ts->getShapeInstance()->castRayOpcode(0, newStart, newEnd, &info)) + { + MatInstance* matInst = dynamic_cast(info.material); + if (matInst) + { + Material* mat = matInst->getMaterial(); + if (mat && mat->getDiffuseMapAsset(0).notNull() && mat->getDiffuseMapAsset(0)->isNamedTarget()) + { + String canvasName = String(mat->getDiffuseMapAsset(0)->getImageFile()).substr(1, (U32)strlen(mat->getDiffuseMapAsset(0)->getImageFile()) - 1); + for (GuiOffscreenCanvas* canvas : GuiOffscreenCanvas::sList) + { + if (canvas->getTarget()->getName() == canvasName) + { + if (!canvas->canInteract() || canvas->getMaxInteractDistance() < info.distance) + { + break; + } + + Point2I canvasSize = canvas->getWindowSize(); + Point2I newCursorPos(mRound(mClampF((info.texCoord.x * canvasSize.x), 0.0f, (F32)canvasSize.x)), + mRound(mClampF((info.texCoord.y * canvasSize.y), 0.0f, (F32)canvasSize.y))); + + canvas->setCursorPos(newCursorPos); + canvas->markDirty(); + GuiOffscreenCanvas::sActiveOffscreenCanvas = canvas; + break; + } + } + } + } + } + } + + } + // Hit something... but we'll only display health for named // ShapeBase objects. Could mask against the object type here // and do a static cast if it's a ShapeBaseObjectType, but this @@ -157,7 +220,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) } // Restore control object collision - control->enableCollision(); + //control->enableCollision(); } diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index d00c3024a..b14f7ece2 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/Engine/source/gui/core/guiCanvas.cpp @@ -690,6 +690,12 @@ bool GuiCanvas::processInputEvent(InputEventInfo &inputEvent) mConsumeLastInputEvent = true; mLastInputDeviceType = inputEvent.deviceType; + // If we have an active offscreen canvas, give it the input + if (GuiOffscreenCanvas::sActiveOffscreenCanvas && + (GuiOffscreenCanvas::sActiveOffscreenCanvas != this) && + GuiOffscreenCanvas::sActiveOffscreenCanvas->processInputEvent(inputEvent)) + return mConsumeLastInputEvent; + // First call the general input handler (on the extremely off-chance that it will be handled): if (mFirstResponder && mFirstResponder->onInputEvent(inputEvent)) { diff --git a/Engine/source/gui/core/guiOffscreenCanvas.cpp b/Engine/source/gui/core/guiOffscreenCanvas.cpp index 522882b14..55562b028 100644 --- a/Engine/source/gui/core/guiOffscreenCanvas.cpp +++ b/Engine/source/gui/core/guiOffscreenCanvas.cpp @@ -9,6 +9,7 @@ IMPLEMENT_CONOBJECT(GuiOffscreenCanvas); +GuiOffscreenCanvas* GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; Vector GuiOffscreenCanvas::sList; GuiOffscreenCanvas::GuiOffscreenCanvas() @@ -33,7 +34,8 @@ void GuiOffscreenCanvas::initPersistFields() addField( "targetName", TypeRealString, Offset( mTargetName, GuiOffscreenCanvas ), ""); addField( "dynamicTarget", TypeBool, Offset( mDynamicTarget, GuiOffscreenCanvas ), ""); addField( "useDepth", TypeBool, Offset( mUseDepth, GuiOffscreenCanvas ), ""); - + addField("canInteract", TypeBool, Offset(mCanInteract, GuiOffscreenCanvas), ""); + addField("maxInteractDistance", TypeF32, Offset(mMaxInteractDistance, GuiOffscreenCanvas), ""); Parent::initPersistFields(); } diff --git a/Engine/source/gui/core/guiOffscreenCanvas.h b/Engine/source/gui/core/guiOffscreenCanvas.h index 0d7a79d35..de8c221b8 100644 --- a/Engine/source/gui/core/guiOffscreenCanvas.h +++ b/Engine/source/gui/core/guiOffscreenCanvas.h @@ -38,6 +38,8 @@ public: void _teardownTargets(); NamedTexTargetRef getTarget() { return &mNamedTarget; } + bool canInteract() { return mCanInteract; } + F32 getMaxInteractDistance() { return mMaxInteractDistance; } void markDirty() { mTargetDirty = true; } @@ -59,9 +61,12 @@ protected: bool mUseDepth; GFXTexHandle mTargetDepth; + bool mCanInteract; + F32 mMaxInteractDistance; public: static Vector sList; + static GuiOffscreenCanvas* sActiveOffscreenCanvas; }; #endif diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/ScreenTarget.asset.taml b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/ScreenTarget.asset.taml new file mode 100644 index 000000000..fc9196375 --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/ScreenTarget.asset.taml @@ -0,0 +1,11 @@ + + + + + diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml new file mode 100644 index 000000000..75d507122 --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_screen_mat.asset.taml b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_screen_mat.asset.taml new file mode 100644 index 000000000..db7490eea --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_screen_mat.asset.taml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.asset.taml b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.asset.taml new file mode 100644 index 000000000..1a8665bbd --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.asset.taml @@ -0,0 +1,6 @@ + diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.fbx b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.fbx new file mode 100644 index 0000000000000000000000000000000000000000..3acc77e04f80a98e20239215f1ef3ab02cbb053e GIT binary patch literal 23916 zcmc&+2|Scr*dJ6XqD6bQHm!t8SwoT%l}ei!W=wM%Gt3M|W2tCWwA`DNrS-b^rYN^m zb}cB)blXt2D3i!oLiX=DGw(3UR(;>^J3sHd@0@d<|9Q6aob#S@#%jD50Z+%PtT5TE zVnU|k>0T--xJkH=Q*gMu(zwnv8p>A^@dP5>jKw5U8DtuDI}}R5H5jguoyD7obW~_j zA%(-S#A*zO8lo};enzZJ&W!3r_i|+d-3BjLq6HM;_9AF3jWVSZ@q$va3()9&vRTio*RM&?4B6UqIb)9Gs5P_<}HO$6| zNF`cOooO~>;j1}?=7^`DuQ-XWlA%ztkwK&{$20MYKnV=sM!+=)Dc?rCbTL+nOx&qv z0(=<)surc8Yluud!Xormn=Mu_cmtV9A=)6~-^H?}ZQLDyBRVk!1<_&!LyX;-J3%9e z;E`DV(A7jQPa2)T5R?>)m#imxkdY4xN}9wRB`6PWI6*}XXBw!VuI}u} zip5~`p$uT;P!+n<&mffm(jXw8E<{4svZj+s&~qsQ(}9StGLLAgFME^~E>j~Kk552Z$ z-0@<#-}pHX179WtpWF*L*7?&=vftFIcePC9z;Sf#+?LlOiV7MrB0Gxv@Q#SUMu8gVsFrW$k&H?Gca^xAv%l*y)iBr zPx`a(H1IE^2P+}mxNdMFd;X+>Ph!}3A+{3SI(;<+M(N7ObuVeunOLD?t$cD&dLY!m- zV%W%BorB6p2y2;QG~I&mTcAL-XTt^k0u9|8U5!~}h9KsWA)uq^VnJmRNkrjDVF6Je zHx4=wB11v|*>JdFWMmSxcT%LRwHWCy$KHKep zl=*$TrZgDk`feB6zzqTMkg#Iyc2V}(F5=n@qt=9H;2MojA{XyZ(}?Xu82KV0IT|g# zA@7$14hFGA2!ZBY8>wWbjT4?iT!D9D!q9~5PN2C%ClNeaxw|-G=3WjZkgAQQKtx4a zSOyo!fjqpEksn8+0~+$Il|nS+p2jYYWElHRX%t`x+!7~vT5oP*gPIj)!vhZEsHcZC zj7MXrhIz}tb>aezo{T=7(xUDKHYSyl_O5Q5+V?t&Qvy5rn204;b1 z0Hl~M0GeyB^szY~QxO9R7`>RWP2Cwxn#&40s9-&e$Nd|7=`sN7B}pR(#?mm+EQ=ut zoe?=Z5`C~K%wm`p=xZ}%L-fHZ!ZlP>*)rGT8B!%qAd6t`-1Wpoy&6m10@Yq9KpL9~ z7p4~*c!O{vS_>z)$b)HJ^IU;h(t$?I7-OJ{vB0p#RI&@0!)aF^11wbTo<0K_5(-7E zq3dZhrWN>sW%oKgeVZ$$vEl29&O|zq>O^F8t2%#P*H;;ESu*q}m}WD!1FcA}odKNy zbs1s>n8HzaO2e{|sKbSt5xjXI7P=1=|9%gE8tRs$VZwznkxj(WkoC-oG#4V1?$!D| z4jLeuVZ217$bUy-vwp7)L>E^I@<7Du3P;u&B4g)gG_Yc+o57DkoI>@C;R1srJN6$M z&W55?ZnXTnhawDaxeyK^o0!m8@V+UCHJhNv)9BjE1)W3qMc_iHx*&c3pb4BKm~RpB zte-`s0wR)A11=C5#rm~$vI|-`*aWX#j${g%=_QCfjx-wfHUxEWg1+`AMm$GIjBI8K zGhBv>%}zXl=E>-dt{9_39te%1(P2H&i3s7ZKT4=Mko3=Vp(~*1B<@8>QWQ!lMwpwS z49u623x#8JeYz0pgU6wwD0Oq8Gyq1RSS&@;xpnT~e{?EZMu9mE-IXTr$3al?O)y7* zlfVMV!mHr|)u2wap2mc^D2;0E?93oCf7Z}+40x3g7}-h$yq4@i`)SG6Ql?WA-~8X8165zYX`8%KI%ePuoi9u9ZzL|O+dxMP~DT;LOtAVj3qJKh|&H+ zx0Z+5z&A!02mblqZ2`bYTCt8M4os$Q?oC$z{wTNfMw!$f<<{OP8~dijvwG!L6Z%;n za^hLNa=WWP%3is>gi(qGKT(IWro&2~K*}C^I1i&+40eGYj$Xt?bTDOeBCep(Ey*rq zrZtt)W8j7QxCQV=jO5jW3ya#F7)-LWGnL3-Z0>*3g~NFb0BFlVfYJv5v~?grIGE)l z(H00rL)`+sE?E+({Zmh0wh5>a$x0zLOr~KtBX;Tr%_4qc*u93Kip8R}GzRlmVaqU4 z=L(q>kM(^AB7In!`$kF;FTW6lPWFNN^C2h;P?0@n3xz~+T#VOVdo&LEMek(2c4wVF z$$IU})IP}i2s>B$BWyz10#^c9_GL@={I`m;bLfkzSJR#D zi>g=4W%o|ihj&TB8ecDR^)a9=>5HmY4nu$nS$iE^FrdIdEPC4_JBiI0es=O%hrwG3 z;nA!Mdzm9UiK4;JVq3wRK4N{15F1`Cy09@n7znhOLv^~?Nq|Ncz=moxX9nkA4m+0X z@l+CVKqKtyzA*+gxK4sa>OS}w(73vz2Mj#x$7H$KH^zWuDeD_!K(fqN7V2YZm&q}^ zz~&v1N@DIDkZG9x!VE~FgnnTLB$TAe_d*E`^g}{f^b0c}p^oJ_f-#ju8CVyZq$<=*Zy*B_$i5$t0g3YmfS_>}8-me{&5}mjWsJ6b&?d8&V2=9j zn&4B63LAn^gxcsToQC#E*NU+WHx!gn!!|ogUI|{t4;IQ>J75Yc5#!y!XQPKPjp^C<+Z@+(s+0zKM zV7k!e*m4t^rHL)uee<;kM1PFl49Y-Kc!?9ESHY&2cvw5`t4M&0J_L(`=wSd!1=b{x z9nhdEzCZur{lh**)!r_!* z{6WoP3kOJF*06MhR_ceqbMLlh03oWq0xqyM+E%in(OvMAHF(#7Op<#FmgyKK=0Ae~ z)5P87r{Sbvp#aIIEo2e(DFi2`mwq;lcK`sAag7jQ6x^1R8L$cDL`3Jj`rpt20zvxT zc2O8_dQcAPL$(u#9ypIf=LmVU5dy(F5VkBO4)-gZ+Cl?Jiqw7g)HAh>-*NzFTn~%h-o0c%?*kq?Mo})L!#=6aQI+C_(i%ej#$yr&8>E}#b z%>r%>9pj{OId)y1Nk0GcqX&@`g~?;brK?;&vwr^6*+=<_cS-u}xK~ab&$8^hyogYZ zfM@FJg;VyAJlmEMagIZ(uYDB1#GsIB)S*_B{?=2+-t9y1`EyMln9UFVkXQU#yNz?QHo?Z`YU;U)VDF2qBR#yO^^-IcF1CL9!`3FvljeQBl|?L>Q>`2M zIEH_>W^nc5$j7vs>aP0cO)jqo2k~a5us?G~yJlZ#J?YkhD1%kaxHFZ8bsO~~QjG-T~C+FDiUN4(4K$o9GFeV$*3ugdjrCZP{yW_&K~ zZqetE6Mn{%aH zYs;0{YYp3+r+KKC-QEK zw{DZ+ECih@-Ems4;e4yHXJFgumIB}Mb49A3v^^2aGR-l*XJnv^Nv)Z5Jt67sA?g0`cSfr3x|G@w^xDIm+I8M%D6m5xO+5 z9TBFHtL?HcEb(!Wdswa)#8os&eyOI+u#~a#fn3IeDMw!DG%jmfUUXZhRu*yOed;b7wj5acQr=zjV2Qtc#VGfC#|{s!KAWT+ zcgg!e9pC3jg~!{&`=Wvi!%R{RW!TRwddROicgyKTrx&#uX%1l1gihBg{Jfd+Ifs7E#&wyz;Nd9gAC(gOv66B#n&n-PNY-TH&|L zM}^a_^IEy2(vQTR#%Wip80FTGaRHd~iO{@+x+O4$RFmnv+rGAGL;Y?kf2Lw$Nv9hFaxY28A z6fY8uiozL@C3uAe>ou}7LFeiC>W>i*HRZ+t^RcEfr@SH20UE&fF z#*X?X4G!gHwv|@1Iduh|jV)C^g=Wi_FDLA!RO@JKYw!AtaU!Lrk|5_gqPe3k>}7*{ zPE&MbM;iNtmx^-!1NOmtI4>!_>DKZ4Dp*Bp$E(J?Yg<|2=sK3K{Au+2vEDec-Ej3% zDO0-xi2?FcuRTdK^LG7f?(y-}s+ZkoED4q$;Xbx@is8|Jg975dR|mR0woj=#3UYZxwiS&(ILhs4W! zv~0NHu`h8Ev6CZ}ej^o+EA;=Dx4ktz;e??Re{tb{raarT+UjyqTA^K{RJrHBp7J#F z=E;=>8E=obuVBkpZz3$rWgm)HF}Spo6`(WCz?2{U2`I&{< ziAv>)Z`eUOs!2|4jq0tJwH^2~cK9<_R3@cgJ;6Dil*8Kid}3VVkQhr{|AxYnu@~p{FRPz0XPAjsr|?Q|#Er zjsUj$L3bAWxq+>z{*C}9H!pTf@bm(PCMEscsj7+cS8F0Jvv*fLsi9wHtMA#6ALq#( z8#}JCvOs%Si7U6zfR`$V@@B-2LU|IS-MEJG*#UNUZWZAT2*p*Uw6`N(xOQAmA!^S{ zx8r#l47=pYOD8p?ZpdF+9XdaDq^EM^(!s0U_^(I}=?eMmFQE#D(vqZeD*dzW@T$&k z*t~~Ly`Cq3%9UH*QE=u?%8NzP4pWs(?>SG-z8`LyGbLbW{$0jXk28U4C$BFZG{%+p zV3D4KT$O=ZI(|YhJLY=cusApV!$syQ!yA>hpBfTZO?bY@96zOsU2>Lr=5Wgnmh)u% z#H#$3Y|ROQdOX8Z656i3H>Aa>qx0|9hn6lF(x~p^Jl--RX?0}YpuifxM*J2&16C$c zKd*p~!Da*!kwKmZk0`4UK3EcCpObf?g^g!<3v@zvJ$Uo__U1T>>b9Ywn`dsjz4N;S%xRH#vz-iOW}QF2UtwML)NyeESALH@ z`XSn3#?@KGMY}dX(S2?6XvpH5ho4gLbKmB2 z1Cu!Go(xuZ3)Q_&51;&!5jdpEHMm9p{itL57Y>sa*6ka&qvk+-B2OyvYqo82jelfo znf$d@?u6yr_LVOq-Fp_U6!0v>H{f}sge+ksK46UT^mWU}+;=!Ia`hC`!=wqrrfcmx zG5tjLghyHt!!9p4Jp1y=M+={4fh0GxR73P@Lo>XG&$@ib5!fGn`o_NXuh&1CdHZI# zVx_b4hYhZK{5R0g%n70&9kYRPtM zOO`%Oyu3dr@tq>SDN`-E`VW3<@%WUc)pPgmm3tQ9p!?skh*qiEiX#iA84E3qX0xLO zD?erw!JDS=%^K#@I9x2|AgE5~nMxvjc_daaNN_R~Rd2&`(E`^vcr|y01u68iFL+Z& zuNZ>uUi8*s;?-?XSqLk?$mh^|>4eTxpWhOq6&b)Bapzvu1RhYsB=4`#5J7tQ_;T%rsO}ZLrP=W2P^!o%7*ok=MEV zElCWn0ngL0%E#=+bH=4xqqi#PJetH>!YUe6SRlRHPpvIBUd_iox&7lms@}mla>q=a z+iY97B}r%bVN=GG7x_4h;t#GbN&QE)cz<4Gf#16NqISx<`V_l2yCsW?^u5R4@oWCF zkZ||&)u>Hhr0$h(DYHLQVURGGWm_~mcSMJ8B5uodrLet8j*ee!6K$u~7ql*I=h9LG zH9YJOeklw78q-|Tq16`DWVAQIT3TJo(>djsZ4-e@PcDy|9I1P_zP|ZC?cWZz-%)$c z*3@(#-7~Ee+}g#`>C^ zX0D{?0h(3fL4$)ak{Vh5Z=WPmbPcX~IJ4tb?5#c-7rp(I_MefpUtHvRwPzX>zqhun zIc*R8R(c+44^%4j|C%>C?~A?Ln++LH3f#j$+ZqE|^nyi8M^I;P|#H|pR*%qtdhzBIfm2>vtqFT)}q z#b*4WL{0l*i94^(z1l)_&uHDJTyNUCZ{E|$(6;e4J1SQ*&Y!Vpk~BJUDzeh3Xj;?U z?4Wn)=dNqFmYuBKX4rC~VN2S*+AsH6PZ}mKsbs}XtB>*6(!ufjm}cGdOk?uysP>L0TuJKmKiZ{Yi6J%8u!k+foi*s2P9OZCm(zcGi=E#?pjWrp5Zk z$`$R8xXiO^R%M5)xW2}Tx%|_tiPl-IIoYT0V%1x?EdloDKIOkne&Ao6oAb%2 z+SexAjZ=`sFeo_`Z*;m0*OFan{n}bjFUl zLR)M1oyrf=PAGm=x4xHAvwd-)L7hY6-b{V3viYT>Lz-1&Y%K5DCy5mV$)#h=u zoaz~N)}f_0*~7RU9{H@y*6PHei5ZWsl`Bo&B0t0HxUYS1+uUZ`|LmXG-kSZ&zn~?$ zeQpG4agIyT%%CL{&W24P(Kc7Pzv&nF8}J`4wjH4p>Q){z?kmynUBvlzoht3GJKW?p z95wp)DR))b%rA*g*S&~m58*4;>lBsyJgidwk8{6~WAIOlVbku4fZQ8RXG@7bJVS?Y ze^RyN6s@{!L-V4m9br<%BX)lc#!=fgX89MnHpg6j)9(2j$1RL@ z'|969^-dX?j^-rridm;HEWb6CgzaH-11v%G}(4yAVKv<}S&Sxw<>YC(6H%4P9} zA?^H1BktFXjHa0HwED8(2QrC-?UVQ&W>Y1nj>CqpC-5#J zi$(wLZzsu6!jjndqA}++V@gKNN&^4n#>~QVC#e&!;G?vjSb3T}IYODEr+Vpu@~5UH zyt@0>7)rdv>p3kiyzCnrTkig8eQvQ!vqDBllJ{q`hoC{bVW07i2p9jvseIYm{KN&BbL$FK zXxu>mMD1X?+MxW!nUia)RP4`~4{18ks+Y+ly;4zrT<@Q#QzToPo~WDIQum(^q-H}zK0smYbVSoJjJPO zUOg_IgpWGe-;&ug=1R~_b52Hi2&joVflQJ$?7#QsY=Vd>k8+6kIfH#n6KD91RJ zd6iJ7v@(cOS)a|VI%5~%{$Hq1sQ-VVcAHUi-nMdb6-j%165bsi%y1nge!RF zStX1k*;f8rQBrv{+`}NG?Z%7iPFi{%Z`_?XJ+MlU%b>loN@&kMn@i5o*fLV@v#ze5 zW0YMK!3jw2XCDdo@Hu(+MxARr=K|F5%2Uw$+`Om-YOF5JdrJ=SEbjcwxfl%%C>|!! zqU;LO2#a|qS<*N84)Ik{VTPGp0!PJ9u~D+gf5|~_t1weTRgP+kGVgeBAR}|US#ay} zFPZXY!QL)kGAk~b8!p}bzT&3uaoQ23rq3Tw@Swo+OJ*>!P{nVYL2dYd)BHvm)Xs(5 zSnjZ<;3WrJox)6gwK=NXqm0bLD~wD=$&^~ZszcFcFpudl7?&cl<+I6(>5JGS#b-E6NR{OM!Z8t##OEbxMl*7lm0-W0}9iu7YXrEIQ0x@|}O_UPS@uFZY5>&B-Wo9k_(chA|Bq_8U@@K*c7 ztz5@zyf;@BuPIZxMxQg-cP7R(Os0N*qw(;c4#!s-R6BCg+du9RjT{@K{xoz;*r@zz z-j<42Cht!zDm-cZx;eyKtCZ(;@|NbKNpF)EBg8yA(XDf6*13~e-M zB78d5db=#KxShZmQ=1j0^ZwNM+e%qswqGK%y;c~8)&+TMwS=P@@1ceb)QEq7%FFtM zby?y}r~w#t5#Cz-ZM9k6Mk3YL*k^G{N8VLWBt2b`YS56q zBCRo&w0Kf-ltG+kwP&vOWEnqrbgQ0H8G7s>kHDo!K6l_!rs|W}&ZpiPuf8$b=p5wU`!;|nK zQF1~yZo>4`h&+?8egusnfyalkomY>PfsYfCZ09G%9XAZ(KCIkl5I1(^euKC%nJeV1 zF3Ntm6P!@J?aBR#?=MQ(eLZUZm&u5Ti<9=xN*}vD-TKQ#`IKjSW-h!m>WXVr0(F{9 z6*GkYO3w3Mh18sPR-R_-aPTO(yV%Op$6PVL{QByS5O@Scr;%5#4MIs;Z?PA`fSg8 zPxOQZ=f}5A*yDLzqA0E4;Jb)fN~NP(6WUKJe;vZ}woN%!S{?5FC{Mat5k57lY0XFD z%!`xYv$5C!KEtb(!ZZ`4xCNnB-T}O_qj_ssR-7|Q2UA{5jH{@Y4cBDLa8oD7UEO&= z+nHAES$Z^&xG;TUTuyaFxMsqk-AkMrh8G5EJM-Qdz@ubgsJ1ido#Ilb23em8srIeL z>d@$mzYcJhv<&jiF)Xd55$==1o*F9{mPUJivV-;u%Z+XqJ)8kSt}DGY?+WA!;(=Ur zd_)k==Ze+p7S4^u3c6msU9ntQXs5SVZ)qqqrci9)$E{IV^&gDj9E=R@J`NMH%OIm5 zjuLEeeV;afIH&>|bOsB=704&EvMak&J_6KnhXPTO6<3cXMll{rh5sZ5aW7s&I1St> zhCCdtIS>RfNzkeYSa5&aTT3@F1o+()){@}F96B9?t&wcp#2IKS=3)(ZlSc_t44kUR zT0z6GxI7{a>tZ#L3j34@%6m!gtb5uY&7n#nZFbuq)#_n?^r5&6*x5h9Kc?x{TA3J| zJ?@Y0TqU%*3y^i~k0O^v$wBamI}blfO@YT{i%KpC?pr=&8Nv5&^UsgER3pkq_dPn_ z*B8$h)W3{zfPQ7&)6Ry-gV9blygmqik&T=eoeg{;MvJYMidTnP0zVg#jkN4?@ZQ$f zMy~Fv)7c4#05nsqpsSPHVYxpzUHcs)`@zos6eB~?t8;w~#&bbJCo=?Tk8`r{p*jW2 z!AW6~BPDl#HTzayB8uDFsPEvSJ&2HqQ@8|b8uNA*{=AUU6l<%21sM^RL!$u13oN|fl z7O4(d3i;x9X&W3p73sG3@#m_T1-fZCO{}2HHLI~)S!iwmTN7CPl40QdD!AWGfhbv8!P-}v)U47tx}y$v`MrEV>0VJ!DG{#c2L)n_Xi zy|og7A@o1~+#6_HB5A(A|GiG=k#nF3{`VdHl-<%_B6~inXoJLbp~1g#pwaCe@eCqP zLU@W5c{Dnmvv_Tn1v^dk5enx4s3>(iAA1QX&};`gFDL_#KXhby%d+J{T(O68z(fNu zc1(RNJpSMTa|EdjEF+XzaKVWw#92Q-hC{yFEv*CykwXvfI=3qrqMgLbh6&0x;CBiC zm7y0_gkpj;c3Rj}A`HuwN4ci%@E-!?k>Hq!y|p z_+Nh_J2IT$*gW-HOXAjdvEI#+4NxFT-7M(>1^?TYj04PHw`4hn@(Y$64a)4zlJmvN zzOke!R@B{+&RFh1Eoo>gv?S_-Lq#)9%e_HmlkV(0?Od|0mj^k!4ib ze+0iT?f!5IV@FfS4iazRC)#niml(OWkQ~|aM-DW@|AyQo6h}rGf#Qj1c z1bV^vp`)@;zt?032VzlB)_|+4D@#6(MXlg$;76>T&zybzw`D1b!PM)DDd{~4<|7=F>m{&&iowkzVS8@-T=G}hg041 zop`^}nH>NQvGbFi`2t4%)1A2n6Gu$FqR!WMXYOt#)R_f2np?k9uLy4d>V0NJ!RUXY zGsj@0ztEW_z^PHBM&dvyK|^j=XZ|UDm;&PeRd@jIx{}xSu4frj8kH(M{?GUuiy;%C zSi;ms5^mPkopW?}2NtGhJysJ<0XwTT_E=4H9KRD*37A2Ft9zrORVhmmtXYrML{pVc zG)j-vL}9QKO(croenU(hgV9`>aT#(t1EHxq9sObo<}-bz=ESSRo@KstzTwg0Kc#V| f@Aq}l{~G`QN?*4g{jIP*&$qH%w$wd%w#@$kIf5Lq literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.tscript b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.tscript new file mode 100644 index 000000000..18269168b --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_shape.tscript @@ -0,0 +1,61 @@ + +singleton TSShapeConstructor(monitor_shapefbx) +{ + baseShapeAsset = "Prototyping:monitor_shape"; + singleDetailSize = "0"; + neverImportMat = "DefaultMaterial ColorEffect*"; + flipUVCoords = "0"; + joinIdenticalVerts = "0"; + reverseWindingOrder = "0"; + removeRedundantMats = "0"; + animFPS = "2"; +}; + +function monitor_shapefbx::onLoad(%this) +{ + %this.addNode("Col-1", "", "0 0 0 0 0 1 0", "0", ""); + %this.addNode("ColBox-1", "Col-1", "0 0 0 1 0 0 0", "0", "Bounds"); + %this.addCollisionDetail("-1", "Box", "Bounds", "4", "10", "30", "32", "30", "30", "30", "Flood fill"); + %this.setBounds("-0.8 -0.244957 -0.0409516 0.8 0.244957 1.10231"); + + if (!isObject(screen_Canvas)) + { + new GuiOffscreenCanvas(screen_Canvas) { + targetName = "screen_Canvas"; + targetSize = "1280 720"; + dynamicTarget = false; + canInteract = true; + maxInteractDistance = "3"; + }; + } + + if(isObject(OptionsMenu)) + { + screen_Canvas.setContent(OptionsMenu); + } + + %screen_Canvas_asset = "Prototyping:ScreenTarget"; + if(!AssetDatabase.isDeclaredAsset(%screen_Canvas_asset)) + { + %screen_asset = new ImageAsset() + { + assetName = "ScreenTarget"; + versionId = 1; + imageFile = "#screen_Canvas"; + }; + TamlWrite(%screen_asset, expandPath("^Prototyping/gui_offscreen_test/" @ %screen_asset.AssetName @ ".asset.taml")); + %previewModule = ModuleDatabase.findModule("Prototyping",1); + AssetDatabase.addDeclaredAsset(%previewModule, expandPath("^Prototyping/gui_offscreen_test/" @ %screen_asset.AssetName @ ".asset.taml")); + } + + %mat_asset = "Prototyping:monitor_screen_mat"; + if(!AssetDatabase.isDeclaredAsset(%mat_asset)) + { + echo("Material asset not found, this should exist"); + } + + %assetDef = AssetDatabase.acquireAsset(%mat_asset); + %material = %assetDef.materialDefinitionName; + %material.DiffuseMapAsset = %screen_Canvas_asset; + +} From b5cd9d0c730f46476269e1253f8296481048c9e4 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 17:08:40 +0100 Subject: [PATCH 10/23] Update guiCrossHairHud.cpp --- Engine/source/T3D/fps/guiCrossHairHud.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/fps/guiCrossHairHud.cpp b/Engine/source/T3D/fps/guiCrossHairHud.cpp index 6e6dc2fce..f8d5afdeb 100644 --- a/Engine/source/T3D/fps/guiCrossHairHud.cpp +++ b/Engine/source/T3D/fps/guiCrossHairHud.cpp @@ -131,9 +131,9 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; - /*GameBase* control = dynamic_cast(conn->getCameraObject()); + GameBase* control = dynamic_cast(conn->getCameraObject()); if (!control || !(control->getTypeMask() & ObjectMask) || !conn->isFirstPerson()) - return;*/ + return; // Parent render. Parent::onRender(offset,updateRect); @@ -153,7 +153,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) // Collision info. We're going to be running LOS tests and we // don't want to collide with the control object. static U32 losMask = TerrainObjectType | ShapeBaseObjectType | StaticShapeObjectType; - //control->disableCollision(); + control->disableCollision(); RayInfo info; if (gClientContainer.castRay(camPos, endPos, losMask, &info)) { @@ -220,7 +220,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) } // Restore control object collision - //control->enableCollision(); + control->enableCollision(); } From 1918ecfdd6ab7dccda9f272c1a23bb47baf1ae7f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 20:44:37 +0100 Subject: [PATCH 11/23] feedback from az fixes for interaction from az --- Engine/source/T3D/fps/guiCrossHairHud.cpp | 3 +-- Engine/source/gui/core/guiCanvas.cpp | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/fps/guiCrossHairHud.cpp b/Engine/source/T3D/fps/guiCrossHairHud.cpp index f8d5afdeb..052350be1 100644 --- a/Engine/source/T3D/fps/guiCrossHairHud.cpp +++ b/Engine/source/T3D/fps/guiCrossHairHud.cpp @@ -126,7 +126,6 @@ void GuiCrossHairHud::initPersistFields() void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) { - GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; // Must have a connection and player control object GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) @@ -162,6 +161,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) { if (mFrameTime->getElapsedMs() > 32) { + GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; mFrameTime->reset(); Point3F newStart, newEnd; @@ -204,7 +204,6 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) } } } - } // Hit something... but we'll only display health for named diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index b14f7ece2..c9f603d05 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/Engine/source/gui/core/guiCanvas.cpp @@ -694,7 +694,10 @@ bool GuiCanvas::processInputEvent(InputEventInfo &inputEvent) if (GuiOffscreenCanvas::sActiveOffscreenCanvas && (GuiOffscreenCanvas::sActiveOffscreenCanvas != this) && GuiOffscreenCanvas::sActiveOffscreenCanvas->processInputEvent(inputEvent)) + { + GuiOffscreenCanvas::sActiveOffscreenCanvas = NULL; return mConsumeLastInputEvent; + } // First call the general input handler (on the extremely off-chance that it will be handled): if (mFirstResponder && mFirstResponder->onInputEvent(inputEvent)) From 26e18cdfe83666c1665ffa3daa5da23ca1fe8505 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 18 Jun 2025 21:17:13 +0100 Subject: [PATCH 12/23] feedback from az scripts changed to reflect a better standard of loading offscreencanvas on client and not on the server --- .../game/data/Prototyping/Prototyping.tscript | 15 +++++++ .../monitor_base_mat.asset.taml | 1 + .../gui_offscreen_test/monitor_shape.tscript | 41 ------------------- 3 files changed, 16 insertions(+), 41 deletions(-) diff --git a/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript b/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript index c053fd2cf..bd3841f9e 100644 --- a/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript +++ b/Templates/BaseGame/game/data/Prototyping/Prototyping.tscript @@ -42,6 +42,21 @@ function Prototyping::initClient(%this) //This is called when a client connects to a server function Prototyping::onCreateClientConnection(%this) { + if (!isObject(screen_Canvas)) + { + new GuiOffscreenCanvas(screen_Canvas) { + targetName = "screen_Canvas"; + targetSize = "1280 720"; + dynamicTarget = false; + canInteract = true; + maxInteractDistance = "3"; + }; + } + + if(isObject(OptionsMenu)) + { + screen_Canvas.setContent(OptionsMenu); + } } //This is called when a client disconnects from a server diff --git a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml index 75d507122..6267d5871 100644 --- a/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml +++ b/Templates/BaseGame/game/data/Prototyping/gui_offscreen_test/monitor_base_mat.asset.taml @@ -4,6 +4,7 @@ Date: Thu, 19 Jun 2025 07:53:32 +0100 Subject: [PATCH 13/23] Update ImageAsset.h add check for if _in matches the filename that is already set for image asset, this stops the set being called twice when loading the same image asset --- Engine/source/T3D/assets/ImageAsset.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 2300e0de6..102f59052 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -123,7 +123,7 @@ public: }; static const String mErrCodeStrings[U32(ImageAssetErrCode::Extended) - U32(Parent::Extended) + 1]; - static U32 getAssetErrCode(ConcreteAssetPtr checkAsset) { if (checkAsset) return checkAsset->mLoadedState; else return 0; } + static U32 getAssetErrCode(ConcreteAssetPtr checkAsset) { if (checkAsset.notNull()) return checkAsset->mLoadedState; else return 0; } static String getAssetErrstrn(U32 errCode) { @@ -241,6 +241,8 @@ public: void _set##name(StringTableEntry _in){ \ if(m##name##Asset.getAssetId() == _in) \ return; \ + if(get##name##File() == _in) \ + return; \ if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset = NULL; \ @@ -296,6 +298,8 @@ public: void _set##name(StringTableEntry _in){ \ if(m##name##Asset.getAssetId() == _in) \ return; \ + if(get##name##File() == _in) \ + return; \ if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset = NULL; \ @@ -358,6 +362,8 @@ public: void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ return; \ + if(get##name##File(index) == _in) \ + return; \ if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset[index] = NULL; \ @@ -414,6 +420,8 @@ public: void _set##name(StringTableEntry _in, const U32& index){ \ if(m##name##Asset[index].getAssetId() == _in) \ return; \ + if(get##name##File(index) == _in) \ + return; \ if(_in == NULL || _in == StringTable->EmptyString()) \ { \ m##name##Asset[index] = NULL; \ From ca1604170ddb4e6f81bcd51131a13da59b01f39e Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 13:34:07 +0100 Subject: [PATCH 14/23] initial commit change the macro to use the refactor (exact same structure as the imageasset macro) --- Engine/source/T3D/assets/ShapeAsset.cpp | 81 ++++- Engine/source/T3D/assets/ShapeAsset.h | 195 +++++++++++ Engine/source/T3D/debris.cpp | 28 +- Engine/source/T3D/debris.h | 8 +- .../T3D/examples/renderShapeExample.cpp | 19 +- .../source/T3D/examples/renderShapeExample.h | 7 +- Engine/source/T3D/missionMarker.cpp | 8 +- Engine/source/T3D/player.cpp | 38 +- Engine/source/T3D/proximityMine.cpp | 6 +- Engine/source/T3D/rigidShape.cpp | 2 +- Engine/source/T3D/shapeBase.cpp | 325 +++++++++--------- Engine/source/T3D/shapeBase.h | 31 +- Engine/source/T3D/shapeImage.cpp | 56 ++- Engine/source/T3D/tsStatic.cpp | 113 +++--- Engine/source/T3D/tsStatic.h | 13 +- Engine/source/T3D/turret/aiTurretShape.cpp | 6 +- Engine/source/T3D/turret/turretShape.cpp | 20 +- Engine/source/T3D/vehicles/flyingVehicle.cpp | 4 +- Engine/source/T3D/vehicles/hoverVehicle.cpp | 2 +- Engine/source/T3D/vehicles/vehicle.cpp | 2 +- Engine/source/T3D/vehicles/wheeledVehicle.cpp | 33 +- Engine/source/T3D/vehicles/wheeledVehicle.h | 8 +- Engine/source/afx/afxMagicMissile.cpp | 17 +- Engine/source/afx/afxMagicMissile.h | 16 +- Engine/source/afx/ce/afxModel.cpp | 60 ++-- Engine/source/afx/ce/afxModel.h | 19 +- Engine/source/afx/ce/afxStaticShape.h | 2 +- Engine/source/environment/VolumetricFog.cpp | 32 +- Engine/source/environment/VolumetricFog.h | 6 +- 29 files changed, 700 insertions(+), 457 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index ff27573cc..decc7258a 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -117,6 +117,54 @@ ConsoleSetType(TypeShapeAssetId) //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// REFACTOR +//----------------------------------------------------------------------------- + +IMPLEMENT_STRUCT(AssetPtr, AssetPtrShapeAsset, , "") +END_IMPLEMENT_STRUCT + +ConsoleType(ShapeAssetPtrRefactor, TypeShapeAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) + + +ConsoleGetType(TypeShapeAssetPtrRefactor) +{ + // Fetch asset Id. + return (*((AssetPtr*)dptr)).getAssetId(); +} + +ConsoleSetType(TypeShapeAssetPtrRefactor) +{ + // 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) + { + Con::warnf("(TypeShapeAssetPtrRefactor) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); + + return; + } + + // Warn. + Con::warnf("(TypeShapeAssetPtrRefactor) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- +// REFACTOR END +//----------------------------------------------------------------------------- + const String ShapeAsset::mErrCodeStrings[] = { "TooManyVerts", @@ -478,7 +526,38 @@ StringTableEntry ShapeAsset::getAssetIdByFilename(StringTableEntry fileName) } else { - AssetPtr shapeAsset = shapeAssetId; //ensures the fallback is loaded + foundAssetcount = AssetDatabase.findAssetType(&query, "ShapeAsset"); + if (foundAssetcount != 0) + { + // loop all image assets and see if we can find one + // using the same image file/named target. + for (auto shapeAsset : query.mAssetList) + { + AssetPtr temp = shapeAsset; + if (temp.notNull()) + { + if (temp->getShapePath() == fileName) + { + return shapeAsset; + } + else + { + Torque::Path temp1 = temp->getShapePath(); + Torque::Path temp2 = fileName; + + if (temp1.getPath() == temp2.getPath() && temp1.getFileName() == temp2.getFileName()) + { + return shapeAsset; + } + } + + } + } + } + else + { + AssetPtr shapeAsset = shapeAssetId; //ensures the fallback is loaded + } } return shapeAssetId; diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 2d186346d..1d7b960cd 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -212,6 +212,9 @@ protected: DefineConsoleType(TypeShapeAssetPtr, S32) DefineConsoleType(TypeShapeAssetId, String) +DECLARE_STRUCT(AssetPtr) +DefineConsoleType(TypeShapeAssetPtrRefactor, AssetPtr) + #ifdef TORQUE_TOOLS //----------------------------------------------------------------------------- // TypeAssetId GuiInspectorField Class @@ -493,4 +496,196 @@ public: \ #pragma endregion + +//----------------------------------------------------------------------------- +// REFACTOR +//----------------------------------------------------------------------------- + +#pragma region Refactor Asset Macros + +#define DECLARE_SHAPEASSET_REFACTOR(className, name) \ +private: \ + AssetPtr m##name##Asset; \ + StringTableEntry m##name##File = StringTable->EmptyString(); \ +public: \ + void _set##name(StringTableEntry _in) { \ + if (m##name##Asset.getAssetId() == _in) \ + return; \ + if(get##name##File() == _in) \ + return; \ + if (_in == NULL || _in == StringTable->EmptyString()) \ + { \ + m##name##Asset = NULL; \ + m##name##File = ""; \ + return; \ + } \ + if (!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry shapeAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + shapeAssetId = query.mAssetList[0]; \ + } \ + else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + shapeAssetId = ShapeAsset::getAssetIdByFilename(_in); \ + if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback) \ + { \ + ShapeAsset* privateShape = new ShapeAsset(); \ + privateShape->setShapeFile(_in); \ + shapeAssetId = AssetDatabase.addPrivateAsset(privateShape); \ + } \ + } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + shapeAssetId = ShapeAsset::smNoShapeAssetFallback; \ + } \ + m##name##Asset = shapeAssetId; \ + m##name##File = _in; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + m##name##File = get##name##File(); \ + } \ + }; \ + \ + inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); } \ + Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return 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; } \ + StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } + +#define DECLARE_SHAPEASSET_NET_REFACTOR(className, name, mask) \ +private: \ + AssetPtr m##name##Asset; \ + StringTableEntry m##name##File = StringTable->EmptyString(); \ +public: \ + void _set##name(StringTableEntry _in) { \ + if (m##name##Asset.getAssetId() == _in) \ + return; \ + if(get##name##File() == _in) \ + return; \ + if (_in == NULL || _in == StringTable->EmptyString()) \ + { \ + m##name##Asset = NULL; \ + m##name##File = ""; \ + setMaskBits(mask); \ + return; \ + } \ + if (!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry shapeAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + shapeAssetId = query.mAssetList[0]; \ + } \ + else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + shapeAssetId = ShapeAsset::getAssetIdByFilename(_in); \ + if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback) \ + { \ + ShapeAsset* privateShape = new ShapeAsset(); \ + privateShape->setShapeFile(_in); \ + shapeAssetId = AssetDatabase.addPrivateAsset(privateShape); \ + } \ + } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + shapeAssetId = ShapeAsset::smNoShapeAssetFallback; \ + } \ + m##name##Asset = shapeAssetId; \ + m##name##File = _in; \ + } \ + else \ + { \ + m##name##Asset = _in; \ + m##name##File = get##name##File(); \ + } \ + setMaskBits(mask); \ + }; \ + \ + inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); } \ + Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return 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; } \ + StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } + +#define INITPERSISTFIELD_SHAPEASSET_REFACTOR(name, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); \ + addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, file docs.)); + + +#define DECLARE_SHAPEASSET_ARRAY_REFACTOR(className, name, max) \ +private: \ + AssetPtr m##name##Asset[max]; \ + StringTableEntry m##name##File[max] = {StringTable->EmptyString() }; \ +public: \ + void _set##name(StringTableEntry _in, const U32& index){ \ + if (m##name##Asset[index].getAssetId() == _in) \ + return; \ + if(get##name##File(index) == _in) \ + return; \ + if (_in == NULL || _in == StringTable->EmptyString()) \ + { \ + m##name##Asset[index] = NULL; \ + m##name##File[index] = ""; \ + return; \ + } \ + if (!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry shapeAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + shapeAssetId = query.mAssetList[0]; \ + } \ + else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + shapeAssetId = ShapeAsset::getAssetIdByFilename(_in); \ + if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback) \ + { \ + ShapeAsset* privateShape = new ShapeAsset(); \ + privateShape->setShapeFile(_in); \ + shapeAssetId = AssetDatabase.addPrivateAsset(privateShape); \ + } \ + } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + shapeAssetId = ShapeAsset::smNoShapeAssetFallback; \ + } \ + m##name##Asset[index] = shapeAssetId; \ + m##name##File[index] = _in; \ + } \ + else \ + { \ + m##name##Asset[index] = _in; \ + m##name##File[index] = get##name##File(index); \ + } \ + }; \ + \ + inline StringTableEntry _get##name##AssetId(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ + Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return 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;}\ + StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } + +#define INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));\ + addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); + +#pragma endregion + +//----------------------------------------------------------------------------- +// REFACTOR END +//----------------------------------------------------------------------------- + #endif diff --git a/Engine/source/T3D/debris.cpp b/Engine/source/T3D/debris.cpp index 78a1e53cc..b7566ab72 100644 --- a/Engine/source/T3D/debris.cpp +++ b/Engine/source/T3D/debris.cpp @@ -116,7 +116,7 @@ DebrisData::DebrisData() terminalVelocity = 0.0f; ignoreWater = true; - INIT_ASSET(Shape); + mShapeAsset.registerRefreshNotify(this); } //#define TRACK_DEBRIS_DATA_CLONES @@ -152,7 +152,7 @@ DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData( terminalVelocity = other.terminalVelocity; ignoreWater = other.ignoreWater; - CLONE_ASSET(Shape); + mShapeAsset = other.mShapeAsset; textureName = other.textureName; explosionId = other.explosionId; // -- for pack/unpack of explosion ptr @@ -191,7 +191,7 @@ DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 void DebrisData::onPerformSubstitutions() { - _setShape(getShape()); + _setShape(_getShapeAssetId()); } bool DebrisData::onAdd() @@ -276,16 +276,16 @@ bool DebrisData::preload(bool server, String &errorStr) if (mShapeAsset.notNull()) { - if (!mShape) + if (!getShape()) { - errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", mShapeAssetId); + errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", _getShapeAssetId()); return false; } else { - TSShapeInstance* pDummy = new TSShapeInstance(mShape, !server); + TSShapeInstance* pDummy = new TSShapeInstance(getShape(), !server); delete pDummy; - if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded()) + if (!server && !getShape()->preloadMaterialList(getShape().getPath()) && NetConnection::filesWereDownloaded()) return false; } } @@ -304,7 +304,7 @@ void DebrisData::initPersistFields() addGroup("Shapes"); addField("texture", TypeString, Offset(textureName, DebrisData), "@brief Texture imagemap to use for this debris object.\n\nNot used any more.\n", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_SHAPEASSET(Shape, DebrisData, "Shape to use for this debris object."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, DebrisData, "Shape to use for this debris object."); endGroup("Shapes"); addGroup("Particle Effects"); @@ -389,7 +389,7 @@ void DebrisData::packData(BitStream* stream) stream->writeString( textureName ); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); for( S32 i=0; ireadSTString(); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); for( S32 i=0; ifriction; // Setup our bounding box - if( mDataBlock->mShape ) + if( mDataBlock->getShape()) { - mObjBox = mDataBlock->mShape->mBounds; + mObjBox = mDataBlock->getShape()->mBounds; } else { mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); } - if( mDataBlock->mShape) + if( mDataBlock->getShape()) { - mShape = new TSShapeInstance( mDataBlock->mShape, true); + mShape = new TSShapeInstance( mDataBlock->getShape(), true); } if( mPart ) diff --git a/Engine/source/T3D/debris.h b/Engine/source/T3D/debris.h index 1d1116031..9d9065d0b 100644 --- a/Engine/source/T3D/debris.h +++ b/Engine/source/T3D/debris.h @@ -47,7 +47,7 @@ class TSShape; //************************************************************************** // Debris Data //************************************************************************** -struct DebrisData : public GameBaseData +struct DebrisData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; @@ -83,8 +83,7 @@ struct DebrisData : public GameBaseData F32 terminalVelocity; // max velocity magnitude bool ignoreWater; - DECLARE_SHAPEASSET(DebrisData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(DebrisData, Shape); + DECLARE_SHAPEASSET_REFACTOR(DebrisData, Shape) StringTableEntry textureName; @@ -111,7 +110,8 @@ public: void onPerformSubstitutions() override; bool allowSubstitutions() const override { return true; } - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } diff --git a/Engine/source/T3D/examples/renderShapeExample.cpp b/Engine/source/T3D/examples/renderShapeExample.cpp index 731db472e..2762cfe9b 100644 --- a/Engine/source/T3D/examples/renderShapeExample.cpp +++ b/Engine/source/T3D/examples/renderShapeExample.cpp @@ -59,7 +59,6 @@ RenderShapeExample::RenderShapeExample() mTypeMask |= StaticObjectType | StaticShapeObjectType; // Make sure to initialize our TSShapeInstance to NULL - INIT_ASSET(Shape); mShapeInstance = NULL; } @@ -75,7 +74,7 @@ void RenderShapeExample::initPersistFields() docsURL; Parent::initPersistFields(); addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET(Shape, RenderShapeExample, "The path to the shape file.") + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, RenderShapeExample, "The path to the shape file.") endGroup( "Shapes" ); // SceneObject already handles exposing the transform @@ -147,7 +146,7 @@ U32 RenderShapeExample::packUpdate( NetConnection *conn, U32 mask, BitStream *st // Write out any of the updated editable properties if ( stream->writeFlag( mask & UpdateMask ) ) { - PACK_ASSET(conn, Shape); + PACK_ASSET_REFACTOR(conn, Shape); // Allow the server object a chance to handle a new shape createShape(); @@ -171,7 +170,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream) if ( stream->readFlag() ) // UpdateMask { - UNPACK_ASSET(conn, Shape); + UNPACK_ASSET_REFACTOR(conn, Shape); if ( isProperlyAdded() ) createShape(); @@ -183,11 +182,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream) //----------------------------------------------------------------------------- void RenderShapeExample::createShape() { - if ( getShape() == StringTable->EmptyString() ) - return; - - // If this is the same shape then no reason to update it - if ( mShapeInstance && getShape() == StringTable->insert(mShape.getPath().getFullPath().c_str()) ) + if ( mShapeAsset.isNull() ) return; // Clean up our previous shape @@ -196,19 +191,19 @@ void RenderShapeExample::createShape() // Attempt to preload the Materials for this shape if ( isClientObject() && - !mShape->preloadMaterialList( mShape.getPath() ) && + !getShape()->preloadMaterialList(getShape().getPath() ) && NetConnection::filesWereDownloaded() ) { return; } // Update the bounding box - mObjBox = mShape->mBounds; + mObjBox = getShape()->mBounds; resetWorldBox(); setRenderTransform(mObjToWorld); // Create the TSShapeInstance - mShapeInstance = new TSShapeInstance( mShape, isClientObject() ); + mShapeInstance = new TSShapeInstance(getShape(), isClientObject() ); } void RenderShapeExample::prepRenderImage( SceneRenderState *state ) diff --git a/Engine/source/T3D/examples/renderShapeExample.h b/Engine/source/T3D/examples/renderShapeExample.h index 3f452c72a..8160044a6 100644 --- a/Engine/source/T3D/examples/renderShapeExample.h +++ b/Engine/source/T3D/examples/renderShapeExample.h @@ -61,14 +61,11 @@ class RenderShapeExample : public SceneObject //-------------------------------------------------------------------------- // Rendering variables //-------------------------------------------------------------------------- - DECLARE_SHAPEASSET(RenderShapeExample, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(RenderShapeExample, Shape); + DECLARE_SHAPEASSET_REFACTOR(RenderShapeExample, Shape) // The actual shape instance TSShapeInstance* mShapeInstance; - void onShapeChanged() {} - public: RenderShapeExample(); virtual ~RenderShapeExample(); @@ -119,4 +116,4 @@ public: void prepRenderImage( SceneRenderState *state ) override; }; -#endif // _RENDERSHAPEEXAMPLE_H_ \ No newline at end of file +#endif // _RENDERSHAPEEXAMPLE_H_ diff --git a/Engine/source/T3D/missionMarker.cpp b/Engine/source/T3D/missionMarker.cpp index a18523ef7..7290ccc97 100644 --- a/Engine/source/T3D/missionMarker.cpp +++ b/Engine/source/T3D/missionMarker.cpp @@ -444,14 +444,14 @@ void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream) { delete mShapeInstance; ShapeBaseData *spawnedDatablock = dynamic_cast(Sim::findObject(mSpawnDataBlock.c_str())); - if (spawnedDatablock && spawnedDatablock->mShape) + if (spawnedDatablock && spawnedDatablock->getShape()) { - mShapeInstance = new TSShapeInstance(spawnedDatablock->mShape); + mShapeInstance = new TSShapeInstance(spawnedDatablock->getShape()); } else if (mDataBlock) { - if (mDataBlock->mShape) - mShapeInstance = new TSShapeInstance(mDataBlock->mShape); + if (mDataBlock->getShape()) + mShapeInstance = new TSShapeInstance(mDataBlock->getShape()); } } stream->read(&mSpawnName); diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index c736ff022..8239bd2f3 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -502,10 +502,10 @@ bool PlayerData::preload(bool server, String &errorStr) // If we don't have a shape don't crash out trying to // setup animations and sequences. - if ( mShape ) + if (getShape()) { // Go ahead a pre-load the player shape - TSShapeInstance* si = new TSShapeInstance(mShape, false); + TSShapeInstance* si = new TSShapeInstance(getShape(), false); TSThread* thread = si->addThread(); // Extract ground transform velocity from animations @@ -516,7 +516,7 @@ bool PlayerData::preload(bool server, String &errorStr) ActionAnimationDef *sp = &ActionAnimationList[i]; dp->name = sp->name; dp->dir.set(sp->dir.x,sp->dir.y,sp->dir.z); - dp->sequence = mShape->findSequence(sp->name); + dp->sequence = getShape()->findSequence(sp->name); // If this is a sprint action and is missing a sequence, attempt to use // the standard run ones. @@ -524,7 +524,7 @@ bool PlayerData::preload(bool server, String &errorStr) { S32 offset = i-SprintRootAnim; ActionAnimationDef *standDef = &ActionAnimationList[RootAnim+offset]; - dp->sequence = mShape->findSequence(standDef->name); + dp->sequence = getShape()->findSequence(standDef->name); } dp->velocityScale = true; @@ -532,12 +532,12 @@ bool PlayerData::preload(bool server, String &errorStr) if (dp->sequence != -1) getGroundInfo(si,thread,dp); } - for (S32 b = 0; b < mShape->sequences.size(); b++) + for (S32 b = 0; b < getShape()->sequences.size(); b++) { if (!isTableSequence(b)) { dp->sequence = b; - dp->name = mShape->getName(mShape->sequences[b].nameIndex); + dp->name = getShape()->getName(getShape()->sequences[b].nameIndex); dp->velocityScale = false; getGroundInfo(si,thread,dp++); } @@ -554,17 +554,17 @@ bool PlayerData::preload(bool server, String &errorStr) lookAction = c; // Resolve spine - spineNode[0] = mShape->findNode("Bip01 Pelvis"); - spineNode[1] = mShape->findNode("Bip01 Spine"); - spineNode[2] = mShape->findNode("Bip01 Spine1"); - spineNode[3] = mShape->findNode("Bip01 Spine2"); - spineNode[4] = mShape->findNode("Bip01 Neck"); - spineNode[5] = mShape->findNode("Bip01 Head"); + spineNode[0] = getShape()->findNode("Bip01 Pelvis"); + spineNode[1] = getShape()->findNode("Bip01 Spine"); + spineNode[2] = getShape()->findNode("Bip01 Spine1"); + spineNode[3] = getShape()->findNode("Bip01 Spine2"); + spineNode[4] = getShape()->findNode("Bip01 Neck"); + spineNode[5] = getShape()->findNode("Bip01 Head"); // Recoil animations - recoilSequence[0] = mShape->findSequence("light_recoil"); - recoilSequence[1] = mShape->findSequence("medium_recoil"); - recoilSequence[2] = mShape->findSequence("heavy_recoil"); + recoilSequence[0] = getShape()->findSequence("light_recoil"); + recoilSequence[1] = getShape()->findSequence("medium_recoil"); + recoilSequence[2] = getShape()->findSequence("heavy_recoil"); } // Convert pickupRadius to a delta of boundingBox @@ -7511,8 +7511,8 @@ F32 Player::getAnimationDurationByID(U32 anim_id) if (anim_id == BAD_ANIM_ID) return 0.0f; S32 seq_id = mDataBlock->actionList[anim_id].sequence; - if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size()) - return mDataBlock->mShape->sequences[seq_id].duration; + if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) + return mDataBlock->getShape()->sequences[seq_id].duration; return 0.0f; } @@ -7524,8 +7524,8 @@ bool Player::isBlendAnimation(const char* name) return false; S32 seq_id = mDataBlock->actionList[anim_id].sequence; - if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size()) - return mDataBlock->mShape->sequences[seq_id].isBlend(); + if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) + return mDataBlock->getShape()->sequences[seq_id].isBlend(); return false; } diff --git a/Engine/source/T3D/proximityMine.cpp b/Engine/source/T3D/proximityMine.cpp index fd02fc091..86c9807b6 100644 --- a/Engine/source/T3D/proximityMine.cpp +++ b/Engine/source/T3D/proximityMine.cpp @@ -144,11 +144,11 @@ bool ProximityMineData::preload( bool server, String& errorStr ) } } - if ( mShape ) + if ( getShape() ) { // Lookup animation sequences - armingSequence = mShape->findSequence( "armed" ); - triggerSequence = mShape->findSequence( "triggered" ); + armingSequence = getShape()->findSequence( "armed" ); + triggerSequence = getShape()->findSequence( "triggered" ); } return true; diff --git a/Engine/source/T3D/rigidShape.cpp b/Engine/source/T3D/rigidShape.cpp index 8a453b065..b87bcc056 100644 --- a/Engine/source/T3D/rigidShape.cpp +++ b/Engine/source/T3D/rigidShape.cpp @@ -310,7 +310,7 @@ bool RigidShapeData::preload(bool server, String &errorStr) if (!collisionDetails.size() || collisionDetails[0] == -1) { Con::errorf("RigidShapeData::preload failed: Rigid shapes must define a collision-1 detail"); - errorStr = String::ToString("RigidShapeData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId()); + errorStr = String::ToString("RigidShapeData: Couldn't load shape asset \"%s\"", getShapeAsset().getAssetId()); return false; } diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 92f5f4da6..8e1f19013 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -201,13 +201,12 @@ ShapeBaseData::ShapeBaseData() inheritEnergyFromMount( false ), mAIControllData(NULL) { - INIT_ASSET(Shape); - INIT_ASSET(DebrisShape); - dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints ); remap_txr_tags = NULL; remap_buffer = NULL; silent_bbox_check = false; + mShapeAsset.registerRefreshNotify(this); + mDebrisShapeAsset.registerRefreshNotify(this); } ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : GameBaseData(other, temp_clone) @@ -217,13 +216,13 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game shadowProjectionDistance = other.shadowProjectionDistance; shadowSphereAdjust = other.shadowSphereAdjust; cloakTexName = other.cloakTexName; - CLONE_ASSET(Shape); + mShapeAsset = other.mShapeAsset; cubeDescName = other.cubeDescName; cubeDescId = other.cubeDescId; reflectorDesc = other.reflectorDesc; debris = other.debris; debrisID = other.debrisID; // -- for pack/unpack of debris ptr - CLONE_ASSET(DebrisShape); + mDebrisShapeAsset = other.mDebrisShapeAsset; explosion = other.explosion; explosionID = other.explosionID; // -- for pack/unpack of explosion ptr underwaterExplosion = other.underwaterExplosion; @@ -245,7 +244,6 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game cameraMaxFov = other.cameraMaxFov; cameraCanBank = other.cameraCanBank; mountedImagesBank = other.mountedImagesBank; - mShape = other.mShape; // -- TSShape loaded using shapeName mCRC = other.mCRC; // -- from shape, used to verify client shape computeCRC = other.computeCRC; eyeNode = other.eyeNode; // -- from shape node "eye" @@ -304,6 +302,9 @@ ShapeBaseData::~ShapeBaseData() if (remap_buffer && !isTempClone()) dFree(remap_buffer); + + mShapeAsset.unregisterRefreshNotify(); + mDebrisShapeAsset.unregisterRefreshNotify(); } bool ShapeBaseData::preload(bool server, String &errorStr) @@ -342,156 +343,159 @@ bool ShapeBaseData::preload(bool server, String &errorStr) "ShapeBaseData::preload: invalid debris data"); } - if( bool(mDebrisShape)) + if(mDebrisShapeAsset.notNull()) { - TSShapeInstance* pDummy = new TSShapeInstance(mDebrisShape, !server); + TSShapeInstance* pDummy = new TSShapeInstance(getDebrisShape(), !server); delete pDummy; } } S32 i; - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); - if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) + if (mShapeAsset.notNull()) { - if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded()) - shapeError = true; - - if(computeCRC) + U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) { - Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId()); + if (!server && !getShape()->preloadMaterialList(getShape().getPath()) && NetConnection::filesWereDownloaded()) + shapeError = true; - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapePath()); - - if (!fileRef) + if (computeCRC) { - errorStr = String::ToString("ShapeBaseData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId()); - return false; - } + Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId()); - if(server) - mCRC = fileRef->getChecksum(); - else if(mCRC != fileRef->getChecksum()) - { - errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", mShapeAsset.getAssetId()); - return false; - } - } - // Resolve details and camera node indexes. - static const String sCollisionStr( "collision-" ); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapePath()); - for (i = 0; i < mShape->details.size(); i++) - { - const String &name = mShape->names[mShape->details[i].nameIndex]; - - if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0) - { - collisionDetails.push_back(i); - collisionBounds.increment(); - - mShape->computeBounds(collisionDetails.last(), collisionBounds.last()); - mShape->getAccelerator(collisionDetails.last()); - - if (!mShape->mBounds.isContained(collisionBounds.last())) + if (!fileRef) { - if (!silent_bbox_check) - Con::warnf("Warning: shape asset %s collision detail %d (Collision-%d) bounds exceed that of shape.", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last()); - collisionBounds.last() = mShape->mBounds; - } - else if (collisionBounds.last().isValidBox() == false) - { - if (!silent_bbox_check) - Con::errorf("Error: shape asset %s-collision detail %d (Collision-%d) bounds box invalid!", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last()); - collisionBounds.last() = mShape->mBounds; + errorStr = String::ToString("ShapeBaseData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId()); + return false; } - // The way LOS works is that it will check to see if there is a LOS detail that matches - // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in - // the future). If it can't find a matching LOS it will simply use the collision instead. - // We check for any "unmatched" LOS's further down - LOSDetails.increment(); - - String buff = String::ToString("LOS-%d", i + 1 + MaxCollisionShapes); - U32 los = mShape->findDetail(buff); - if (los == -1) - LOSDetails.last() = i; - else - LOSDetails.last() = los; - } - } - - // Snag any "unmatched" LOS details - static const String sLOSStr( "LOS-" ); - - for (i = 0; i < mShape->details.size(); i++) - { - const String &name = mShape->names[mShape->details[i].nameIndex]; - - if (name.compare( sLOSStr, sLOSStr.length(), String::NoCase ) == 0) - { - // See if we already have this LOS - bool found = false; - for (U32 j = 0; j < LOSDetails.size(); j++) + if (server) + mCRC = fileRef->getChecksum(); + else if (mCRC != fileRef->getChecksum()) { - if (LOSDetails[j] == i) + errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", mShapeAsset.getAssetId()); + return false; + } + } + // Resolve details and camera node indexes. + static const String sCollisionStr("collision-"); + + for (i = 0; i < getShape()->details.size(); i++) + { + const String& name = getShape()->names[getShape()->details[i].nameIndex]; + + if (name.compare(sCollisionStr, sCollisionStr.length(), String::NoCase) == 0) + { + collisionDetails.push_back(i); + collisionBounds.increment(); + + getShape()->computeBounds(collisionDetails.last(), collisionBounds.last()); + getShape()->getAccelerator(collisionDetails.last()); + + if (!getShape()->mBounds.isContained(collisionBounds.last())) { + if (!silent_bbox_check) + Con::warnf("Warning: shape asset %s collision detail %d (Collision-%d) bounds exceed that of shape.", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last()); + collisionBounds.last() = getShape()->mBounds; + } + else if (collisionBounds.last().isValidBox() == false) + { + if (!silent_bbox_check) + Con::errorf("Error: shape asset %s-collision detail %d (Collision-%d) bounds box invalid!", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last()); + collisionBounds.last() = getShape()->mBounds; + } + + // The way LOS works is that it will check to see if there is a LOS detail that matches + // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in + // the future). If it can't find a matching LOS it will simply use the collision instead. + // We check for any "unmatched" LOS's further down + LOSDetails.increment(); + + String buff = String::ToString("LOS-%d", i + 1 + MaxCollisionShapes); + U32 los = getShape()->findDetail(buff); + if (los == -1) + LOSDetails.last() = i; + else + LOSDetails.last() = los; + } + } + + // Snag any "unmatched" LOS details + static const String sLOSStr("LOS-"); + + for (i = 0; i < getShape()->details.size(); i++) + { + const String& name = getShape()->names[getShape()->details[i].nameIndex]; + + if (name.compare(sLOSStr, sLOSStr.length(), String::NoCase) == 0) + { + // See if we already have this LOS + bool found = false; + for (U32 j = 0; j < LOSDetails.size(); j++) + { + if (LOSDetails[j] == i) + { found = true; break; + } } - } - if (!found) - LOSDetails.push_back(i); + if (!found) + LOSDetails.push_back(i); + } } - } - debrisDetail = mShape->findDetail("Debris-17"); - eyeNode = mShape->findNode("eye"); - earNode = mShape->findNode( "ear" ); - if( earNode == -1 ) - earNode = eyeNode; - cameraNode = mShape->findNode("cam"); - if (cameraNode == -1) - cameraNode = eyeNode; + debrisDetail = getShape()->findDetail("Debris-17"); + eyeNode = getShape()->findNode("eye"); + earNode = getShape()->findNode("ear"); + if (earNode == -1) + earNode = eyeNode; + cameraNode = getShape()->findNode("cam"); + if (cameraNode == -1) + cameraNode = eyeNode; - // Resolve mount point node indexes - for (i = 0; i < SceneObject::NumMountPoints; i++) { - char fullName[256]; - dSprintf(fullName,sizeof(fullName),"mount%d",i); - mountPointNode[i] = mShape->findNode(fullName); - } + // Resolve mount point node indexes + for (i = 0; i < SceneObject::NumMountPoints; i++) { + char fullName[256]; + dSprintf(fullName, sizeof(fullName), "mount%d", i); + mountPointNode[i] = getShape()->findNode(fullName); + } - // find the AIRepairNode - hardcoded to be the last node in the array... - mountPointNode[AIRepairNode] = mShape->findNode("AIRepairNode"); + // find the AIRepairNode - hardcoded to be the last node in the array... + mountPointNode[AIRepairNode] = getShape()->findNode("AIRepairNode"); - // - hulkSequence = mShape->findSequence("Visibility"); - damageSequence = mShape->findSequence("Damage"); + // + hulkSequence = getShape()->findSequence("Visibility"); + damageSequence = getShape()->findSequence("Damage"); - // - F32 w = mShape->mBounds.len_y() / 2; - if (cameraMaxDist < w) - cameraMaxDist = w; - // just parse up the string and collect the remappings in txr_tag_remappings. - if (!server && remap_txr_tags != NULL && remap_txr_tags != StringTable->insert("")) - { - txr_tag_remappings.clear(); - if (remap_buffer) - dFree(remap_buffer); - - remap_buffer = dStrdup(remap_txr_tags); - - char* remap_token = dStrtok(remap_buffer, " \t"); - while (remap_token != NULL) + // + F32 w = getShape()->mBounds.len_y() / 2; + if (cameraMaxDist < w) + cameraMaxDist = w; + // just parse up the string and collect the remappings in txr_tag_remappings. + if (!server && remap_txr_tags != NULL && remap_txr_tags != StringTable->insert("")) { - char* colon = dStrchr(remap_token, ':'); - if (colon) + txr_tag_remappings.clear(); + if (remap_buffer) + dFree(remap_buffer); + + remap_buffer = dStrdup(remap_txr_tags); + + char* remap_token = dStrtok(remap_buffer, " \t"); + while (remap_token != NULL) { - *colon = '\0'; - txr_tag_remappings.increment(); - txr_tag_remappings.last().old_tag = remap_token; - txr_tag_remappings.last().new_tag = colon+1; + char* colon = dStrchr(remap_token, ':'); + if (colon) + { + *colon = '\0'; + txr_tag_remappings.increment(); + txr_tag_remappings.last().old_tag = remap_token; + txr_tag_remappings.last().new_tag = colon + 1; + } + remap_token = dStrtok(NULL, " \t"); } - remap_token = dStrtok(NULL, " \t"); } } } @@ -543,12 +547,12 @@ void ShapeBaseData::initPersistFields() { docsURL; addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET(Shape, ShapeBaseData, "The source shape asset."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, ShapeBaseData, "The source shape asset."); addField("computeCRC", TypeBool, Offset(computeCRC, ShapeBaseData), "If true, verify that the CRC of the client's shape model matches the " "server's CRC for the shape model when loaded by the client."); addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData)); - INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional."); endGroup( "Shapes" ); addGroup("Movement"); addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, ShapeBaseData), @@ -677,12 +681,12 @@ DefineEngineMethod( ShapeBaseData, checkDeployPos, bool, ( TransformF txfm ),, "@note This is a server side only check, and is not actually limited to spawning.\n") { - if (bool(object->mShape) == false) + if (bool(object->getShape()) == false) return false; MatrixF mat = txfm.getMatrix(); - Box3F objBox = object->mShape->mBounds; + Box3F objBox = object->getShape()->mBounds; Point3F boxCenter = (objBox.minExtents + objBox.maxExtents) * 0.5f; objBox.minExtents = boxCenter + (objBox.minExtents - boxCenter) * 0.9f; objBox.maxExtents = boxCenter + (objBox.maxExtents - boxCenter) * 0.9f; @@ -752,8 +756,8 @@ void ShapeBaseData::packData(BitStream* stream) stream->write(shadowProjectionDistance); stream->write(shadowSphereAdjust); - PACKDATA_ASSET(Shape); - PACKDATA_ASSET(DebrisShape); + PACKDATA_ASSET_REFACTOR(Shape); + PACKDATA_ASSET_REFACTOR(DebrisShape); stream->writeString(cloakTexName); if(stream->writeFlag(mass != gShapeBaseDataProto.mass)) @@ -829,8 +833,8 @@ void ShapeBaseData::unpackData(BitStream* stream) stream->read(&shadowProjectionDistance); stream->read(&shadowSphereAdjust); - UNPACKDATA_ASSET(Shape); - UNPACKDATA_ASSET(DebrisShape); + UNPACKDATA_ASSET_REFACTOR(Shape); + UNPACKDATA_ASSET_REFACTOR(DebrisShape); cloakTexName = stream->readSTString(); if(stream->readFlag()) @@ -918,17 +922,6 @@ void ShapeBaseData::unpackData(BitStream* stream) silent_bbox_check = stream->readFlag(); } -// -// -void ShapeBaseData::onShapeChanged() -{ - reloadOnLocalClient(); -} - -void ShapeBaseData::onDebrisChanged() -{ - reloadOnLocalClient(); -} //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -1210,12 +1203,12 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) // Even if loadShape succeeds, there may not actually be // a shape assigned to this object. - if (bool(mDataBlock->mShape)) { + if (bool(mDataBlock->getShape())) { delete mShapeInstance; if (isClientObject() && mDataBlock->txr_tag_remappings.size() > 0) { // temporarily substitute material tags with alternates - TSMaterialList* mat_list = mDataBlock->mShape->materialList; + TSMaterialList* mat_list = mDataBlock->getShape()->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -1235,7 +1228,7 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) } } } - mShapeInstance = new TSShapeInstance(mDataBlock->mShape, isClientObject()); + mShapeInstance = new TSShapeInstance(mDataBlock->getShape(), isClientObject()); if (isClientObject()) { mShapeInstance->cloneMaterialList(); @@ -1243,7 +1236,7 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) // restore the material tags to original form if (mDataBlock->txr_tag_remappings.size() > 0) { - TSMaterialList* mat_list = mDataBlock->mShape->materialList; + TSMaterialList* mat_list = mDataBlock->getShape()->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -1269,11 +1262,11 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) } } - mObjBox = mDataBlock->mShape->mBounds; + mObjBox = mDataBlock->getShape()->mBounds; resetWorldBox(); // Set the initial mesh hidden state. - mMeshHidden.setSize(mDataBlock->mShape->objects.size()); + mMeshHidden.setSize(mDataBlock->getShape()->objects.size()); mMeshHidden.clear(); // Initialize the threads @@ -1297,11 +1290,11 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) AssertFatal(prevDB != NULL, "ShapeBase::onNewDataBlock - how did you have a sequence playing without a prior datablock?"); - const TSShape* prevShape = prevDB->mShape; + const TSShape* prevShape = prevDB->getShape(); const TSShape::Sequence& prevSeq = prevShape->sequences[st.sequence]; const String& prevSeqName = prevShape->names[prevSeq.nameIndex]; - st.sequence = mDataBlock->mShape->findSequence(prevSeqName); + st.sequence = mDataBlock->getShape()->findSequence(prevSeqName); if (st.sequence != -1) { @@ -1971,13 +1964,13 @@ void ShapeBase::blowUp() TSShapeInstance *debShape = NULL; - if( mDataBlock->mDebrisShape == NULL ) + if( mDataBlock->getDebrisShape() == NULL) { return; } else { - debShape = new TSShapeInstance( mDataBlock->mDebrisShape, true); + debShape = new TSShapeInstance( mDataBlock->getDebrisShape(), true); } @@ -2049,7 +2042,7 @@ Point3F ShapeBase::getAIRepairPoint() //---------------------------------------------------------------------------- void ShapeBase::getNodeTransform(const char* nodeName, MatrixF* outMat) { - S32 nodeIDx = mDataBlock->getShapeResource()->findNode(nodeName); + S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName); const MatrixF& xfm = isMounted() ? mMount.xfm : MatrixF::Identity; MatrixF nodeTransform(xfm); @@ -2216,7 +2209,7 @@ void ShapeBase::getNodeTransform(const char* nodeName, const MatrixF& xfm, Matri if (!mShapeInstance) return; - S32 nodeIDx = mDataBlock->getShapeResource()->findNode(nodeName); + S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName); MatrixF nodeTransform(xfm); const Point3F& scale = getScale(); @@ -5027,7 +5020,7 @@ void ShapeBase::_updateHiddenMeshes() void ShapeBase::setMeshHidden( const char *meshName, bool forceHidden ) { - setMeshHidden( mDataBlock->mShape->findObject( meshName ), forceHidden ); + setMeshHidden( mDataBlock->getShape()->findObject(meshName), forceHidden); } void ShapeBase::setMeshHidden( S32 meshIndex, bool forceHidden ) @@ -5096,7 +5089,7 @@ void ShapeBase::dumpMeshVisibility() { const TSShapeInstance::MeshObjectInstance &mesh = meshes[i]; - const String &meshName = mDataBlock->mShape->getMeshName( i ); + const String &meshName = mDataBlock->getShape()->getMeshName( i ); Con::printf( "%d - %s - forceHidden = %s, visibility = %f", i, @@ -5378,8 +5371,8 @@ F32 ShapeBase::getAnimationDurationByID(U32 anim_id) return 0.0f; S32 seq_id = (S32) anim_id; - if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size()) - return mDataBlock->mShape->sequences[seq_id].duration; + if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) + return mDataBlock->getShape()->sequences[seq_id].duration; return 0.0f; } @@ -5391,8 +5384,8 @@ bool ShapeBase::isBlendAnimation(const char* name) return false; S32 seq_id = (S32) anim_id; - if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size()) - return mDataBlock->mShape->sequences[seq_id].isBlend(); + if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) + return mDataBlock->getShape()->sequences[seq_id].isBlend(); return false; } @@ -5404,11 +5397,11 @@ const char* ShapeBase::getLastClipName(U32 clip_tag) S32 seq_id = (S32) last_anim_id; - S32 idx = mDataBlock->mShape->sequences[seq_id].nameIndex; - if (idx < 0 || idx >= mDataBlock->mShape->names.size()) + S32 idx = mDataBlock->getShape()->sequences[seq_id].nameIndex; + if (idx < 0 || idx >= mDataBlock->getShape()->names.size()) return 0; - return mDataBlock->mShape->names[idx]; + return mDataBlock->getShape()->names[idx]; } // diff --git a/Engine/source/T3D/shapeBase.h b/Engine/source/T3D/shapeBase.h index 46f9a3270..a8807a026 100644 --- a/Engine/source/T3D/shapeBase.h +++ b/Engine/source/T3D/shapeBase.h @@ -140,7 +140,8 @@ class ShapeBaseConvex : public Convex //-------------------------------------------------------------------------- -struct ShapeBaseImageData: public GameBaseData { +struct ShapeBaseImageData: public GameBaseData, protected AssetPtrCallback +{ private: typedef GameBaseData Parent; @@ -380,11 +381,7 @@ struct ShapeBaseImageData: public GameBaseData { F32 scriptAnimTransitionTime; ///< The amount of time to transition between the previous sequence and new sequence ///< when the script prefix has changed. - DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes, onShapeChanged); ///< Name of shape to render. - DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, Shape); - - //DECLARE_SHAPEASSET(ShapeBaseImageData, ShapeFP); ///< Name of shape to render in first person (optional). - //DECLARE_ASSET_SETGET(ShapeBaseImageData, ShapeFP); + DECLARE_SHAPEASSET_ARRAY_REFACTOR(ShapeBaseImageData, Shape, MaxShapes) ///< Name of shape to render. StringTableEntry imageAnimPrefix; ///< Passed along to the mounting shape to modify /// animation sequences played in 3rd person. [optional] @@ -519,6 +516,12 @@ struct ShapeBaseImageData: public GameBaseData { DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, S32 slot, F32 dt ) ); DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, S32 slot, F32 dt ) ); /// @} + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } }; typedef ShapeBaseImageData::LightType ShapeBaseImageLightType; @@ -533,7 +536,7 @@ DefineEnumType( ShapeBaseImageRecoilState ); //-------------------------------------------------------------------------- /// @nosubgrouping -struct ShapeBaseData : public GameBaseData { +struct ShapeBaseData : public GameBaseData, protected AssetPtrCallback { private: typedef GameBaseData Parent; @@ -553,8 +556,7 @@ public: F32 shadowProjectionDistance; F32 shadowSphereAdjust; - DECLARE_SHAPEASSET(ShapeBaseData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(ShapeBaseData, Shape); + DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, Shape) StringTableEntry cloakTexName; @@ -570,8 +572,7 @@ public: DebrisData * debris; S32 debrisID; - DECLARE_SHAPEASSET(ShapeBaseData, DebrisShape, onDebrisChanged); - DECLARE_ASSET_SETGET(ShapeBaseData, DebrisShape); + DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, DebrisShape) ExplosionData* explosion; S32 explosionID; @@ -691,10 +692,14 @@ public: Vector txr_tag_remappings; bool silent_bbox_check; - void onShapeChanged(); - void onDebrisChanged(); public: ShapeBaseData(const ShapeBaseData&, bool = false); + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } }; diff --git a/Engine/source/T3D/shapeImage.cpp b/Engine/source/T3D/shapeImage.cpp index bf1687649..95281cbd6 100644 --- a/Engine/source/T3D/shapeImage.cpp +++ b/Engine/source/T3D/shapeImage.cpp @@ -293,8 +293,7 @@ ShapeBaseImageData::ShapeBaseImageData() isAnimated[i] = false; hasFlash[i] = false; shapeIsValid[i] = false; - - INIT_ASSET_ARRAY(Shape, i); + mShapeAsset[i].registerRefreshNotify(this); } shakeCamera = false; @@ -454,10 +453,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) if (!mShapeAsset[i].isNull()) { - // Resolve shapename - mShape[i] = mShapeAsset[i]->getShapeResource(); - - if (!bool(mShape[i])) { + if (!bool(getShape(i))) { errorStr = String::ToString("Unable to load shape asset: %s", mShapeAsset[i]->getAssetId()); return false; } @@ -465,7 +461,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) { Con::printf("Validation required for shape asset: %s", mShapeAsset[i]->getAssetId()); - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShape[i].getPath()); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(getShape(i).getPath()); if (!fileRef) { @@ -485,23 +481,23 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) } // Resolve nodes & build mount transform - eyeMountNode[i] = mShape[i]->findNode("eyeMount"); - eyeNode[i] = mShape[i]->findNode("eye"); + eyeMountNode[i] = getShape(i)->findNode("eyeMount"); + eyeNode[i] = getShape(i)->findNode("eye"); if (eyeNode[i] == -1) eyeNode[i] = eyeMountNode[i]; - ejectNode[i] = mShape[i]->findNode("ejectPoint"); - muzzleNode[i] = mShape[i]->findNode("muzzlePoint"); - retractNode[i] = mShape[i]->findNode("retractionPoint"); + ejectNode[i] = getShape(i)->findNode("ejectPoint"); + muzzleNode[i] = getShape(i)->findNode("muzzlePoint"); + retractNode[i] = getShape(i)->findNode("retractionPoint"); mountTransform[i] = mountOffset; - S32 node = mShape[i]->findNode("mountPoint"); + S32 node = getShape(i)->findNode("mountPoint"); if (node != -1) { MatrixF total(1); do { MatrixF nmat; QuatF q; - TSTransform::setMatrix(mShape[i]->defaultRotations[node].getQuatF(&q), mShape[i]->defaultTranslations[node],&nmat); + TSTransform::setMatrix(getShape(i)->defaultRotations[node].getQuatF(&q), getShape(i)->defaultTranslations[node],&nmat); total.mul(nmat); - node = mShape[i]->nodes[node].parentIndex; + node = getShape(i)->nodes[node].parentIndex; } while(node != -1); total.inverse(); @@ -514,7 +510,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) for (U32 j = 0; j < MaxStates; j++) { StateData& s = state[j]; if (stateSequence[j] && stateSequence[j][0]) - s.sequence[i] = mShape[i]->findSequence(stateSequence[j]); + s.sequence[i] = getShape(i)->findSequence(stateSequence[j]); if (s.sequence[i] != -1) { // This state has an animation sequence @@ -525,7 +521,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) char bufferVis[128]; dStrncpy(bufferVis, stateSequence[j], 100); dStrcat(bufferVis, "_vis", 128); - s.sequenceVis[i] = mShape[i]->findSequence(bufferVis); + s.sequenceVis[i] = getShape(i)->findSequence(bufferVis); } if (s.sequenceVis[i] != -1) { @@ -537,13 +533,13 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) s.ignoreLoadedForReady = stateIgnoreLoadedForReady[j]; if (stateEmitterNode[j] && stateEmitterNode[j][0]) - s.emitterNode[i] = mShape[i]->findNode(stateEmitterNode[j]); + s.emitterNode[i] = getShape(i)->findNode(stateEmitterNode[j]); if (s.emitterNode[i] == -1) s.emitterNode[i] = muzzleNode[i]; } - ambientSequence[i] = mShape[i]->findSequence("ambient"); - spinSequence[i] = mShape[i]->findSequence("spin"); + ambientSequence[i] = getShape(i)->findSequence("ambient"); + spinSequence[i] = getShape(i)->findSequence("spin"); shapeIsValid[i] = true; } @@ -567,7 +563,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) { if( shapeIsValid[i] ) { - TSShapeInstance* pDummy = new TSShapeInstance(mShape[i], !server); + TSShapeInstance* pDummy = new TSShapeInstance(getShape(i), !server); delete pDummy; } } @@ -628,8 +624,8 @@ void ShapeBaseImageData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_ARRAY(Shape, MaxShapes, ShapeBaseImageData, "The shape asset to use for this image in the third person") - //addProtectedField("shapeFileFP", TypeShapeFilename, Offset(mShapeName[1], ShapeBaseImageData), _setShapeData, defaultProtectedGetFn, "deprecated alias for ShapeFPFile/Asset", AbstractClassRep::FIELD_HideInInspectors); + INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(Shape, MaxShapes, ShapeBaseImageData, "The shape assets for this shape image") + addField("casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData), "@brief DebrisData datablock to use for ejected casings.\n\n" "@see stateEjectShell"); @@ -1002,10 +998,7 @@ void ShapeBaseImageData::packData(BitStream* stream) } } - for (U32 j = 0; j < MaxShapes; ++j) - { - PACKDATA_ASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional) - } + PACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes); // shape 0 for normal use, shape 1 for first person use (optional) stream->writeString(imageAnimPrefix); stream->writeString(imageAnimPrefixFP); @@ -1186,10 +1179,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream) } } - for (U32 j = 0; j < MaxShapes; ++j) - { - UNPACKDATA_ASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional) - } + UNPACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes); // shape 0 for normal use, shape 1 for first person use (optional) imageAnimPrefix = stream->readSTString(); imageAnimPrefixFP = stream->readSTString(); @@ -2148,7 +2138,7 @@ S32 ShapeBase::getNodeIndex(U32 imageSlot,StringTableEntry nodeName) { MountedImage& image = mMountedImageList[imageSlot]; if (image.dataBlock) - return image.dataBlock->mShape[getImageShapeIndex(image)]->findNode(nodeName); + return image.dataBlock->getShape(getImageShapeIndex(image))->findNode(nodeName); else return -1; } @@ -2338,7 +2328,7 @@ void ShapeBase::setImage( U32 imageSlot, for (U32 i=0; ishapeIsValid[i]) - image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->mShape[i], isClientObject()); + image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->getShape(i), isClientObject()); } if (isClientObject()) diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index 52a28d14b..ad41f08c6 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -151,13 +151,14 @@ TSStatic::TSStatic() mAnimOffset = 0.0f; mAnimSpeed = 1.0f; - INIT_ASSET(Shape); + mShapeAsset.registerRefreshNotify(this); } TSStatic::~TSStatic() { delete mConvexList; mConvexList = NULL; + mShapeAsset.unregisterRefreshNotify(); } ImplementEnumType(TSMeshType, @@ -180,11 +181,7 @@ void TSStatic::initPersistFields() docsURL; addGroup("Shape"); - INITPERSISTFIELD_SHAPEASSET(Shape, TSStatic, "Model to use for this TSStatic"); - - addProtectedField("shapeName", TypeShapeFilename, Offset(mShapeName, TSStatic), - &TSStatic::_setShapeData, &defaultProtectedGetFn, - "%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic. Legacy field. Any loose files assigned here will attempt to be auto-imported in as an asset.", AbstractClassRep::FIELD_HideInInspectors); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, TSStatic, "Model to use for this TSStatic"); endGroup("Shape"); @@ -393,59 +390,55 @@ bool TSStatic::_createShape() mAmbientThread = NULL; //mShape = NULL; - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); - if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) + if (mShapeAsset.notNull()) { - //Special-case handling, usually because we set noShape - mShape = mShapeAsset->getShapeResource(); - } + if (!getShape()) + { + Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId()); + return false; + } - if (!mShape) - { - Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId()); - return false; - } + if (isClientObject() && + !getShape()->preloadMaterialList(getShape().getPath()) && + NetConnection::filesWereDownloaded()) + return false; - if (isClientObject() && - !mShape->preloadMaterialList(mShape.getPath()) && - NetConnection::filesWereDownloaded()) - return false; + mObjBox = getShape()->mBounds; + resetWorldBox(); - mObjBox = mShape->mBounds; - resetWorldBox(); + mShapeInstance = new TSShapeInstance(getShape(), isClientObject()); + mShapeInstance->resetMaterialList(); + mShapeInstance->cloneMaterialList(); - mShapeInstance = new TSShapeInstance(mShape, isClientObject()); - mShapeInstance->resetMaterialList(); - mShapeInstance->cloneMaterialList(); + if (isGhost()) + { + // Reapply the current skin + mAppliedSkinName = ""; + reSkin(); - if (isGhost()) - { - // Reapply the current skin - mAppliedSkinName = ""; - reSkin(); + updateMaterials(); + } - updateMaterials(); - } + prepCollision(); - prepCollision(); + // Find the "ambient" animation if it exists + S32 ambientSeq = getShape()->findSequence("ambient"); - // Find the "ambient" animation if it exists - S32 ambientSeq = mShape->findSequence("ambient"); + if (ambientSeq > -1 && !mAmbientThread) + mAmbientThread = mShapeInstance->addThread(); - if (ambientSeq > -1 && !mAmbientThread) - mAmbientThread = mShapeInstance->addThread(); + if ( mAmbientThread ) + mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset); - if ( mAmbientThread ) - mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset); - - // Resolve CubeReflectorDesc. - if (cubeDescName.isNotEmpty()) - { - Sim::findObject(cubeDescName, reflectorDesc); - } - else if (cubeDescId > 0) - { - Sim::findObject(cubeDescId, reflectorDesc); + // Resolve CubeReflectorDesc. + if (cubeDescName.isNotEmpty()) + { + Sim::findObject(cubeDescName, reflectorDesc); + } + else if (cubeDescId > 0) + { + Sim::findObject(cubeDescId, reflectorDesc); + } } //Set up the material slot vars for easy manipulation @@ -533,20 +526,20 @@ void TSStatic::prepCollision() if (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh) { - mShape->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD); + getShape()->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD); if (mDecalType == mCollisionType) { mDecalDetailsPtr = &mCollisionDetails; } else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) { - mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); + getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); mDecalDetailsPtr = &mDecalDetails; } } else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) { - mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); + getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); mDecalDetailsPtr = &mDecalDetails; } @@ -564,12 +557,12 @@ void TSStatic::_updatePhysics() if (mCollisionType == Bounds) { MatrixF offset(true); - offset.setPosition(mShape->center); + offset.setPosition(getShape()->center); colShape = PHYSICSMGR->createCollision(); colShape->addBox(getObjBox().getExtents() * 0.5f * mObjScale, offset); } else - colShape = mShape->buildColShape(mCollisionType == VisibleMesh, getScale()); + colShape = getShape()->buildColShape(mCollisionType == VisibleMesh, getScale()); if (colShape) { @@ -958,7 +951,7 @@ U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream) if (stream->writeFlag(mask & AdvancedStaticOptionsMask)) { - PACK_ASSET(con, Shape); + PACK_ASSET_REFACTOR(con, Shape); stream->write((U32)mDecalType); @@ -1074,7 +1067,7 @@ void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream) if (stream->readFlag()) // AdvancedStaticOptionsMask { - UNPACK_ASSET(con, Shape); + UNPACK_ASSET_REFACTOR(con, Shape); stream->read((U32*)&mDecalType); @@ -1596,7 +1589,7 @@ void TSStatic::updateMaterials() if (mShapeAsset->isAssetValid()) path = mShapeAsset->getShapeFileName(); else - path = mShapeName; + path = mShapeFile; pMatList->setTextureLookupPath(path); @@ -1778,7 +1771,7 @@ DefineEngineMethod(TSStatic, changeMaterial, void, (const char* mapTo, Material* return; } - TSMaterialList* shapeMaterialList = object->getShapeResource()->materialList; + TSMaterialList* shapeMaterialList = object->getShape()->materialList; // Check the mapTo name exists for this shape S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo)); @@ -1818,7 +1811,7 @@ DefineEngineMethod(TSStatic, getModelFile, const char*, (), , "@endtsexample\n" ) { - return object->getShape(); + return object->getShapeFile(); } void TSStatic::set_special_typing() @@ -1863,14 +1856,14 @@ void TSStatic::setSelectionFlags(U8 flags) bool TSStatic::hasNode(const char* nodeName) { - S32 nodeIDx = getShapeResource()->findNode(nodeName); + S32 nodeIDx = getShape()->findNode(nodeName); return nodeIDx >= 0; } void TSStatic::getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat) { - S32 nodeIDx = getShapeResource()->findNode(nodeName); + S32 nodeIDx = getShape()->findNode(nodeName); MatrixF nodeTransform(xfm); const Point3F& scale = getScale(); diff --git a/Engine/source/T3D/tsStatic.h b/Engine/source/T3D/tsStatic.h index fef5ed0bb..150aa59cf 100644 --- a/Engine/source/T3D/tsStatic.h +++ b/Engine/source/T3D/tsStatic.h @@ -101,7 +101,7 @@ public: /// A simple mesh shape with optional ambient animation. -class TSStatic : public SceneObject +class TSStatic : public SceneObject, protected AssetPtrCallback { typedef SceneObject Parent; @@ -186,12 +186,17 @@ protected: ReflectorDesc* reflectorDesc; CubeReflector mCubeReflector; + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + _createShape(); + _updateShouldTick(); + } + protected: Convex* mConvexList; - DECLARE_SHAPEASSET(TSStatic, Shape, onShapeChanged); - DECLARE_ASSET_NET_SETGET(TSStatic, Shape, AdvancedStaticOptionsMask); + DECLARE_SHAPEASSET_NET_REFACTOR(TSStatic, Shape, AdvancedStaticOptionsMask) U32 mShapeHash; Vector mCollisionDetails; @@ -239,7 +244,7 @@ public: DECLARE_CATEGORY("Object \t Simple"); static void initPersistFields(); /// returns the shape asset used for this object - StringTableEntry getTypeHint() const override { return (getShapeAsset()) ? getShapeAsset()->getAssetName(): StringTable->EmptyString(); } + StringTableEntry getTypeHint() const override { return (mShapeAsset.notNull()) ? mShapeAsset->getAssetName(): StringTable->EmptyString(); } static void consoleInit(); static bool _setFieldSkin(void* object, const char* index, const char* data); static const char* _getFieldSkin(void* object, const char* data); diff --git a/Engine/source/T3D/turret/aiTurretShape.cpp b/Engine/source/T3D/turret/aiTurretShape.cpp index 5ad3df020..cedb51af2 100644 --- a/Engine/source/T3D/turret/aiTurretShape.cpp +++ b/Engine/source/T3D/turret/aiTurretShape.cpp @@ -246,8 +246,8 @@ bool AITurretShapeData::preload(bool server, String &errorStr) return false; // We have mShape at this point. Resolve nodes. - scanNode = mShape->findNode("scanPoint"); - aimNode = mShape->findNode("aimPoint"); + scanNode = getShape()->findNode("scanPoint"); + aimNode = getShape()->findNode("aimPoint"); if (scanNode == -1) scanNode = pitchNode; if (scanNode == -1) scanNode = headingNode; @@ -259,7 +259,7 @@ bool AITurretShapeData::preload(bool server, String &errorStr) for (U32 j = 0; j < MaxStates; j++) { StateData& s = state[j]; if (stateSequence[j] && stateSequence[j][0]) - s.sequence = mShape->findSequence(stateSequence[j]); + s.sequence = getShape()->findSequence(stateSequence[j]); if (s.sequence != -1) { // This state has an animation sequence diff --git a/Engine/source/T3D/turret/turretShape.cpp b/Engine/source/T3D/turret/turretShape.cpp index e155663aa..08380da6a 100644 --- a/Engine/source/T3D/turret/turretShape.cpp +++ b/Engine/source/T3D/turret/turretShape.cpp @@ -217,35 +217,35 @@ bool TurretShapeData::preload(bool server, String &errorStr) return false; // We have mShape at this point. Resolve nodes. - headingNode = mShape->findNode("heading"); - pitchNode = mShape->findNode("pitch"); + headingNode = getShape()->findNode("heading"); + pitchNode = getShape()->findNode("pitch"); // Find any mirror pitch nodes for (U32 i = 0; i < NumMirrorDirectionNodes; ++i) { char name[32]; dSprintf(name, 31, "pitch%d", i+1); - pitchNodes[i] = mShape->findNode(name); + pitchNodes[i] = getShape()->findNode(name); dSprintf(name, 31, "heading%d", i+1); - headingNodes[i] = mShape->findNode(name); + headingNodes[i] = getShape()->findNode(name); } // Resolve weapon mount point node indexes for (U32 i = 0; i < ShapeBase::MaxMountedImages; i++) { char fullName[256]; dSprintf(fullName,sizeof(fullName),"weaponMount%d",i); - weaponMountNode[i] = mShape->findNode(fullName); + weaponMountNode[i] = getShape()->findNode(fullName); } // Recoil animations - recoilSequence[0] = mShape->findSequence("light_recoil"); - recoilSequence[1] = mShape->findSequence("medium_recoil"); - recoilSequence[2] = mShape->findSequence("heavy_recoil"); + recoilSequence[0] = getShape()->findSequence("light_recoil"); + recoilSequence[1] = getShape()->findSequence("medium_recoil"); + recoilSequence[2] = getShape()->findSequence("heavy_recoil"); // Optional sequences used when the turret rotates - pitchSequence = mShape->findSequence("pitch"); - headingSequence = mShape->findSequence("heading"); + pitchSequence = getShape()->findSequence("pitch"); + headingSequence = getShape()->findSequence("heading"); return true; } diff --git a/Engine/source/T3D/vehicles/flyingVehicle.cpp b/Engine/source/T3D/vehicles/flyingVehicle.cpp index 24cf33490..4e10c4b2a 100644 --- a/Engine/source/T3D/vehicles/flyingVehicle.cpp +++ b/Engine/source/T3D/vehicles/flyingVehicle.cpp @@ -135,7 +135,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr) if (!Parent::preload(server, errorStr)) return false; - TSShapeInstance* si = new TSShapeInstance(mShape, false); + TSShapeInstance* si = new TSShapeInstance(getShape(), false); // Resolve objects transmitted from server if (!server) { @@ -164,7 +164,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr) // Resolve jet nodes for (S32 j = 0; j < MaxJetNodes; j++) - jetNode[j] = mShape->findNode(sJetNode[j]); + jetNode[j] = getShape()->findNode(sJetNode[j]); // maxSpeed = maneuveringForce / minDrag; diff --git a/Engine/source/T3D/vehicles/hoverVehicle.cpp b/Engine/source/T3D/vehicles/hoverVehicle.cpp index 482364bd3..9f536454c 100644 --- a/Engine/source/T3D/vehicles/hoverVehicle.cpp +++ b/Engine/source/T3D/vehicles/hoverVehicle.cpp @@ -332,7 +332,7 @@ bool HoverVehicleData::preload(bool server, String &errorStr) } // Resolve jet nodes for (S32 j = 0; j < MaxJetNodes; j++) - jetNode[j] = mShape->findNode(sJetNode[j]); + jetNode[j] = getShape()->findNode(sJetNode[j]); return true; } diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index 9ad0abdbf..167ea203a 100644 --- a/Engine/source/T3D/vehicles/vehicle.cpp +++ b/Engine/source/T3D/vehicles/vehicle.cpp @@ -163,7 +163,7 @@ bool VehicleData::preload(bool server, String &errorStr) if (!collisionDetails.size() || collisionDetails[0] == -1) { Con::errorf("VehicleData::preload failed: Vehicle models must define a collision-1 detail"); - errorStr = String::ToString("VehicleData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId()); + errorStr = String::ToString("VehicleData: Couldn't load shape asset \"%s\"", getShapeAsset().getAssetId()); return false; } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.cpp b/Engine/source/T3D/vehicles/wheeledVehicle.cpp index 9f3febd13..ec107eedc 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.cpp +++ b/Engine/source/T3D/vehicles/wheeledVehicle.cpp @@ -75,8 +75,6 @@ ConsoleDocClass( WheeledVehicleTire, WheeledVehicleTire::WheeledVehicleTire() { - INIT_ASSET(Shape); - staticFriction = 1; kineticFriction = 0.5f; restitution = 1; @@ -88,15 +86,16 @@ WheeledVehicleTire::WheeledVehicleTire() longitudinalDamping = 1; longitudinalRelaxation = 1; mass = 1.f; + mShapeAsset.registerRefreshNotify(this); } bool WheeledVehicleTire::preload(bool server, String &errorStr) { // Load up the tire shape. ShapeBase has an option to force a // CRC check, this is left out here, but could be easily added. - if (!mShape) + if (!getShape()) { - errorStr = String::ToString("WheeledVehicleTire: Couldn't load shape \"%s\"", mShapeAssetId); + errorStr = String::ToString("WheeledVehicleTire: Couldn't load shape \"%s\"", _getShapeAssetId()); return false; } else @@ -104,7 +103,7 @@ bool WheeledVehicleTire::preload(bool server, String &errorStr) // Determinw wheel radius from the shape's bounding box. // The tire should be built with it's hub axis along the // object's Y axis. - radius = mShape->mBounds.len_z() / 2; + radius = getShape()->mBounds.len_z() / 2; } return true; @@ -113,7 +112,7 @@ bool WheeledVehicleTire::preload(bool server, String &errorStr) void WheeledVehicleTire::initPersistFields() { docsURL; - INITPERSISTFIELD_SHAPEASSET(Shape, WheeledVehicleTire, "The shape to use for the wheel."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, WheeledVehicleTire, "The shape to use for the wheel."); addFieldV( "mass", TypeRangedF32, Offset(mass, WheeledVehicleTire), &CommonValidators::PositiveFloat, "The mass of the wheel.\nCurrently unused." ); @@ -178,7 +177,7 @@ void WheeledVehicleTire::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); stream->write(mass); stream->write(staticFriction); @@ -197,7 +196,7 @@ void WheeledVehicleTire::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); stream->read(&mass); stream->read(&staticFriction); @@ -343,7 +342,7 @@ bool WheeledVehicleData::preload(bool server, String &errorStr) // A temporary shape instance is created so that we can // animate the shape and extract wheel information. - TSShapeInstance* si = new TSShapeInstance(mShape, false); + TSShapeInstance* si = new TSShapeInstance(getShape(), false); // Resolve objects transmitted from server if (!server) { @@ -367,14 +366,14 @@ bool WheeledVehicleData::preload(bool server, String &errorStr) // The wheel must have a hub node to operate at all. dSprintf(buff,sizeof(buff),"hub%d",i); - wp->springNode = mShape->findNode(buff); + wp->springNode = getShape()->findNode(buff); if (wp->springNode != -1) { // Check for spring animation.. If there is none we just grab // the current position of the hub. Otherwise we'll animate // and get the position at time 0. dSprintf(buff,sizeof(buff),"spring%d",i); - wp->springSequence = mShape->findSequence(buff); + wp->springSequence = getShape()->findSequence(buff); if (wp->springSequence == -1) si->mNodeTransforms[wp->springNode].getColumn(3, &wp->pos); else { @@ -403,17 +402,17 @@ bool WheeledVehicleData::preload(bool server, String &errorStr) // Check for steering. Should think about normalizing the // steering animation the way the suspension is, but I don't // think it's as critical. - steeringSequence = mShape->findSequence("steering"); + steeringSequence = getShape()->findSequence("steering"); // Brakes - brakeLightSequence = mShape->findSequence("brakelight"); + brakeLightSequence = getShape()->findSequence("brakelight"); // Extract collision planes from shape collision detail level if (collisionDetails[0] != -1) { MatrixF imat(1); SphereF sphere; - sphere.center = mShape->center; - sphere.radius = mShape->mRadius; + sphere.center = getShape()->center; + sphere.radius = getShape()->mRadius; PlaneExtractorPolyList polyList; polyList.mPlaneList = &rigidBody.mPlaneList; polyList.setTransform(&imat, Point3F(1,1,1)); @@ -1579,8 +1578,8 @@ void WheeledVehicle::unpackUpdate(NetConnection *con, BitStream *stream) // Create an instance of the tire for rendering delete wheel->shapeInstance; - wheel->shapeInstance = (wheel->tire->mShape == NULL) ? 0: - new TSShapeInstance(wheel->tire->mShape); + wheel->shapeInstance = (wheel->tire->getShape() == NULL) ? 0: + new TSShapeInstance(wheel->tire->getShape()); } } } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.h b/Engine/source/T3D/vehicles/wheeledVehicle.h index f208fbf5b..17164a286 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.h +++ b/Engine/source/T3D/vehicles/wheeledVehicle.h @@ -39,12 +39,11 @@ class ParticleEmitterData; //---------------------------------------------------------------------------- -struct WheeledVehicleTire: public SimDataBlock +struct WheeledVehicleTire: public SimDataBlock, protected AssetPtrCallback { typedef SimDataBlock Parent; - DECLARE_SHAPEASSET(WheeledVehicleTire, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(WheeledVehicleTire, Shape); + DECLARE_SHAPEASSET_REFACTOR(WheeledVehicleTire, Shape) // Physical properties F32 mass; // Mass of the whole wheel @@ -74,7 +73,8 @@ struct WheeledVehicleTire: public SimDataBlock void packData(BitStream* stream) override; void unpackData(BitStream* stream) override; - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } diff --git a/Engine/source/afx/afxMagicMissile.cpp b/Engine/source/afx/afxMagicMissile.cpp index d77ead423..46a8d6371 100644 --- a/Engine/source/afx/afxMagicMissile.cpp +++ b/Engine/source/afx/afxMagicMissile.cpp @@ -141,7 +141,6 @@ U32 Projectile::smProjectileWarpTicks = 5; // afxMagicMissileData::afxMagicMissileData() { - INIT_ASSET(ProjectileShape); INIT_ASSET(ProjectileSound); /* From stock Projectile code... @@ -241,11 +240,13 @@ afxMagicMissileData::afxMagicMissileData() reverse_targeting = false; caster_safety_time = U32_MAX; + + mProjectileShapeAsset.registerRefreshNotify(this); } afxMagicMissileData::afxMagicMissileData(const afxMagicMissileData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - CLONE_ASSET(ProjectileShape); + mProjectileShapeAsset = other.mProjectileShapeAsset; projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName CLONE_ASSET(ProjectileSound); splash = other.splash; @@ -305,6 +306,8 @@ afxMagicMissileData::~afxMagicMissileData() { if (wiggle_axis) delete [] wiggle_axis; + + mProjectileShapeAsset.unregisterRefreshNotify(); } afxMagicMissileData* afxMagicMissileData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) @@ -334,7 +337,7 @@ void afxMagicMissileData::initPersistFields() static IRangeValidatorScaled ticksFromMS(TickMs, 0, MaxLifetimeTicks); addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET(ProjectileShape, afxMagicMissileData, "Shape for the projectile"); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(ProjectileShape, afxMagicMissileData, "Shape for the projectile"); addField("scale", TypePoint3F, Offset(scale, afxMagicMissileData)); addField("missileShapeScale", TypePoint3F, myOffset(scale)); endGroup("Shapes"); @@ -531,10 +534,10 @@ bool afxMagicMissileData::preload(bool server, String &errorStr) U32 assetStatus = ShapeAsset::getAssetErrCode(mProjectileShapeAsset); if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) { - projectileShape = mProjectileShapeAsset->getShapeResource(); + projectileShape = getProjectileShape(); if (bool(projectileShape) == false) { - errorStr = String::ToString("afxMagicMissileData::preload: Couldn't load shape \"%s\"", mProjectileShapeAssetId); + errorStr = String::ToString("afxMagicMissileData::preload: Couldn't load shape \"%s\"", _getProjectileShapeAssetId()); return false; } /* From stock Projectile code... @@ -586,7 +589,7 @@ void afxMagicMissileData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET(ProjectileShape); + PACKDATA_ASSET_REFACTOR(ProjectileShape); /* From stock Projectile code... stream->writeFlag(faceViewer); @@ -697,7 +700,7 @@ void afxMagicMissileData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(ProjectileShape); + UNPACKDATA_ASSET_REFACTOR(ProjectileShape); /* From stock Projectile code... faceViewer = stream->readFlag(); */ diff --git a/Engine/source/afx/afxMagicMissile.h b/Engine/source/afx/afxMagicMissile.h index 8aa8f8084..26f731ae3 100644 --- a/Engine/source/afx/afxMagicMissile.h +++ b/Engine/source/afx/afxMagicMissile.h @@ -56,7 +56,7 @@ class SFXSource; //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// // afxMagicMissileData -class afxMagicMissileData : public GameBaseData +class afxMagicMissileData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; @@ -66,16 +66,10 @@ protected: public: enum { MaxLifetimeTicks = 4095 }; - void onShapeChanged() - { - reloadOnLocalClient(); - } - public: // variables set in datablock definition: // Shape related - DECLARE_SHAPEASSET(afxMagicMissileData, ProjectileShape, onShapeChanged); - DECLARE_ASSET_SETGET(afxMagicMissileData, ProjectileShape); + DECLARE_SHAPEASSET_REFACTOR(afxMagicMissileData, ProjectileShape) //StringTableEntry projectileShapeName; //bool hasLight; @@ -228,6 +222,12 @@ public: afxMagicMissileData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); bool allowSubstitutions() const override { return true; } void gather_cons_defs(Vector& defs); + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } }; //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// diff --git a/Engine/source/afx/ce/afxModel.cpp b/Engine/source/afx/ce/afxModel.cpp index 97746493d..00a2e0f71 100644 --- a/Engine/source/afx/ce/afxModel.cpp +++ b/Engine/source/afx/ce/afxModel.cpp @@ -54,7 +54,6 @@ ConsoleDocClass( afxModelData, afxModelData::afxModelData() { - INIT_ASSET(Shape); sequence = ST_NULLSTRING; seq_rate = 1.0f; seq_offset = 0.0f; @@ -79,11 +78,13 @@ afxModelData::afxModelData() shadowMaxVisibleDistance = 80.0f; shadowProjectionDistance = 10.0f; shadowSphereAdjust = 1.0; + + mShapeAsset.registerRefreshNotify(this); } afxModelData::afxModelData(const afxModelData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - CLONE_ASSET(Shape); + mShapeAsset = other.mShapeAsset; sequence = other.sequence; seq_rate = other.seq_rate; seq_offset = other.seq_offset; @@ -113,6 +114,8 @@ afxModelData::~afxModelData() { if (remap_buffer) dFree(remap_buffer); + + mShapeAsset.unregisterRefreshNotify(); } bool afxModelData::preload(bool server, String &errorStr) @@ -126,9 +129,9 @@ bool afxModelData::preload(bool server, String &errorStr) if (mShapeAsset.notNull()) { - if (!mShape) + if (!getShape()) { - errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", mShapeAssetId); + errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", _getShapeAssetId()); return false; } @@ -160,7 +163,7 @@ bool afxModelData::preload(bool server, String &errorStr) if (txr_tag_remappings.size() == 0) { // this little hack forces the textures to preload - TSShapeInstance* pDummy = new TSShapeInstance(mShape); + TSShapeInstance* pDummy = new TSShapeInstance(getShape()); delete pDummy; } } @@ -174,7 +177,7 @@ void afxModelData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET(Shape, afxModelData, "The name of a .dts format file to use for the model."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, afxModelData, "The name of a .dts format file to use for the model."); endGroup("Shapes"); addGroup("Animation"); @@ -258,7 +261,7 @@ void afxModelData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); stream->writeString(sequence); stream->write(seq_rate); stream->write(seq_offset); @@ -289,7 +292,7 @@ void afxModelData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); sequence = stream->readSTString(); stream->read(&seq_rate); stream->read(&seq_offset); @@ -318,21 +321,10 @@ void afxModelData::unpackData(BitStream* stream) void afxModelData::onPerformSubstitutions() { - if (mShapeAssetId != StringTable->EmptyString()) + if (!getShape()) { - mShapeAsset = mShapeAssetId; - if (mShapeAsset.notNull()) - { - mShape = mShapeAsset->getShapeResource(); - } - - if (!mShape) - { - Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", mShapeAssetId); - return; - } - - // REMAP-TEXTURE-TAGS ISSUES? + Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", _getShapeAssetId()); + return; } } @@ -406,18 +398,18 @@ bool afxModel::onAdd() return false; // setup our bounding box - if (mDataBlock->mShape) - mObjBox = mDataBlock->mShape->mBounds; + if (mDataBlock->getShape()) + mObjBox = mDataBlock->getShape()->mBounds; else mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); // setup the shape instance and sequence - if (mDataBlock->mShape) + if (mDataBlock->getShape()) { if (/*isClientObject() && */mDataBlock->txr_tag_remappings.size() > 0) { // temporarily substitute material tags with alternates - TSMaterialList* mat_list = mDataBlock->mShape->materialList; + TSMaterialList* mat_list = mDataBlock->getShape()->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -438,7 +430,7 @@ bool afxModel::onAdd() } } - shape_inst = new TSShapeInstance(mDataBlock->mShape); + shape_inst = new TSShapeInstance(mDataBlock->getShape()); if (true) // isClientObject()) { @@ -447,7 +439,7 @@ bool afxModel::onAdd() // restore the material tags to original form if (mDataBlock->txr_tag_remappings.size() > 0) { - TSMaterialList* mat_list = mDataBlock->mShape->materialList; + TSMaterialList* mat_list = mDataBlock->getShape()->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -513,14 +505,14 @@ bool afxModel::onAdd() resetWorldBox(); - if (mDataBlock->mShape) + if (mDataBlock->getShape()) { // Scan out the collision hulls... static const String sCollisionStr( "collision-" ); - for (U32 i = 0; i < mDataBlock->mShape->details.size(); i++) + for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++) { - const String &name = mDataBlock->mShape->names[mDataBlock->mShape->details[i].nameIndex]; + const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex]; if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0) { @@ -534,7 +526,7 @@ bool afxModel::onAdd() char buff[128]; dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + 8/*MaxCollisionShapes*/); - U32 los = mDataBlock->mShape->findDetail(buff); + U32 los = mDataBlock->getShape()->findDetail(buff); if (los == -1) mLOSDetails.last() = i; else @@ -545,9 +537,9 @@ bool afxModel::onAdd() // Snag any "unmatched" LOS details static const String sLOSStr( "LOS-" ); - for (U32 i = 0; i < mDataBlock->mShape->details.size(); i++) + for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++) { - const String &name = mDataBlock->mShape->names[mDataBlock->mShape->details[i].nameIndex]; + const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex]; if (name.compare( sLOSStr, sLOSStr.length(), String::NoCase ) == 0) { diff --git a/Engine/source/afx/ce/afxModel.h b/Engine/source/afx/ce/afxModel.h index de2656b8f..ce7fb19ac 100644 --- a/Engine/source/afx/ce/afxModel.h +++ b/Engine/source/afx/ce/afxModel.h @@ -39,12 +39,11 @@ class TSShape; //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// // afxModel Data -struct afxModelData : public GameBaseData +struct afxModelData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; - DECLARE_SHAPEASSET(afxModelData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(afxModelData, Shape); + DECLARE_SHAPEASSET_REFACTOR(afxModelData, Shape) StringTableEntry sequence; @@ -94,13 +93,15 @@ public: static void initPersistFields(); - void onShapeChanged() - { - reloadOnLocalClient(); - } void onSequenceChanged() {} DECLARE_CONOBJECT(afxModelData); + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } }; //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// @@ -154,9 +155,9 @@ public: void setSequenceRateFactor(F32 factor); void setSortPriority(S8 priority) { sort_priority = priority; } - const char* getShapeFileName() const { return mDataBlock->getShape(); } + const char* getShapeFileName() const { return mDataBlock->getShapeFile(); } void setVisibility(bool flag) { is_visible = flag; } - TSShape* getTSShape() { return mDataBlock->getShapeResource(); } + TSShape* getTSShape() { return mDataBlock->getShape(); } TSShapeInstance* getTSShapeInstance() { return shape_inst; } U32 setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans); diff --git a/Engine/source/afx/ce/afxStaticShape.h b/Engine/source/afx/ce/afxStaticShape.h index 3d0e3f2d9..fce335f90 100644 --- a/Engine/source/afx/ce/afxStaticShape.h +++ b/Engine/source/afx/ce/afxStaticShape.h @@ -85,7 +85,7 @@ public: U32 packUpdate(NetConnection*, U32, BitStream*) override; void unpackUpdate(NetConnection*, BitStream*) override; - const char* getShapeFileName() const { return mDataBlock->mShapeAsset->getShapeFileName(); } + const char* getShapeFileName() const { return mDataBlock->getShapeFile(); } void setVisibility(bool flag) { mIs_visible = flag; } DECLARE_CONOBJECT(afxStaticShape); diff --git a/Engine/source/environment/VolumetricFog.cpp b/Engine/source/environment/VolumetricFog.cpp index 875982015..be8b8a2cc 100644 --- a/Engine/source/environment/VolumetricFog.cpp +++ b/Engine/source/environment/VolumetricFog.cpp @@ -135,8 +135,6 @@ VolumetricFog::VolumetricFog() mTexTiles = 1.0f; mSpeed1.set(0.5f, 0.0f); mSpeed2.set(0.1f, 0.1f); - - INIT_ASSET(Shape); } VolumetricFog::~VolumetricFog() @@ -164,7 +162,7 @@ void VolumetricFog::initPersistFields() docsURL; Parent::initPersistFields(); addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET(Shape, VolumetricFog, "The source shape asset."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, VolumetricFog, "The source shape asset."); endGroup("Shapes"); addGroup("VolumetricFogData"); @@ -342,7 +340,7 @@ void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize) bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId) { - mShapeAssetId = shapeAssetId; + _setShape(shapeAssetId); LoadShape(); return true; @@ -358,20 +356,20 @@ bool VolumetricFog::LoadShape() return false; } - if (!mShape) + if (!getShape()) { Con::errorf("VolumetricFog::_createShape() - Shape Asset had no valid shape!"); return false; } - mObjBox = mShape->mBounds; - mRadius = mShape->mRadius; + mObjBox = getShape()->mBounds; + mRadius = getShape()->mRadius; resetWorldBox(); if (!isClientObject()) return false; - TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false); + TSShapeInstance *mShapeInstance = new TSShapeInstance(getShape(), false); meshes mesh_detail; for (S32 i = 0; i < det_size.size(); i++) @@ -387,9 +385,9 @@ bool VolumetricFog::LoadShape() // browsing model for detail levels - for (U32 i = 0; i < mShape->details.size(); i++) + for (U32 i = 0; i < getShape()->details.size(); i++) { - const TSDetail *detail = &mShape->details[i]; + const TSDetail *detail = &getShape()->details[i]; mesh_detail.det_size = detail->size; mesh_detail.sub_shape = detail->subShapeNum; mesh_detail.obj_det = detail->objectDetailNum; @@ -405,8 +403,8 @@ bool VolumetricFog::LoadShape() const S32 ss = det_size[i].sub_shape; if (ss >= 0) { - const S32 start = mShape->subShapeFirstObject[ss]; - const S32 end = start + mShape->subShapeNumObjects[ss]; + const S32 start = getShape()->subShapeFirstObject[ss]; + const S32 end = start + getShape()->subShapeNumObjects[ss]; for (S32 j = start; j < end; j++) { // Loading shape, only the first mesh for each detail will be used! @@ -568,7 +566,7 @@ U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream) } if (stream->writeFlag(mask & FogShapeMask)) { - PACK_ASSET(con, Shape); + PACK_ASSET_REFACTOR(con, Shape); mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); @@ -597,8 +595,8 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) VectorF scale; VectorF mOldScale = getScale(); StringTableEntry oldTextureName = mTextureAsset.getAssetId(); - StringTableEntry oldShapeAsset = mShapeAssetId; - StringTableEntry oldShape = mShapeName; + StringTableEntry oldShapeAsset = _getShapeAssetId(); + StringTableEntry oldShape = getShapeFile(); if (stream->readFlag())// Fog color stream->read(&mFogColor); @@ -667,11 +665,11 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) } if (stream->readFlag())//Fog shape { - UNPACK_ASSET(con, Shape); + UNPACK_ASSET_REFACTOR(con, Shape); mathRead(*stream, &mat); mathRead(*stream, &scale); - if (strcmp(oldShapeAsset, mShapeAssetId) != 0 || strcmp(oldShape, mShapeName) != 0) + if (strcmp(oldShapeAsset, _getShapeAssetId()) != 0 || strcmp(oldShape, getShapeFile()) != 0) { mIsVBDirty = true; mShapeLoaded = LoadShape(); diff --git a/Engine/source/environment/VolumetricFog.h b/Engine/source/environment/VolumetricFog.h index 42f085eab..76519f654 100644 --- a/Engine/source/environment/VolumetricFog.h +++ b/Engine/source/environment/VolumetricFog.h @@ -84,8 +84,7 @@ class VolumetricFog : public SceneObject Vector *indices; }; - DECLARE_SHAPEASSET(VolumetricFog, Shape, onShapeChanged); - DECLARE_ASSET_NET_SETGET(VolumetricFog, Shape, FogShapeMask); + DECLARE_SHAPEASSET_REFACTOR(VolumetricFog, Shape) protected: // Rendertargets; @@ -203,6 +202,7 @@ class VolumetricFog : public SceneObject void ResizeRT(PlatformWindow *win, bool resize); protected: + // Protected methods bool onAdd() override; void onRemove() override; @@ -246,8 +246,6 @@ class VolumetricFog : public SceneObject bool isInsideFog(); bool setShapeAsset(const StringTableEntry shapeAssetId); - - void onShapeChanged() {} DECLARE_CONOBJECT(VolumetricFog); DECLARE_CATEGORY("Environment \t Weather"); From 5d641929cf02f98a5bd6365a22bed4e9fb5d8e56 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 14:10:00 +0100 Subject: [PATCH 15/23] player and ground cover --- Engine/source/T3D/assets/ShapeAsset.h | 58 +++++++++++++++++++++++++++ Engine/source/T3D/fx/groundCover.cpp | 21 +++++----- Engine/source/T3D/fx/groundCover.h | 8 ++-- Engine/source/T3D/player.cpp | 37 ++++++++--------- Engine/source/T3D/player.h | 10 +++-- 5 files changed, 95 insertions(+), 39 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 1d7b960cd..722f5b4ad 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -678,6 +678,64 @@ 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;}\ StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } +#define DECLARE_SHAPEASSET_ARRAY_NET_REFACTOR(className, name, max, mask) \ +private: \ + AssetPtr m##name##Asset[max]; \ + StringTableEntry m##name##File[max] = {StringTable->EmptyString() }; \ +public: \ + void _set##name(StringTableEntry _in, const U32& index){ \ + if (m##name##Asset[index].getAssetId() == _in) \ + return; \ + if(get##name##File(index) == _in) \ + return; \ + if (_in == NULL || _in == StringTable->EmptyString()) \ + { \ + m##name##Asset[index] = NULL; \ + m##name##File[index] = ""; \ + setMaskBits(mask); \ + return; \ + } \ + if (!AssetDatabase.isDeclaredAsset(_in)) \ + { \ + StringTableEntry shapeAssetId = StringTable->EmptyString(); \ + AssetQuery query; \ + S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in); \ + if (foundAssetcount != 0) \ + { \ + shapeAssetId = query.mAssetList[0]; \ + } \ + else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#')) \ + { \ + shapeAssetId = ShapeAsset::getAssetIdByFilename(_in); \ + if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback) \ + { \ + ShapeAsset* privateShape = new ShapeAsset(); \ + privateShape->setShapeFile(_in); \ + shapeAssetId = AssetDatabase.addPrivateAsset(privateShape); \ + } \ + } \ + else \ + { \ + Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in); \ + shapeAssetId = ShapeAsset::smNoShapeAssetFallback; \ + } \ + m##name##Asset[index] = shapeAssetId; \ + m##name##File[index] = _in; \ + } \ + else \ + { \ + m##name##Asset[index] = _in; \ + m##name##File[index] = get##name##File(index); \ + } \ + setMaskBits(mask); \ + }; \ + \ + inline StringTableEntry _get##name##AssetId(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ + Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return 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;}\ + StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } + #define INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));\ addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index 9352deabf..bf53746cb 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -521,7 +521,7 @@ GroundCover::GroundCover() mBillboardRects[i].point.set( 0.0f, 0.0f ); mBillboardRects[i].extent.set( 1.0f, 1.0f ); - INIT_ASSET_ARRAY(Shape, i); + mShapeAsset[i].registerRefreshNotify(this); mShapeInstances[i] = NULL; @@ -563,8 +563,7 @@ void GroundCover::initPersistFields() addField( "billboardUVs", TypeRectUV, Offset( mBillboardRects, GroundCover ), MAX_COVERTYPES, "Subset material UV coordinates for this cover billboard." ); - addField("shapeFilename", TypeFilename, Offset(mShapeName, GroundCover), MAX_COVERTYPES, "The cover shape filename. [Optional]", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_SHAPEASSET_ARRAY(Shape, MAX_COVERTYPES, GroundCover, "The cover shape. [Optional]"); + INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(Shape, MAX_COVERTYPES, GroundCover, "The cover shape. [Optional]"); addField( "layer", TypeTerrainMaterialAssetId, Offset( mLayer, GroundCover ), MAX_COVERTYPES, "Terrain material assetId to limit coverage to, or blank to not limit." ); @@ -767,10 +766,10 @@ U32 GroundCover::packUpdate( NetConnection *connection, U32 mask, BitStream *str stream->write( mBillboardRects[i].point.y ); stream->write( mBillboardRects[i].extent.x ); stream->write( mBillboardRects[i].extent.y ); - - PACK_ASSET_ARRAY(connection, Shape, i); } + PACK_ASSET_ARRAY_REFACTOR(connection, Shape, MAX_COVERTYPES) + stream->writeFlag( mDebugRenderCells ); stream->writeFlag( mDebugNoBillboards ); stream->writeFlag( mDebugNoShapes ); @@ -838,10 +837,10 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream ) stream->read( &mBillboardRects[i].point.y ); stream->read( &mBillboardRects[i].extent.x ); stream->read( &mBillboardRects[i].extent.y ); - - UNPACK_ASSET_ARRAY(connection, Shape, i); } + UNPACK_ASSET_ARRAY_REFACTOR(connection, Shape, MAX_COVERTYPES) + mDebugRenderCells = stream->readFlag(); mDebugNoBillboards = stream->readFlag(); mDebugNoShapes = stream->readFlag(); @@ -887,17 +886,17 @@ void GroundCover::_initShapes() for ( S32 i=0; i < MAX_COVERTYPES; i++ ) { - if ( mShapeAsset[i].isNull() || mShape[i] == nullptr) + if ( mShapeAsset[i].isNull() || getShape(i) == nullptr) continue; - if ( isClientObject() && !mShape[i]->preloadMaterialList(mShape[i].getPath()) && NetConnection::filesWereDownloaded() ) + if ( isClientObject() && !getShape(i)->preloadMaterialList(getShape(i).getPath()) && NetConnection::filesWereDownloaded() ) { - Con::warnf( "GroundCover::_initShapes() material preload failed for shape: %s", mShapeAssetId[i] ); + Con::warnf( "GroundCover::_initShapes() material preload failed for shape: %s", _getShapeAssetId(i)); continue; } // Create the shape instance. - mShapeInstances[i] = new TSShapeInstance(mShape[i], isClientObject() ); + mShapeInstances[i] = new TSShapeInstance(getShape(i), isClientObject() ); } } diff --git a/Engine/source/T3D/fx/groundCover.h b/Engine/source/T3D/fx/groundCover.h index af5d02858..af6a74d7e 100644 --- a/Engine/source/T3D/fx/groundCover.h +++ b/Engine/source/T3D/fx/groundCover.h @@ -111,7 +111,7 @@ public: }; -class GroundCover : public SceneObject +class GroundCover : public SceneObject, protected AssetPtrCallback { friend class GroundCoverShaderConstHandles; friend class GroundCoverCell; @@ -341,8 +341,7 @@ protected: RectF mBillboardRects[MAX_COVERTYPES]; /// The cover shape filenames. - DECLARE_SHAPEASSET_ARRAY(GroundCover, Shape, MAX_COVERTYPES, onShapeChanged); - DECLARE_ASSET_ARRAY_NET_SETGET(GroundCover, Shape, -1); + DECLARE_SHAPEASSET_ARRAY_NET_REFACTOR(GroundCover, Shape, MAX_COVERTYPES, -1) /// The cover shape instances. TSShapeInstance* mShapeInstances[MAX_COVERTYPES]; @@ -410,7 +409,8 @@ protected: void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { _initShapes(); setMaskBits(U32(-1)); diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 8239bd2f3..e6b779eb0 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -297,7 +297,7 @@ PlayerData::PlayerData() imageAnimPrefixFP = StringTable->EmptyString(); for (U32 i=0; iEmptyString()) + if (mShapeFPAsset[i].notNull()) { - if (!mShapeFP[i]) + if (!getShapeFP(i)) { - errorStr = String::ToString("PlayerData: Couldn't load mounted image %d shape \"%s\"", i, mShapeFPAssetId[i]); + errorStr = String::ToString("PlayerData: Couldn't load mounted image %d shape \"%s\"", i, _getShapeFPAssetId(i)); return false; } - if (!server && !mShapeFP[i]->preloadMaterialList(mShapeFP[i].getPath()) && NetConnection::filesWereDownloaded()) + if (!server && !getShapeFP(i)->preloadMaterialList(getShapeFP(i).getPath()) && NetConnection::filesWereDownloaded()) shapeError = true; if (computeCRC) { - Con::printf("Validation required for mounted image %d shape: %s", i, mShapeFPAssetId[i]); + Con::printf("Validation required for mounted image %d shape: %s", i, _getShapeFPAssetId(i)); - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeFP[i].getPath()); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(getShapeFP(i).getPath()); if (!fileRef) { - errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.", i, mShapeFP[i].getPath().getFullPath().c_str()); + errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.", i, getShapeFP(i).getPath().getFullPath().c_str()); return false; } @@ -634,7 +634,7 @@ bool PlayerData::preload(bool server, String &errorStr) mCRCFP[i] = fileRef->getChecksum(); else if (mCRCFP[i] != fileRef->getChecksum()) { - errorStr = String::ToString("PlayerData: Mounted image %d shape \"%s\" does not match version on server.", i, mShapeFPAssetId[i]); + errorStr = String::ToString("PlayerData: Mounted image %d shape \"%s\" does not match version on server.", i, _getShapeFPAssetId(i)); return false; } } @@ -1134,13 +1134,8 @@ void PlayerData::initPersistFields() // Mounted images arrays addArray( "Mounted Images", ShapeBase::MaxMountedImages ); - addProtectedField("shapeNameFP", TypeShapeFilename, Offset(mShapeFPName, PlayerData), &_setShapeFPData, &defaultProtectedGetFn, ShapeBase::MaxMountedImages, - "@brief File name of this player's shape that will be used in conjunction with the corresponding mounted image.\n\n" - "These optional parameters correspond to each mounted image slot to indicate a shape that is rendered " - "in addition to the mounted image shape. Typically these are a player's arms (or arm) that is " - "animated along with the mounted image's state animation sequences.\n", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_SHAPEASSET_ARRAY(ShapeFP, ShapeBase::MaxMountedImages, PlayerData, "@brief File name of this player's shape that will be used in conjunction with the corresponding mounted image.\n\n" + INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(ShapeFP, ShapeBase::MaxMountedImages, PlayerData, "@brief File name of this player's shape that will be used in conjunction with the corresponding mounted image.\n\n" "These optional parameters correspond to each mounted image slot to indicate a shape that is rendered " "in addition to the mounted image shape. Typically these are a player's arms (or arm) that is " "animated along with the mounted image's state animation sequences.\n"); @@ -1340,14 +1335,14 @@ void PlayerData::packData(BitStream* stream) stream->writeString(imageAnimPrefixFP); for (U32 i=0; iwrite(mCRCFP[i]); } } + + PACKDATA_ASSET_ARRAY_REFACTOR(ShapeFP, ShapeBase::MaxMountedImages) } void PlayerData::unpackData(BitStream* stream) @@ -1520,14 +1515,14 @@ void PlayerData::unpackData(BitStream* stream) imageAnimPrefixFP = stream->readSTString(); for (U32 i=0; iread(&(mCRCFP[i])); } } + + UNPACKDATA_ASSET_ARRAY_REFACTOR(ShapeFP, ShapeBase::MaxMountedImages) } @@ -1863,9 +1858,9 @@ bool Player::onNewDataBlock( GameBaseData *dptr, bool reload ) { for (U32 i=0; imShapeFP[i])) + if (bool(mDataBlock->getShapeFP(i))) { - mShapeFPInstance[i] = new TSShapeInstance(mDataBlock->mShapeFP[i], isClientObject()); + mShapeFPInstance[i] = new TSShapeInstance(mDataBlock->getShapeFP(i), isClientObject()); mShapeFPInstance[i]->cloneMaterialList(); diff --git a/Engine/source/T3D/player.h b/Engine/source/T3D/player.h index f1f10e29a..a3a426a14 100644 --- a/Engine/source/T3D/player.h +++ b/Engine/source/T3D/player.h @@ -58,7 +58,7 @@ class OpenVRTrackedObject; //---------------------------------------------------------------------------- -struct PlayerData: public ShapeBaseData { +struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already in shapebasedata. */ { typedef ShapeBaseData Parent; enum Constants { RecoverDelayBits = 7, @@ -82,8 +82,7 @@ struct PlayerData: public ShapeBaseData { /// that we don't create a TSThread on the player if we don't /// need to. - DECLARE_SHAPEASSET_ARRAY(PlayerData, ShapeFP, ShapeBase::MaxMountedImages, onShapeChanged); ///< Used to render with mounted images in first person [optional] - DECLARE_ASSET_ARRAY_SETGET(PlayerData, ShapeFP); + DECLARE_SHAPEASSET_ARRAY_REFACTOR(PlayerData, ShapeFP, ShapeBase::MaxMountedImages) StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify /// animation sequences played in first person. [optional] @@ -391,6 +390,11 @@ struct PlayerData: public ShapeBaseData { DECLARE_CALLBACK( void, onEnterMissionArea, ( Player* obj ) ); DECLARE_CALLBACK( void, onLeaveMissionArea, ( Player* obj ) ); /// @} +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } }; From 2b973abdcf15d3ee8903d73cc86072728ded8412 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 14:32:32 +0100 Subject: [PATCH 16/23] physics shape and physics debris --- Engine/source/T3D/physics/physicsDebris.cpp | 30 ++++++++-------- Engine/source/T3D/physics/physicsDebris.h | 13 +++---- Engine/source/T3D/physics/physicsShape.cpp | 39 +++++++++++---------- Engine/source/T3D/physics/physicsShape.h | 8 ++--- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/Engine/source/T3D/physics/physicsDebris.cpp b/Engine/source/T3D/physics/physicsDebris.cpp index d6d5eff8e..7f77f5d0c 100644 --- a/Engine/source/T3D/physics/physicsDebris.cpp +++ b/Engine/source/T3D/physics/physicsDebris.cpp @@ -74,7 +74,12 @@ PhysicsDebrisData::PhysicsDebrisData() lifetime = 5.0f; lifetimeVariance = 0.0f; - INIT_ASSET(Shape); + mShapeAsset.registerRefreshNotify(this); +} + +PhysicsDebrisData::~PhysicsDebrisData() +{ + mShapeAsset.unregisterRefreshNotify(); } bool PhysicsDebrisData::onAdd() @@ -96,12 +101,12 @@ bool PhysicsDebrisData::preload( bool server, String &errorStr ) { // Create a dummy shape to force the generation of shaders and materials // during the level load and not during gameplay. - TSShapeInstance *pDummy = new TSShapeInstance( mShape, !server ); + TSShapeInstance *pDummy = new TSShapeInstance( getShape(), !server); delete pDummy; } else { - errorStr = String::ToString("PhysicsDebrisData::load: Couldn't load shape asset \"%s\"", mShapeAssetId); + errorStr = String::ToString("PhysicsDebrisData::load: Couldn't load shape asset \"%s\"", _getShapeAssetId()); return false; } @@ -113,12 +118,9 @@ void PhysicsDebrisData::initPersistFields() docsURL; addGroup( "Shapes" ); - addProtectedField( "shapeFile", TypeShapeFilename, Offset( mShapeName, PhysicsDebrisData ), &_setShapeData, &defaultProtectedGetFn, - "@brief Path to the .DAE or .DTS file to use for this shape.\n\n" - "Compatable with Live-Asset Reloading.", AbstractClassRep::FIELD_HideInInspectors); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, PhysicsDebrisData, "@brief Shape to use with this debris.\n\n" + "Compatable with Live-Asset Reloading."); - INITPERSISTFIELD_SHAPEASSET(Shape, PhysicsDebrisData, "@brief Shape to use with this debris.\n\n" - "Compatable with Live-Asset Reloading."); endGroup( "Shapes" ); addGroup("Rendering"); @@ -216,7 +218,7 @@ void PhysicsDebrisData::packData(BitStream* stream) stream->write( waterDampingScale ); stream->write( buoyancyDensity ); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); } void PhysicsDebrisData::unpackData(BitStream* stream) @@ -237,7 +239,7 @@ void PhysicsDebrisData::unpackData(BitStream* stream) stream->read( &waterDampingScale ); stream->read( &buoyancyDensity ); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); } DefineEngineMethod( PhysicsDebrisData, preload, void, (), , @@ -248,7 +250,7 @@ DefineEngineMethod( PhysicsDebrisData, preload, void, (), , { String errorStr; - object->_setShape(object->getShape()); + object->_setShape(object->_getShapeAssetId()); if( !object->preload( false, errorStr ) ) Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() ); @@ -362,7 +364,7 @@ bool PhysicsDebris::onAdd() } // Setup our bounding box - mObjBox = mDataBlock->mShape->mBounds; + mObjBox = mDataBlock->getShape()->mBounds; resetWorldBox(); // Add it to the client scene. @@ -625,7 +627,7 @@ void PhysicsDebris::_createFragments() if ( !mWorld ) return; - TSShape *shape = mDataBlock->mShape; + TSShape *shape = mDataBlock->getShape(); mShapeInstance = new TSShapeInstance( shape, true ); mShapeInstance->animate(); @@ -699,7 +701,7 @@ void PhysicsDebris::_findNodes( U32 colNode, Vector &nodeIds ) // 1. Visible mesh nodes are siblings of the collision node under a common parent dummy node // 2. Collision node is a child of its visible mesh node - TSShape *shape = mDataBlock->mShape; + TSShape *shape = mDataBlock->getShape(); S32 itr = shape->nodes[colNode].parentIndex; itr = shape->nodes[itr].firstChild; diff --git a/Engine/source/T3D/physics/physicsDebris.h b/Engine/source/T3D/physics/physicsDebris.h index 9b9ae6861..3b5371647 100644 --- a/Engine/source/T3D/physics/physicsDebris.h +++ b/Engine/source/T3D/physics/physicsDebris.h @@ -42,7 +42,7 @@ class TSShape; //************************************************************************** // Debris Data //************************************************************************** -class PhysicsDebrisData : public GameBaseData +class PhysicsDebrisData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; @@ -86,10 +86,10 @@ public: /// Is rendererd during shadow passes. bool castShadows; - DECLARE_SHAPEASSET(PhysicsDebrisData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(PhysicsDebrisData, Shape); + DECLARE_SHAPEASSET_REFACTOR(PhysicsDebrisData, Shape) PhysicsDebrisData(); + virtual ~PhysicsDebrisData(); bool onAdd() override; bool preload( bool server, String &errorStr ) override; @@ -97,13 +97,14 @@ public: void packData( BitStream *stream ) override; void unpackData( BitStream *stream ) override; - void onShapeChanged() + DECLARE_CONOBJECT( PhysicsDebrisData ); + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } - DECLARE_CONOBJECT( PhysicsDebrisData ); - }; diff --git a/Engine/source/T3D/physics/physicsShape.cpp b/Engine/source/T3D/physics/physicsShape.cpp index 805531c8b..09e86c530 100644 --- a/Engine/source/T3D/physics/physicsShape.cpp +++ b/Engine/source/T3D/physics/physicsShape.cpp @@ -78,11 +78,12 @@ PhysicsShapeData::PhysicsShapeData() buoyancyDensity( 0.0f ), simType( SimType_ClientServer ) { - INIT_ASSET(Shape); + mShapeAsset.registerRefreshNotify(this); } PhysicsShapeData::~PhysicsShapeData() { + mShapeAsset.unregisterRefreshNotify(); } void PhysicsShapeData::initPersistFields() @@ -90,7 +91,7 @@ void PhysicsShapeData::initPersistFields() docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET(Shape, PhysicsShapeData, "@brief Shape asset to be used with this physics object.\n\n" + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, PhysicsShapeData, "@brief Shape asset to be used with this physics object.\n\n" "Compatable with Live-Asset Reloading. ") addField( "debris", TYPEID< SimObjectRef >(), Offset( debris, PhysicsShapeData ), @@ -180,7 +181,7 @@ void PhysicsShapeData::packData( BitStream *stream ) { Parent::packData( stream ); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); stream->write( mass ); stream->write( dynamicFriction ); @@ -204,7 +205,7 @@ void PhysicsShapeData::unpackData( BitStream *stream ) { Parent::unpackData(stream); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); stream->read( &mass ); stream->read( &dynamicFriction ); @@ -249,19 +250,19 @@ void PhysicsShapeData::_onResourceChanged( const Torque::Path &path ) if ( path != Path(mShapeAsset->getShapeFilePath()) ) return; - _setShape(getShape()); + _setShape(_getShapeAssetId()); // Reload the changed shape. PhysicsCollisionRef reloadcolShape; - if ( !mShape ) + if ( !getShape()) { Con::warnf( ConsoleLogEntry::General, "PhysicsShapeData::_onResourceChanged: Could not reload %s.", path.getFileName().c_str() ); return; } // Reload the collision shape. - reloadcolShape = mShape->buildColShape( false, Point3F::One ); + reloadcolShape = getShape()->buildColShape( false, Point3F::One ); if ( bool(reloadcolShape)) colShape = reloadcolShape; @@ -286,31 +287,31 @@ bool PhysicsShapeData::preload( bool server, String &errorBuffer ) if (mShapeAsset.notNull()) { - if (bool(mShape) == false) + if (bool(getShape()) == false) { - errorBuffer = String::ToString("PhysicsShapeData: Couldn't load shape \"%s\"", mShapeAssetId); + errorBuffer = String::ToString("PhysicsShapeData: Couldn't load shape \"%s\"", _getShapeAssetId()); return false; } - if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded()) + if (!server && !getShape()->preloadMaterialList(getShape().getPath()) && NetConnection::filesWereDownloaded()) shapeError = true; } // Prepare the shared physics collision shape. - if ( !colShape && mShape) + if ( !colShape && getShape()) { - colShape = mShape->buildColShape( false, Point3F::One ); + colShape = getShape()->buildColShape( false, Point3F::One ); // If we got here and didn't get a collision shape then // we need to fail... can't have a shape without collision. if ( !colShape ) { //no collision so we create a simple box collision shape from the shapes bounds and alert the user - Con::warnf( "PhysicsShapeData::preload - No collision found for shape '%s', auto-creating one", mShapeAssetId); - Point3F halfWidth = mShape->mBounds.getExtents() * 0.5f; + Con::warnf( "PhysicsShapeData::preload - No collision found for shape '%s', auto-creating one", _getShapeAssetId()); + Point3F halfWidth = getShape()->mBounds.getExtents() * 0.5f; colShape = PHYSICSMGR->createCollision(); MatrixF centerXfm(true); - centerXfm.setPosition(mShape->mBounds.getCenter()); + centerXfm.setPosition(getShape()->mBounds.getCenter()); colShape->addBox(halfWidth, centerXfm); return true; } @@ -703,11 +704,11 @@ bool PhysicsShape::_createShape() mAmbientSeq = -1; PhysicsShapeData *db = getDataBlock(); - if ( !db || !db->mShape) + if ( !db || !db->getShape()) return false; // Set the world box. - mObjBox = db->mShape->mBounds; + mObjBox = db->getShape()->mBounds; resetWorldBox(); // If this is the server and its a client only simulation @@ -721,11 +722,11 @@ bool PhysicsShape::_createShape() } // Create the shape instance. - mShapeInst = new TSShapeInstance( db->mShape, isClientObject() ); + mShapeInst = new TSShapeInstance( db->getShape(), isClientObject() ); if ( isClientObject() ) { - mAmbientSeq = db->mShape->findSequence( "ambient" ); + mAmbientSeq = db->getShape()->findSequence( "ambient" ); _initAmbient(); } diff --git a/Engine/source/T3D/physics/physicsShape.h b/Engine/source/T3D/physics/physicsShape.h index 466e39ebf..7419c2442 100644 --- a/Engine/source/T3D/physics/physicsShape.h +++ b/Engine/source/T3D/physics/physicsShape.h @@ -51,7 +51,7 @@ class PhysicsDebrisData; class ExplosionData; -class PhysicsShapeData : public GameBaseData +class PhysicsShapeData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; @@ -74,8 +74,7 @@ public: public: - DECLARE_SHAPEASSET(PhysicsShapeData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(PhysicsShapeData, Shape); + DECLARE_SHAPEASSET_REFACTOR(PhysicsShapeData, Shape) /// The shared unscaled collision shape. PhysicsCollisionRef colShape; @@ -135,7 +134,8 @@ public: SimObjectRef< ExplosionData > explosion; SimObjectRef< PhysicsShapeData > destroyedShape; - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } From 51f4255c149c25d7e1214ca3018cc5c00f509c10 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 16:27:16 +0100 Subject: [PATCH 17/23] explosion and guiobjectview --- Engine/source/T3D/fx/explosion.cpp | 22 +++++---- Engine/source/T3D/fx/explosion.h | 8 +-- Engine/source/T3D/guiObjectView.cpp | 76 ++++++++++++++--------------- Engine/source/T3D/guiObjectView.h | 35 ++++++------- 4 files changed, 67 insertions(+), 74 deletions(-) diff --git a/Engine/source/T3D/fx/explosion.cpp b/Engine/source/T3D/fx/explosion.cpp index 02676be26..f28a90b72 100644 --- a/Engine/source/T3D/fx/explosion.cpp +++ b/Engine/source/T3D/fx/explosion.cpp @@ -239,7 +239,7 @@ ExplosionData::ExplosionData() explosionScale.set(1.0f, 1.0f, 1.0f); playSpeed = 1.0f; - INIT_ASSET(ExplosionShape); + mExplosionShapeAsset.registerRefreshNotify(this); explosionAnimation = -1; @@ -315,7 +315,7 @@ ExplosionData::ExplosionData(const ExplosionData& other, bool temp_clone) : Game particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr explosionScale = other.explosionScale; playSpeed = other.playSpeed; - CLONE_ASSET(ExplosionShape); + mExplosionShapeAsset = other.mExplosionShapeAsset; explosionAnimation = other.explosionAnimation; // -- from explosionShape sequence "ambient" dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) ); dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs @@ -360,6 +360,8 @@ ExplosionData::~ExplosionData() if (!isTempClone()) return; + mExplosionShapeAsset.unregisterRefreshNotify(); + // particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves #ifdef TRACK_EXPLOSION_DATA_CLONES @@ -393,7 +395,7 @@ void ExplosionData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET(ExplosionShape, ExplosionData, "@brief Optional shape asset to place at the center of the explosion.\n\n" + INITPERSISTFIELD_SHAPEASSET_REFACTOR(ExplosionShape, ExplosionData, "@brief Optional shape asset to place at the center of the explosion.\n\n" "The ambient animation of this model will be played automatically at the start of the explosion."); endGroup("Shapes"); @@ -668,7 +670,7 @@ void ExplosionData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET(ExplosionShape); + PACKDATA_ASSET_REFACTOR(ExplosionShape); //PACKDATA_SOUNDASSET(Sound); PACKDATA_ASSET(Sound); @@ -773,7 +775,7 @@ void ExplosionData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(ExplosionShape); + UNPACKDATA_ASSET_REFACTOR(ExplosionShape); UNPACKDATA_ASSET(Sound); @@ -897,10 +899,10 @@ bool ExplosionData::preload(bool server, String &errorStr) if (mExplosionShapeAsset.notNull()) { // Resolve animations - explosionAnimation = mExplosionShape->findSequence("ambient"); + explosionAnimation = getExplosionShape()->findSequence("ambient"); // Preload textures with a dummy instance... - TSShapeInstance* pDummy = new TSShapeInstance(mExplosionShape, !server); + TSShapeInstance* pDummy = new TSShapeInstance(getExplosionShape(), !server); delete pDummy; } else { @@ -1392,8 +1394,8 @@ bool Explosion::explode() launchDebris( mInitialNormal ); spawnSubExplosions(); - if (bool(mDataBlock->mExplosionShape) && mDataBlock->explosionAnimation != -1) { - mExplosionInstance = new TSShapeInstance(mDataBlock->mExplosionShape, true); + if (bool(mDataBlock->getExplosionShape()) && mDataBlock->explosionAnimation != -1) { + mExplosionInstance = new TSShapeInstance(mDataBlock->getExplosionShape(), true); mExplosionThread = mExplosionInstance->addThread(); mExplosionInstance->setSequence(mExplosionThread, mDataBlock->explosionAnimation, 0); @@ -1403,7 +1405,7 @@ bool Explosion::explode() mEndingMS = U32(mExplosionInstance->getScaledDuration(mExplosionThread) * 1000.0f); mObjScale.convolve(mDataBlock->explosionScale); - mObjBox = mDataBlock->mExplosionShape->mBounds; + mObjBox = mDataBlock->getExplosionShape()->mBounds; resetWorldBox(); } diff --git a/Engine/source/T3D/fx/explosion.h b/Engine/source/T3D/fx/explosion.h index 0ea4c63d7..c00483625 100644 --- a/Engine/source/T3D/fx/explosion.h +++ b/Engine/source/T3D/fx/explosion.h @@ -52,7 +52,7 @@ struct DebrisData; class SFXProfile; //-------------------------------------------------------------------------- -class ExplosionData : public GameBaseData { +class ExplosionData : public GameBaseData, protected AssetPtrCallback { public: typedef GameBaseData Parent; @@ -79,8 +79,7 @@ class ExplosionData : public GameBaseData { Point3F explosionScale; F32 playSpeed; - DECLARE_SHAPEASSET(ExplosionData, ExplosionShape, onShapeChanged); - DECLARE_ASSET_SETGET(ExplosionData, ExplosionShape); + DECLARE_SHAPEASSET_REFACTOR(ExplosionData, ExplosionShape) S32 explosionAnimation; @@ -143,7 +142,8 @@ public: ExplosionData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); bool allowSubstitutions() const override { return true; } - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } diff --git a/Engine/source/T3D/guiObjectView.cpp b/Engine/source/T3D/guiObjectView.cpp index cc29f453b..911e52e60 100644 --- a/Engine/source/T3D/guiObjectView.cpp +++ b/Engine/source/T3D/guiObjectView.cpp @@ -119,8 +119,6 @@ GuiObjectView::GuiObjectView() // By default don't do dynamic reflection // updates for this viewport. mReflectPriority = 0.0f; - INIT_ASSET(Model); - INIT_ASSET(MountedModel); } //------------------------------------------------------------------------------ @@ -137,7 +135,7 @@ void GuiObjectView::initPersistFields() { docsURL; addGroup( "Model" ); - INITPERSISTFIELD_SHAPEASSET(Model, GuiObjectView, "The source shape asset."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Model, GuiObjectView, "The source shape asset."); addField( "skin", TypeRealString, Offset( mSkinName, GuiObjectView ), "The skin to use on the object model." ); endGroup( "Model" ); @@ -150,7 +148,7 @@ void GuiObjectView::initPersistFields() endGroup( "Animation" ); addGroup( "Mounting" ); - INITPERSISTFIELD_SHAPEASSET(MountedModel, GuiObjectView, "The mounted shape asset."); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(MountedModel, GuiObjectView, "The mounted shape asset."); addField( "mountedSkin", TypeRealString, Offset( mMountSkinName, GuiObjectView ), "Skin name used on mounted shape file." ); addField( "mountedNode", TypeRealString, Offset( mMountNodeName, GuiObjectView ), @@ -335,19 +333,23 @@ bool GuiObjectView::setObjectModel( const String& modelName ) { mRunThread = 0; - // Load the shape. - _setModel(modelName); - if( !getModelResource()) + // Load the shape if its not the one already set. + if (modelName.c_str() != _getModelAssetId()) + _setModel(modelName.c_str()); + else + return true; + + if( !getModel()) { Con::warnf( "GuiObjectView::setObjectModel - Failed to load model '%s'", modelName.c_str() ); return false; } - if (!getModelResource()->preloadMaterialList(getModelResource().getPath())) return false; + if (!getModel()->preloadMaterialList(getModel().getPath())) return false; // Instantiate it. - mModelInstance = new TSShapeInstance(getModelResource(), true ); + mModelInstance = new TSShapeInstance(getModel(), true ); mModelInstance->resetMaterialList(); mModelInstance->cloneMaterialList(); @@ -359,8 +361,8 @@ bool GuiObjectView::setObjectModel( const String& modelName ) mModelInstance->initMaterialList(); // Initialize camera values. - mOrbitPos = getModelResource()->center; - mMinOrbitDist = getModelResource()->mRadius; + mOrbitPos = getModel()->center; + mMinOrbitDist = getModel()->mRadius; // Initialize animation. @@ -369,11 +371,6 @@ bool GuiObjectView::setObjectModel( const String& modelName ) return true; } -void GuiObjectView::onModelChanged() -{ - -} - //------------------------------------------------------------------------------ void GuiObjectView::setSkin( const String& name ) @@ -389,17 +386,21 @@ void GuiObjectView::setSkin( const String& name ) bool GuiObjectView::setMountedObject( const String& modelName ) { - // Load the model. - _setMountedModel(modelName); - if (!getMountedModelResource()) + // Load the model if it is not already the asset then set it.. + if (modelName.c_str() != _getMountedModelAssetId()) + _setMountedModel(modelName.c_str()); + else + return true; + + if (!getMountedModel()) { Con::warnf("GuiObjectView::setMountedObject - Failed to load model '%s'", modelName.c_str()); return false; } - if (!getMountedModelResource()->preloadMaterialList(getMountedModelResource().getPath())) return false; + if (!getMountedModel()->preloadMaterialList(getMountedModel().getPath())) return false; - mMountedModelInstance = new TSShapeInstance(getMountedModelResource(), true); + mMountedModelInstance = new TSShapeInstance(getMountedModel(), true); mMountedModelInstance->resetMaterialList(); mMountedModelInstance->cloneMaterialList(); @@ -413,11 +414,6 @@ bool GuiObjectView::setMountedObject( const String& modelName ) return true; } -void GuiObjectView::onMountedModelChanged() -{ - -} - //------------------------------------------------------------------------------ void GuiObjectView::setMountSkin(const String& name) @@ -632,7 +628,7 @@ void GuiObjectView::setLightDirection( const Point3F& direction ) void GuiObjectView::_initAnimation() { - AssertFatal(getModelResource(), "GuiObjectView::_initAnimation - No model loaded!" ); + AssertFatal(getModel(), "GuiObjectView::_initAnimation - No model loaded!" ); if( mAnimationSeqName.isEmpty() && mAnimationSeq == -1 ) return; @@ -641,13 +637,13 @@ void GuiObjectView::_initAnimation() if( !mAnimationSeqName.isEmpty() ) { - mAnimationSeq = getModelResource()->findSequence( mAnimationSeqName ); + mAnimationSeq = getModel()->findSequence( mAnimationSeqName ); if( mAnimationSeq == -1 ) { Con::errorf( "GuiObjectView::_initAnimation - Cannot find animation sequence '%s' on '%s'", mAnimationSeqName.c_str(), - mModelName + _getModelAssetId() ); return; @@ -658,11 +654,11 @@ void GuiObjectView::_initAnimation() if( mAnimationSeq != -1 ) { - if( mAnimationSeq >= getModelResource()->sequences.size() ) + if( mAnimationSeq >= getModel()->sequences.size() ) { Con::errorf( "GuiObjectView::_initAnimation - Sequence '%i' out of range for model '%s'", mAnimationSeq, - mModelName + _getModelAssetId() ); mAnimationSeq = -1; @@ -693,12 +689,12 @@ void GuiObjectView::_initMount() if( !mMountNodeName.isEmpty() ) { - mMountNode = getModelResource()->findNode( mMountNodeName ); + mMountNode = getModel()->findNode( mMountNodeName ); if( mMountNode == -1 ) { Con::errorf( "GuiObjectView::_initMount - No node '%s' on '%s'", mMountNodeName.c_str(), - mModelName + _getModelAssetId() ); return; @@ -707,11 +703,11 @@ void GuiObjectView::_initMount() // Make sure mount node is valid. - if( mMountNode != -1 && mMountNode >= getModelResource()->nodes.size() ) + if( mMountNode != -1 && mMountNode >= getModel()->nodes.size() ) { Con::errorf( "GuiObjectView::_initMount - Mount node index '%i' out of range for '%s'", mMountNode, - mModelName + _getModelAssetId() ); mMountNode = -1; @@ -720,11 +716,11 @@ void GuiObjectView::_initMount() // Look up node on the mounted model from // which to mount to the primary model's node. - if (!getMountedModelResource()) return; - S32 mountPoint = getMountedModelResource()->findNode( "mountPoint" ); + if (!getMountedModel()) return; + S32 mountPoint = getMountedModel()->findNode( "mountPoint" ); if( mountPoint != -1 ) { - getMountedModelResource()->getNodeWorldTransform(mountPoint, &mMountTransform), + getMountedModel()->getNodeWorldTransform(mountPoint, &mMountTransform), mMountTransform.inverse(); } } @@ -745,7 +741,7 @@ DefineEngineMethod( GuiObjectView, getModel, const char*, (),, "@return Name of the displayed model.\n\n" "@see GuiControl") { - return Con::getReturnBuffer( object->getModel() ); + return Con::getReturnBuffer( object->_getModelAssetId() ); } //----------------------------------------------------------------------------- @@ -775,7 +771,7 @@ DefineEngineMethod( GuiObjectView, getMountedModel, const char*, (),, "@return Name of the mounted model.\n\n" "@see GuiControl") { - return Con::getReturnBuffer( object->getMountedModel() ); + return Con::getReturnBuffer( object->_getMountedModelAssetId() ); } //----------------------------------------------------------------------------- diff --git a/Engine/source/T3D/guiObjectView.h b/Engine/source/T3D/guiObjectView.h index 887e32a41..a6e3535b9 100644 --- a/Engine/source/T3D/guiObjectView.h +++ b/Engine/source/T3D/guiObjectView.h @@ -37,7 +37,7 @@ class LightInfo; /// A control that displays a TSShape in its view. -class GuiObjectView : public GuiTSCtrl +class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback { public: @@ -70,15 +70,8 @@ class GuiObjectView : public GuiTSCtrl /// @{ ///Model loaded for display. - DECLARE_SHAPEASSET(GuiObjectView, Model, onModelChanged); - static bool _setModelData(void* obj, const char* index, const char* data)\ - { - bool ret = false; - GuiObjectView* object = static_cast(obj); - ret = object->setObjectModel(StringTable->insert(data)); - return ret; - } - void onModelChanged(); + DECLARE_SHAPEASSET_REFACTOR(GuiObjectView, Model) + TSShapeInstance* mModelInstance; /// Name of skin to use on model. String mSkinName; @@ -109,15 +102,7 @@ class GuiObjectView : public GuiTSCtrl /// @{ ///Model to mount to the primary model. - DECLARE_SHAPEASSET(GuiObjectView, MountedModel, onMountedModelChanged); - static bool _setMountedModelData(void* obj, const char* index, const char* data)\ - { - bool ret = false; - GuiObjectView* object = static_cast(obj); - ret = object->setMountedObject(StringTable->insert(data)); - return ret; - } - void onMountedModelChanged(); + DECLARE_SHAPEASSET_REFACTOR(GuiObjectView, MountedModel) TSShapeInstance* mMountedModelInstance; /// @@ -284,7 +269,17 @@ class GuiObjectView : public GuiTSCtrl static void initPersistFields(); DECLARE_CONOBJECT( GuiObjectView ); - DECLARE_DESCRIPTION( "A control that shows a TSShape model." ); + DECLARE_DESCRIPTION( "A control that shows a TSShape model." ); + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + if (mModelAsset.notNull()) + setObjectModel(_getModelAssetId()); + + if (mMountedModelAsset.notNull()) + setMountedObject(_getMountedModelAssetId()); + } }; #endif // !_GUIOBJECTVIEW_H_ From 1949ff9d7b4fdf2045548e73f417cc73bf34e137 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 16:29:59 +0100 Subject: [PATCH 18/23] projectile --- Engine/source/T3D/projectile.cpp | 32 +++++++++++++++----------------- Engine/source/T3D/projectile.h | 8 ++++---- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index 58c6f3aa6..cf8df1065 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -145,7 +145,7 @@ U32 Projectile::smProjectileWarpTicks = 5; // ProjectileData::ProjectileData() { - INIT_ASSET(ProjectileShape); + mProjectileShapeAsset.registerRefreshNotify(this); INIT_ASSET(ProjectileSound); @@ -223,7 +223,7 @@ ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : G CLONE_ASSET(ProjectileSound); lightDesc = other.lightDesc; lightDescId = other.lightDescId; // -- for pack/unpack of lightDesc ptr - CLONE_ASSET(ProjectileShape);// -- TSShape loads using mProjectileShapeName + mProjectileShapeAsset = other.mProjectileShapeAsset;// -- TSShape loads using mProjectileShapeName activateSeq = other.activateSeq; // -- from projectileShape sequence "activate" maintainSeq = other.maintainSeq; // -- from projectileShape sequence "maintain" particleEmitter = other.particleEmitter; @@ -237,9 +237,7 @@ void ProjectileData::initPersistFields() { docsURL; addGroup("Shapes"); - addProtectedField("projectileShapeName", TypeShapeFilename, Offset(mProjectileShapeName, ProjectileData), &_setProjectileShapeData, &defaultProtectedGetFn, - "@brief File path to the model of the projectile.\n\n", AbstractClassRep::FIELD_HideInInspectors); - INITPERSISTFIELD_SHAPEASSET(ProjectileShape, ProjectileData, "@brief The model of the projectile.\n\n"); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(ProjectileShape, ProjectileData, "@brief The model of the projectile.\n\n"); addField("scale", TypePoint3F, Offset(scale, ProjectileData), "@brief Scale to apply to the projectile's size.\n\n" "@note This is applied after SceneObject::scale\n"); @@ -383,20 +381,20 @@ bool ProjectileData::preload(bool server, String &errorStr) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockid(lightDesc): %d", lightDescId); } - if (mProjectileShapeAssetId != StringTable->EmptyString()) + if (mProjectileShapeAsset.notNull()) { //If we've got a shapeAsset assigned for our projectile, but we failed to load the shape data itself, report the error - if (!mProjectileShape) + if (!getProjectileShape()) { - errorStr = String::ToString("ProjectileData::load: Couldn't load shape \"%s\"", mProjectileShapeAssetId); + errorStr = String::ToString("ProjectileData::load: Couldn't load shape \"%s\"", _getProjectileShapeAssetId()); return false; } else { - activateSeq = mProjectileShape->findSequence("activate"); - maintainSeq = mProjectileShape->findSequence("maintain"); + activateSeq = getProjectileShape()->findSequence("activate"); + maintainSeq = getProjectileShape()->findSequence("maintain"); - TSShapeInstance* pDummy = new TSShapeInstance(mProjectileShape, !server); + TSShapeInstance* pDummy = new TSShapeInstance(getProjectileShape(), !server); delete pDummy; } } @@ -409,7 +407,7 @@ void ProjectileData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET(ProjectileShape); + PACKDATA_ASSET_REFACTOR(ProjectileShape); stream->writeFlag(faceViewer); if(stream->writeFlag(scale.x != 1 || scale.y != 1 || scale.z != 1)) @@ -474,7 +472,7 @@ void ProjectileData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET(ProjectileShape); + UNPACKDATA_ASSET_REFACTOR(ProjectileShape); faceViewer = stream->readFlag(); if(stream->readFlag()) @@ -800,9 +798,9 @@ bool Projectile::onAdd() } else { - if (bool(mDataBlock->mProjectileShape)) + if (bool(mDataBlock->getProjectileShape())) { - mProjectileShape = new TSShapeInstance(mDataBlock->mProjectileShape, isClientObject()); + mProjectileShape = new TSShapeInstance(mDataBlock->getProjectileShape(), isClientObject()); if (mDataBlock->activateSeq != -1) { @@ -841,8 +839,8 @@ bool Projectile::onAdd() processAfter(mSourceObject); // Setup our bounding box - if (bool(mDataBlock->mProjectileShape) == true) - mObjBox = mDataBlock->mProjectileShape->mBounds; + if (bool(mDataBlock->getProjectileShape()) == true) + mObjBox = mDataBlock->getProjectileShape()->mBounds; else mObjBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0)); diff --git a/Engine/source/T3D/projectile.h b/Engine/source/T3D/projectile.h index 2ca827ea7..af1b3e8d3 100644 --- a/Engine/source/T3D/projectile.h +++ b/Engine/source/T3D/projectile.h @@ -63,7 +63,7 @@ class Projectile; //-------------------------------------------------------------------------- /// Datablock for projectiles. This class is the base class for all other projectiles. -class ProjectileData : public GameBaseData +class ProjectileData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; @@ -71,8 +71,7 @@ protected: bool onAdd() override; public: - DECLARE_SHAPEASSET(ProjectileData, ProjectileShape, onShapeChanged); - DECLARE_ASSET_SETGET(ProjectileData, ProjectileShape); + DECLARE_SHAPEASSET_REFACTOR(ProjectileData, ProjectileShape) /// Set to true if it is a billboard and want it to always face the viewer, false otherwise bool faceViewer; @@ -154,7 +153,8 @@ public: ProjectileData(const ProjectileData&, bool = false); bool allowSubstitutions() const override { return true; } - void onShapeChanged() +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } From 08f52cfa16c2a6e87d68614035dd37faca69dfc8 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 16:58:44 +0100 Subject: [PATCH 19/23] add extra checks add extra checks around an empty stringtableentry for assets and bitmap controls --- Engine/source/T3D/assets/ImageAsset.h | 8 ++++---- Engine/source/T3D/assets/ShapeAsset.h | 6 +++--- Engine/source/gui/buttons/guiBitmapButtonCtrl.h | 6 ++++++ Engine/source/gui/controls/guiBitmapCtrl.cpp | 17 ++++++++++------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Engine/source/T3D/assets/ImageAsset.h b/Engine/source/T3D/assets/ImageAsset.h index 102f59052..97623f5a4 100644 --- a/Engine/source/T3D/assets/ImageAsset.h +++ b/Engine/source/T3D/assets/ImageAsset.h @@ -243,7 +243,7 @@ public: return; \ if(get##name##File() == _in) \ return; \ - if(_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset = NULL; \ m##name##File = ""; \ @@ -300,7 +300,7 @@ public: return; \ if(get##name##File() == _in) \ return; \ - if(_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset = NULL; \ m##name##File = ""; \ @@ -364,7 +364,7 @@ public: return; \ if(get##name##File(index) == _in) \ return; \ - if(_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset[index] = NULL; \ m##name##File[index] = ""; \ @@ -422,7 +422,7 @@ public: return; \ if(get##name##File(index) == _in) \ return; \ - if(_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset[index] = NULL; \ m##name##File[index] = ""; \ diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 722f5b4ad..2086c0395 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -513,7 +513,7 @@ public: return; \ if(get##name##File() == _in) \ return; \ - if (_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset = NULL; \ m##name##File = ""; \ @@ -569,7 +569,7 @@ public: return; \ if(get##name##File() == _in) \ return; \ - if (_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset = NULL; \ m##name##File = ""; \ @@ -632,7 +632,7 @@ public: return; \ if(get##name##File(index) == _in) \ return; \ - if (_in == NULL || _in == StringTable->EmptyString()) \ + if(_in == NULL || _in == StringTable->EmptyString() || _in == "") \ { \ m##name##Asset[index] = NULL; \ m##name##File[index] = ""; \ diff --git a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h index 773f7eb2c..ec96e9344 100644 --- a/Engine/source/gui/buttons/guiBitmapButtonCtrl.h +++ b/Engine/source/gui/buttons/guiBitmapButtonCtrl.h @@ -123,6 +123,12 @@ private: String mBitmapFile; public: void _setBitmap(StringTableEntry _in) { + if (_in == NULL || _in == StringTable->EmptyString() || _in == "") + { + mBitmapAsset = NULL; + mBitmapFile = ""; + return; + } 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]; diff --git a/Engine/source/gui/controls/guiBitmapCtrl.cpp b/Engine/source/gui/controls/guiBitmapCtrl.cpp index 52955f90d..fe7aa7862 100644 --- a/Engine/source/gui/controls/guiBitmapCtrl.cpp +++ b/Engine/source/gui/controls/guiBitmapCtrl.cpp @@ -121,16 +121,19 @@ void GuiBitmapCtrl::setBitmap(const char* name, bool resize) if (assetId != StringTable->EmptyString()) _setBitmap(assetId); else - _setBitmap(name); + _setBitmap(StringTable->EmptyString()); } - mBitmap = mBitmapAsset->getTexture(&GFXDefaultGUIProfile); - - if (getBitmap() && resize) + if (mBitmapAsset.notNull()) { - - setExtent(mBitmap->getWidth(), mBitmap->getHeight()); - updateSizing(); + mBitmap = mBitmapAsset->getTexture(&GFXDefaultGUIProfile); + + if (getBitmap() && resize) + { + + setExtent(mBitmap->getWidth(), mBitmap->getHeight()); + updateSizing(); + } } setUpdate(); From 9208cdfcd65035a3797869d3d372c371867c2ec8 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 17:24:43 +0100 Subject: [PATCH 20/23] tsforestitem and forestitem --- Engine/source/forest/forestItem.cpp | 13 ++++++------- Engine/source/forest/forestItem.h | 10 ++++++---- Engine/source/forest/ts/tsForestItemData.cpp | 14 +++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Engine/source/forest/forestItem.cpp b/Engine/source/forest/forestItem.cpp index 239919a91..36c12e8a7 100644 --- a/Engine/source/forest/forestItem.cpp +++ b/Engine/source/forest/forestItem.cpp @@ -53,7 +53,8 @@ ForestItemData::ForestItemData() mTightnessCoefficient( 0.4f ), mDampingCoefficient( 0.7f ) { - INIT_ASSET(Shape); + mShape = NULL; + mShapeAsset.registerRefreshNotify(this); } void ForestItemData::initPersistFields() @@ -61,10 +62,8 @@ void ForestItemData::initPersistFields() docsURL; addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET(Shape, ForestItemData, "Shape asset for this item type"); - - addProtectedField( "shapeFile", TypeShapeFilename, Offset( mShapeName, ForestItemData ), &_setShapeData, &defaultProtectedGetFn, - "Shape file for this item type", AbstractClassRep::FIELD_HideInInspectors ); + INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, ForestItemData, "Shape asset for this item type"); + endGroup( "Shapes" ); addGroup("Physics"); @@ -164,7 +163,7 @@ void ForestItemData::packData(BitStream* stream) stream->write( localName ); - PACKDATA_ASSET(Shape); + PACKDATA_ASSET_REFACTOR(Shape); stream->writeFlag( mCollidable ); @@ -190,7 +189,7 @@ void ForestItemData::unpackData(BitStream* stream) stream->read( &localName ); setInternalName( localName ); - UNPACKDATA_ASSET(Shape); + UNPACKDATA_ASSET_REFACTOR(Shape); mCollidable = stream->readFlag(); diff --git a/Engine/source/forest/forestItem.h b/Engine/source/forest/forestItem.h index 28d9f4248..2b7337593 100644 --- a/Engine/source/forest/forestItem.h +++ b/Engine/source/forest/forestItem.h @@ -48,7 +48,7 @@ struct RayInfo; class AbstractPolyList; -class ForestItemData : public SimDataBlock +class ForestItemData : public SimDataBlock, protected AssetPtrCallback { protected: @@ -62,8 +62,7 @@ protected: public: - DECLARE_SHAPEASSET(ForestItemData, Shape, onShapeChanged); - DECLARE_ASSET_SETGET(ForestItemData, Shape); + DECLARE_SHAPEASSET_REFACTOR(ForestItemData, Shape) /// This is the radius used during placement to ensure /// the element isn't crowded up against other trees. @@ -144,7 +143,10 @@ public: return theSignal; } - void onShapeChanged() + Resource mShape; + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { reloadOnLocalClient(); } diff --git a/Engine/source/forest/ts/tsForestItemData.cpp b/Engine/source/forest/ts/tsForestItemData.cpp index 5c88cf0ef..292ca564d 100644 --- a/Engine/source/forest/ts/tsForestItemData.cpp +++ b/Engine/source/forest/ts/tsForestItemData.cpp @@ -99,13 +99,13 @@ void TSForestItemData::inspectPostApply() void TSForestItemData::_onResourceChanged( const Torque::Path &path ) { - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(_getShapeAssetId()); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; } - if ( path != Path(mShapeAsset->getShapeFilePath()) ) + if ( path != Path(getShapeFile()) ) return; SAFE_DELETE( mShapeInstance ); @@ -116,18 +116,18 @@ void TSForestItemData::_onResourceChanged( const Torque::Path &path ) void TSForestItemData::_loadShape() { - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + mShape = getShape(); + U32 assetStatus = ShapeAsset::getAssetErrCode(_getShapeAssetId()); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; } - _setShape(mShapeAssetId); if ( !(bool)mShape ) return; if ( mIsClientObject && - !mShape->preloadMaterialList(mShapeAsset->getShapeFilePath()) ) + !mShape->preloadMaterialList(mShape.getPath()) ) return; // Lets add an autobillboard detail if don't have one. @@ -165,7 +165,7 @@ TSShapeInstance* TSForestItemData::_getShapeInstance() const void TSForestItemData::_checkLastDetail() { - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(_getShapeAssetId()); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; @@ -177,7 +177,7 @@ void TSForestItemData::_checkLastDetail() // TODO: Expose some real parameters to the datablock maybe? if ( detail->subShapeNum != -1 ) { - mShape->addImposter(mShapeAsset->getShapeFilePath(), 10, 4, 0, 0, 256, 0, 0 ); + mShape->addImposter(mShape.getPath(), 10, 4, 0, 0, 256, 0, 0); // HACK: If i don't do this it crashes! while ( mShape->detailCollisionAccelerators.size() < mShape->details.size() ) From 542563feaf128365dbf80ce438e7a275c8948500 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Thu, 19 Jun 2025 17:32:09 +0100 Subject: [PATCH 21/23] Update ShapeAsset.h fix linux and mac being pedantic about NULL = 0 --- Engine/source/T3D/assets/ShapeAsset.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 2086c0395..8a3d37ba5 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -554,7 +554,7 @@ public: }; \ \ inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); } \ - Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return NULL; } \ + Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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; } \ StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } @@ -612,7 +612,7 @@ public: }; \ \ inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); } \ - Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return NULL; } \ + Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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; } \ StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } @@ -673,7 +673,7 @@ public: }; \ \ inline StringTableEntry _get##name##AssetId(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ - Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return NULL; } \ + Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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;}\ StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } @@ -731,7 +731,7 @@ public: }; \ \ inline StringTableEntry _get##name##AssetId(const U32& index) const { return m##name##Asset[index].getAssetId(); } \ - Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return NULL; } \ + Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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;}\ StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } From fd7342668caed06ffa650e7731e78dbeb3c0edae Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 20 Jun 2025 15:58:20 +0100 Subject: [PATCH 22/23] streamline shape asset shape asset now has the same import "@" as image asset cut out extra filename parameters that arent needed refresh hopefully fixed --- Engine/source/T3D/assets/ShapeAsset.cpp | 173 +++++---- Engine/source/T3D/assets/ShapeAsset.h | 337 ++---------------- Engine/source/T3D/assets/assetImporter.cpp | 86 ++--- Engine/source/T3D/guiObjectView.cpp | 2 +- Engine/source/T3D/physics/physicsDebris.cpp | 2 +- Engine/source/T3D/physics/physicsShape.cpp | 2 +- Engine/source/T3D/shapeBase.cpp | 2 +- Engine/source/T3D/tsStatic.cpp | 2 +- .../source/gui/editor/guiShapeEdPreview.cpp | 2 +- Engine/source/gui/editor/inspector/group.cpp | 2 +- .../editor/inspector/variableInspector.cpp | 2 +- Engine/source/ts/assimp/assimpShapeLoader.cpp | 17 + .../source/ts/collada/colladaShapeLoader.cpp | 17 + Engine/source/ts/tsShapeConstruct.cpp | 2 +- Engine/source/ts/tsShapeConstruct.h | 2 +- 15 files changed, 185 insertions(+), 465 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index decc7258a..c3ee4e89e 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -60,12 +60,20 @@ StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL; IMPLEMENT_CONOBJECT(ShapeAsset); -ConsoleType(assetIdString, TypeShapeAssetPtr, String, ASSET_ID_FIELD_PREFIX) + +//----------------------------------------------------------------------------- +// REFACTOR +//----------------------------------------------------------------------------- + +IMPLEMENT_STRUCT(AssetPtr, AssetPtrShapeAsset, , "") +END_IMPLEMENT_STRUCT + +ConsoleType(ShapeAssetPtr, TypeShapeAssetPtr, AssetPtr, ASSET_ID_FIELD_PREFIX) + ConsoleGetType(TypeShapeAssetPtr) { // Fetch asset Id. - //return *((StringTableEntry*)dptr); return (*((AssetPtr*)dptr)).getAssetId(); } @@ -77,17 +85,24 @@ ConsoleSetType(TypeShapeAssetPtr) // Yes, so fetch field value. const char* pFieldValue = argv[0]; - // Fetch asset Id. - StringTableEntry* assetId = (StringTableEntry*)(dptr); + // Fetch asset pointer. + AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); - // Update asset value. - *assetId = StringTable->insert(pFieldValue); + // Is the asset pointer the correct type? + if (pAssetPtr == NULL) + { + Con::warnf("(TypeShapeAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); return; } // Warn. - Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset."); + Con::warnf("(TypeShapeAssetPtr) - Cannot set multiple args to a single asset."); } //----------------------------------------------------------------------------- @@ -115,52 +130,6 @@ ConsoleSetType(TypeShapeAssetId) Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset."); } -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// REFACTOR -//----------------------------------------------------------------------------- - -IMPLEMENT_STRUCT(AssetPtr, AssetPtrShapeAsset, , "") -END_IMPLEMENT_STRUCT - -ConsoleType(ShapeAssetPtrRefactor, TypeShapeAssetPtrRefactor, AssetPtr, ASSET_ID_FIELD_PREFIX) - - -ConsoleGetType(TypeShapeAssetPtrRefactor) -{ - // Fetch asset Id. - return (*((AssetPtr*)dptr)).getAssetId(); -} - -ConsoleSetType(TypeShapeAssetPtrRefactor) -{ - // 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) - { - Con::warnf("(TypeShapeAssetPtrRefactor) - Failed to set asset Id '%d'.", pFieldValue); - return; - } - - // Set asset. - pAssetPtr->setAssetId(pFieldValue); - - return; - } - - // Warn. - Con::warnf("(TypeShapeAssetPtrRefactor) - Cannot set multiple args to a single asset."); -} - //----------------------------------------------------------------------------- // REFACTOR END //----------------------------------------------------------------------------- @@ -176,15 +145,11 @@ const String ShapeAsset::mErrCodeStrings[] = ShapeAsset::ShapeAsset() { - mFileName = StringTable->EmptyString(); + mShapeFile = StringTable->EmptyString(); mConstructorFileName = StringTable->EmptyString(); - mFilePath = StringTable->EmptyString(); - mConstructorFilePath = StringTable->EmptyString(); mDiffuseImposterFileName = StringTable->EmptyString(); - mDiffuseImposterPath = StringTable->EmptyString(); mNormalImposterFileName = StringTable->EmptyString(); - mNormalImposterPath = StringTable->EmptyString(); mLoadedState = AssetErrCode::NotLoaded; @@ -217,7 +182,7 @@ void ShapeAsset::initPersistFields() // Call parent. Parent::initPersistFields(); - addProtectedField("fileName", TypeAssetLooseFilePath, Offset(mFileName, ShapeAsset), + addProtectedField("fileName", TypeAssetLooseFilePath, Offset(mShapeFile, ShapeAsset), &setShapeFile, &getShapeFile, "Path to the shape file we want to render"); addProtectedField("constuctorFileName", TypeAssetLooseFilePath, Offset(mConstructorFileName, ShapeAsset), &setShapeConstructorFile, &getShapeConstructorFile, "Path to the shape file we want to render"); @@ -225,7 +190,7 @@ void ShapeAsset::initPersistFields() addProtectedField("diffuseImposterFileName", TypeAssetLooseFilePath, Offset(mDiffuseImposterFileName, ShapeAsset), &setDiffuseImposterFile, &getDiffuseImposterFile, "Path to the diffuse imposter file we want to render"); addProtectedField("normalImposterFileName", TypeAssetLooseFilePath, Offset(mNormalImposterFileName, ShapeAsset), - &setNormalImposterFile, &getNormalImposterFile, "Path to the normal imposter file we want to render"); + &setNormalImposterFile, &getNormalImposterFilePath, "Path to the normal imposter file we want to render"); } @@ -248,29 +213,31 @@ void ShapeAsset::initializeAsset() // Call parent. Parent::initializeAsset(); - if (mFileName == StringTable->EmptyString()) + if (mShapeFile == StringTable->EmptyString()) return; ResourceManager::get().getChangedSignal().notify(this, &ShapeAsset::_onResourceChanged); //Ensure our path is expando'd if it isn't already - mFilePath = getOwned() ? expandAssetFilePath(mFileName) : mFilePath; + mShapeFile = getOwned() ? expandAssetFilePath(mShapeFile) : mShapeFile; - mConstructorFilePath = getOwned() ? expandAssetFilePath(mConstructorFileName) : mConstructorFilePath; - if (!Torque::FS::IsFile(mConstructorFilePath)) - Con::errorf("ShapeAsset::initializeAsset (%s) could not find %s!", getAssetName(), mConstructorFilePath); - mDiffuseImposterPath = getOwned() ? expandAssetFilePath(mDiffuseImposterFileName) : mDiffuseImposterFileName; - if (mDiffuseImposterPath == StringTable->EmptyString()) + mConstructorFileName = getOwned() ? expandAssetFilePath(mConstructorFileName) : mConstructorFileName; + if (!Torque::FS::IsFile(mConstructorFileName)) + Con::errorf("ShapeAsset::initializeAsset (%s) could not find %s!", getAssetName(), mConstructorFileName); + + + mDiffuseImposterFileName = getOwned() ? expandAssetFilePath(mDiffuseImposterFileName) : mDiffuseImposterFileName; + if (mDiffuseImposterFileName == StringTable->EmptyString()) { - String diffusePath = String(mFilePath) + "_imposter.dds"; - mDiffuseImposterPath = StringTable->insert(diffusePath.c_str()); + String diffusePath = String(mShapeFile) + "_imposter.dds"; + mDiffuseImposterFileName = StringTable->insert(diffusePath.c_str()); } - mNormalImposterPath = getOwned() ? expandAssetFilePath(mNormalImposterFileName) : mNormalImposterFileName; - if (mNormalImposterPath == StringTable->EmptyString()) + mNormalImposterFileName = getOwned() ? expandAssetFilePath(mNormalImposterFileName) : mNormalImposterFileName; + if (mNormalImposterFileName == StringTable->EmptyString()) { - String normalPath = String(mFilePath) + "_imposter_normals.dds"; - mNormalImposterPath = StringTable->insert(normalPath.c_str()); + String normalPath = String(mShapeFile) + "_imposter_normals.dds"; + mNormalImposterFileName = StringTable->insert(normalPath.c_str()); } } @@ -283,10 +250,10 @@ void ShapeAsset::setShapeFile(const char* pShapeFile) pShapeFile = StringTable->insert(pShapeFile, true); // Ignore no change, - if (pShapeFile == mFileName) + if (pShapeFile == mShapeFile) return; - mFileName = getOwned() ? expandAssetFilePath(pShapeFile) : pShapeFile; + mShapeFile = getOwned() ? expandAssetFilePath(pShapeFile) : pShapeFile; // Refresh the asset. refreshAsset(); @@ -348,7 +315,7 @@ void ShapeAsset::setNormalImposterFile(const char* pImageFile) void ShapeAsset::_onResourceChanged(const Torque::Path &path) { - if (path != Torque::Path(mFilePath) ) + if (path != Torque::Path(mShapeFile) ) return; refreshAsset(); @@ -397,17 +364,17 @@ U32 ShapeAsset::load() } } - mShape = ResourceManager::get().load(mFilePath); + mShape = ResourceManager::get().load(mShapeFile); if (!mShape) { - Con::errorf("ShapeAsset::loadShape : failed to load shape file %s (%s)!", getAssetName(), mFilePath); + Con::errorf("ShapeAsset::loadShape : failed to load shape file %s (%s)!", getAssetName(), mShapeFile); mLoadedState = BadFileReference; return mLoadedState; //if it failed to load, bail out } // Construct billboards if not done already if (GFXDevice::devicePresent()) - mShape->setupBillboardDetails(mFilePath, mDiffuseImposterPath, mNormalImposterPath); + mShape->setupBillboardDetails(mShapeFile, mDiffuseImposterFileName, mNormalImposterFileName); //If they exist, grab our imposters here and bind them to our shapeAsset @@ -467,8 +434,6 @@ U32 ShapeAsset::load() mLoadedState = Ok; - mChangeSignal.trigger(); - return mLoadedState; } @@ -536,13 +501,13 @@ StringTableEntry ShapeAsset::getAssetIdByFilename(StringTableEntry fileName) AssetPtr temp = shapeAsset; if (temp.notNull()) { - if (temp->getShapePath() == fileName) + if (temp->getShapeFile() == fileName) { return shapeAsset; } else { - Torque::Path temp1 = temp->getShapePath(); + Torque::Path temp1 = temp->getShapeFile(); Torque::Path temp2 = fileName; if (temp1.getPath() == temp2.getPath() && temp1.getFileName() == temp2.getFileName()) @@ -606,16 +571,43 @@ void ShapeAsset::copyTo(SimObject* object) void ShapeAsset::onAssetRefresh(void) { - if (mFileName == StringTable->EmptyString()) + // Ignore if not yet added to the sim. + if (!isProperlyAdded()) return; - // Update. - if(!Platform::isFullPath(mFileName)) - mFilePath = getOwned() ? expandAssetFilePath(mFileName) : mFilePath; + if (mShapeFile == StringTable->EmptyString()) + return; + + // Call parent. + Parent::onAssetRefresh(); load(); } +void ShapeAsset::onTamlPreWrite(void) +{ + // Call parent. + Parent::onTamlPreWrite(); + + // ensure paths are collapsed. + mShapeFile = collapseAssetFilePath(mShapeFile); + mConstructorFileName = collapseAssetFilePath(mConstructorFileName); + mDiffuseImposterFileName = collapseAssetFilePath(mDiffuseImposterFileName); + mNormalImposterFileName = collapseAssetFilePath(mNormalImposterFileName); +} + +void ShapeAsset::onTamlPostWrite(void) +{ + // Call parent. + Parent::onTamlPostWrite(); + + // ensure paths are expanded. + mShapeFile = expandAssetFilePath(mShapeFile); + mConstructorFileName = expandAssetFilePath(mConstructorFileName); + mDiffuseImposterFileName = expandAssetFilePath(mDiffuseImposterFileName); + mNormalImposterFileName = expandAssetFilePath(mNormalImposterFileName); +} + void ShapeAsset::SplitSequencePathAndName(String& srcPath, String& srcName) { srcName = ""; @@ -705,7 +697,7 @@ const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overri delete imposterCap; delete shape; - String dumpPath = String(mFilePath) + ".png"; + String dumpPath = String(mShapeFile) + ".png"; char* returnBuffer = Con::getReturnBuffer(128); dSprintf(returnBuffer, 128, "%s", dumpPath.c_str()); @@ -749,14 +741,14 @@ DefineEngineMethod(ShapeAsset, getShapePath, const char*, (), , "Gets the shape's file path\n" "@return The filename of the shape file") { - return object->getShapeFilePath(); + return object->getShapeFile(); } DefineEngineMethod(ShapeAsset, getShapeConstructorFilePath, const char*, (), , "Gets the shape's constructor file.\n" "@return The filename of the shape constructor file") { - return object->getShapeConstructorFilePath(); + return object->getShapeConstructorFile(); } DefineEngineMethod(ShapeAsset, getStatusString, String, (), , "get status string")\ @@ -992,5 +984,4 @@ void GuiInspectorTypeShapeAssetId::consoleInit() ConsoleBaseType::getType(TypeShapeAssetId)->setInspectorFieldType("GuiInspectorTypeShapeAssetId"); } - #endif diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 8a3d37ba5..5efd392b0 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -67,33 +67,6 @@ class ShapeAsset : public AssetBase typedef AssetBase Parent; typedef AssetPtr ConcreteAssetPtr; -protected: - StringTableEntry mFileName; - StringTableEntry mConstructorFileName; - StringTableEntry mFilePath; - StringTableEntry mConstructorFilePath; - Resource mShape; - - StringTableEntry mDiffuseImposterFileName; - StringTableEntry mDiffuseImposterPath; - - StringTableEntry mNormalImposterFileName; - StringTableEntry mNormalImposterPath; - - //Material assets we're dependent on and use - Vector mMaterialAssetIds; - Vector> mMaterialAssets; - - //Animation assets we're dependent on and use - Vector mAnimationAssetIds; - Vector> mAnimationAssets; - - typedef Signal ShapeAssetChanged; - ShapeAssetChanged mChangeSignal; - - typedef Signal ShapeAssetArrayChanged; - ShapeAssetArrayChanged mChangeArraySignal; - public: enum ShapeAssetErrCode { @@ -115,6 +88,23 @@ public: return mErrCodeStrings[errCode - Parent::Extended]; }; +private: + StringTableEntry mShapeFile; + StringTableEntry mConstructorFileName; + StringTableEntry mDiffuseImposterFileName; + StringTableEntry mNormalImposterFileName; + + //Material assets we're dependent on and use + Vector mMaterialAssetIds; + Vector> mMaterialAssets; + + //Animation assets we're dependent on and use + Vector mAnimationAssetIds; + Vector> mAnimationAssets; + + Resource mShape; +public: + ShapeAsset(); virtual ~ShapeAsset(); @@ -127,8 +117,6 @@ public: virtual void setDataField(StringTableEntry slotName, StringTableEntry array, StringTableEntry value); - void initializeAsset() override; - /// Declare Console Object. DECLARE_CONOBJECT(ShapeAsset); @@ -139,10 +127,8 @@ public: Resource getShapeResource() { load(); return mShape; } void SplitSequencePathAndName(String& srcPath, String& srcName); - StringTableEntry getShapeFileName() { return mFileName; } - StringTableEntry getShapePath() { return mFilePath; } - U32 getShapeFilenameHash() { return _StringTable::hashString(mFilePath); } + U32 getShapeFilenameHash() { return _StringTable::hashString(mShapeFile); } Vector> getMaterialAssets() { return mMaterialAssets; } @@ -164,26 +150,18 @@ public: void _onResourceChanged(const Torque::Path& path); - ShapeAssetChanged& getChangedSignal() { return mChangeSignal; } - ShapeAssetArrayChanged& getChangedArraySignal() { return mChangeArraySignal; } - void setShapeFile(const char* pScriptFile); - inline StringTableEntry getShapeFile(void) const { return mFileName; }; + inline StringTableEntry getShapeFile(void) const { return mShapeFile; }; void setShapeConstructorFile(const char* pScriptFile); inline StringTableEntry getShapeConstructorFile(void) const { return mConstructorFileName; }; - inline StringTableEntry getShapeFilePath(void) const { return mFilePath; }; - inline StringTableEntry getShapeConstructorFilePath(void) const { return mConstructorFilePath; }; - //Imposter images void setDiffuseImposterFile(const char* pImageFile); inline StringTableEntry getDiffuseImposterFile(void) const { return mDiffuseImposterFileName; }; - inline StringTableEntry getDiffuseImposterFilePath(void) const { return mDiffuseImposterPath; }; void setNormalImposterFile(const char* pImageFile); - inline StringTableEntry getNormalImposterFile(void) const { return mNormalImposterFileName; }; - inline StringTableEntry getNormalImposterFilePath(void) const { return mNormalImposterPath; }; + inline StringTableEntry getNormalImposterFilePath(void) const { return mNormalImposterFileName; }; static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* shapeAsset); @@ -195,25 +173,33 @@ public: #endif protected: - void onAssetRefresh(void) override; + // Asset Base callback + void initializeAsset(void) override; + void onAssetRefresh(void) override; + /// Taml callbacks. + void onTamlPreWrite(void) override; + void onTamlPostWrite(void) override; + +protected: static bool setShapeFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setShapeFile(data); return false; } static const char* getShapeFile(void* obj, const char* data) { return static_cast(obj)->getShapeFile(); } + static bool writeShapeFile(void* obj, StringTableEntry pFieldName) { return static_cast(obj)->getShapeFile() != StringTable->EmptyString(); } static bool setShapeConstructorFile(void* obj, const char* index, const char* data) { static_cast(obj)->setShapeConstructorFile(data); return false; } static const char* getShapeConstructorFile(void* obj, const char* data) { return static_cast(obj)->getShapeConstructorFile(); } static bool setDiffuseImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setDiffuseImposterFile(data); return false; } static const char* getDiffuseImposterFile(void* obj, const char* data) { return static_cast(obj)->getDiffuseImposterFile(); } + static bool setNormalImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setNormalImposterFile(data); return false; } - static const char* getNormalImposterFile(void* obj, const char* data) { return static_cast(obj)->getNormalImposterFile(); } + static const char* getNormalImposterFilePath(void* obj, const char* data) { return static_cast(obj)->getNormalImposterFilePath(); } }; -DefineConsoleType(TypeShapeAssetPtr, S32) DefineConsoleType(TypeShapeAssetId, String) DECLARE_STRUCT(AssetPtr) -DefineConsoleType(TypeShapeAssetPtrRefactor, AssetPtr) +DefineConsoleType(TypeShapeAssetPtr, AssetPtr) #ifdef TORQUE_TOOLS //----------------------------------------------------------------------------- @@ -249,254 +235,9 @@ public: DECLARE_CONOBJECT(GuiInspectorTypeShapeAssetId); static void consoleInit(); }; + #endif -#pragma region Singular Asset Macros - -#define DECLARE_SHAPEASSET(className,name,changeFunc) public: \ - Resourcem##name;\ - StringTableEntry m##name##Name; \ - StringTableEntry m##name##AssetId;\ - AssetPtr m##name##Asset;\ -public: \ - const StringTableEntry get##name##File() const { return StringTable->insert(m##name##Name); }\ - void set##name##Name(const FileName &_in) { m##name##Name = _in;}\ - 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 (m##name##Asset.notNull())\ - {\ - m##name##Asset->getChangedSignal().remove(this, &className::changeFunc);\ - }\ - if (_in == NULL || _in == StringTable->EmptyString())\ - {\ - m##name##Name = StringTable->EmptyString();\ - m##name##AssetId = StringTable->EmptyString();\ - m##name##Asset = NULL;\ - m##name = NULL;\ - return true;\ - }\ - \ - if (AssetDatabase.isDeclaredAsset(_in))\ - {\ - m##name##AssetId = _in;\ - \ - U32 assetState = ShapeAsset::getAssetById(m##name##AssetId, &m##name##Asset);\ - \ - if (ShapeAsset::Ok == assetState)\ - {\ - m##name##Name = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - StringTableEntry assetId = ShapeAsset::getAssetIdByFilename(_in);\ - if (assetId != StringTable->EmptyString())\ - {\ - m##name##AssetId = assetId;\ - if (ShapeAsset::getAssetById(m##name##AssetId, &m##name##Asset) == ShapeAsset::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##Asset.notNull())\ - {\ - m##name = m##name##Asset->getShapeResource();\ - \ - m##name##Asset->getChangedSignal().notify(this, &className::changeFunc);\ - }\ - else\ - {\ - m##name = NULL;\ - }\ - \ - if(get##name() == StringTable->EmptyString())\ - return true;\ - \ - if (m##name##Asset.notNull() && m##name##Asset->getStatus() != ShapeAsset::Ok)\ - {\ - Con::errorf("%s(%s)::_set%s() - shape asset failure \"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ShapeAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\ - return false; \ - }\ - else if (!m##name)\ - {\ - Con::errorf("%s(%s)::_set%s() - Couldn't load shape \"%s\"", macroText(className), getName(), macroText(name), _in);\ - return false;\ - }\ - return true;\ - }\ - \ - const StringTableEntry get##name() const\ - {\ - if (m##name##Asset && (m##name##Asset->getShapePath() != StringTable->EmptyString()))\ - return m##name##Asset->getShapePath();\ - else if (m##name##AssetId != StringTable->EmptyString())\ - return m##name##AssetId;\ - else if (m##name##Name != StringTable->EmptyString())\ - return m##name##Name;\ - else\ - return StringTable->EmptyString();\ - }\ - Resource get##name##Resource() \ - {\ - return m##name;\ - }\ - bool is##name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); } - -#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS - -#define INITPERSISTFIELD_SHAPEASSET(name, consoleClass, docs) \ - addProtectedField(assetText(name, File), TypeShapeFilename, Offset(m##name##Name, consoleClass), _set##name##Data, & defaultProtectedGetFn, assetText(name, docs)); \ - addProtectedField(assetText(name, Asset), TypeShapeAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, & defaultProtectedGetFn, assetText(name, asset reference.)); - -#else - -#define INITPERSISTFIELD_SHAPEASSET(name, consoleClass, docs) \ - addProtectedField(assetText(name, File), TypeShapeFilename, Offset(m##name##Name, consoleClass), _set##name##Data, & defaultProtectedGetFn, assetText(name, docs), AbstractClassRep::FIELD_HideInInspectors); \ - addProtectedField(assetText(name, Asset), TypeShapeAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, & defaultProtectedGetFn, assetText(name, asset reference.)); - -#endif // SHOW_LEGACY_FILE_FIELDS - -#pragma endregion - -#pragma region Arrayed Asset Macros - -#define DECLARE_SHAPEASSET_ARRAY(className,name,max,changeFunc) public: \ - static const U32 sm##name##Count = max;\ - Resourcem##name[max];\ - StringTableEntry m##name##Name[max]; \ - StringTableEntry m##name##AssetId[max];\ - AssetPtr m##name##Asset[max];\ -public: \ - const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\ - void set##name##Name(const FileName &_in, const U32& index) { m##name##Name[index] = _in;}\ - 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##Asset[index].notNull())\ - {\ - m##name##Asset[index]->getChangedSignal().remove(this, &className::changeFunc);\ - }\ - 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] = NULL;\ - return true;\ - }\ - \ - if (AssetDatabase.isDeclaredAsset(_in))\ - {\ - m##name##AssetId[index] = _in;\ - \ - U32 assetState = ShapeAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\ - \ - if (ShapeAsset::Ok == assetState)\ - {\ - m##name##Name[index] = StringTable->EmptyString();\ - }\ - }\ - else\ - {\ - StringTableEntry assetId = ShapeAsset::getAssetIdByFilename(_in);\ - if (assetId != StringTable->EmptyString())\ - {\ - m##name##AssetId[index] = assetId;\ - if (ShapeAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]) == ShapeAsset::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##Asset[index].notNull())\ - {\ - m##name[index] = m##name##Asset[index]->getShapeResource();\ - \ - m##name##Asset[index]->getChangedSignal().notify(this, &className::changeFunc);\ - }\ - else\ - {\ - m##name[index] = NULL;\ - }\ - \ - if(get##name(index) == StringTable->EmptyString())\ - return true;\ - \ - if (m##name##Asset[index].notNull() && m##name##Asset[index]->getStatus() != ShapeAsset::Ok)\ - {\ - Con::errorf("%s(%s)::_set%s(%i) - shape asset failure \"%s\" due to [%s]", macroText(className), getName(), macroText(name), index, _in, ShapeAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\ - return false; \ - }\ - else if (!m##name[index])\ - {\ - Con::errorf("%s(%s)::_set%s(%i) - Couldn't load shape \"%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]->getShapePath() != StringTable->EmptyString()))\ - return m##name##Asset[index]->getShapePath();\ - else if (m##name##AssetId[index] != StringTable->EmptyString())\ - return m##name##AssetId[index];\ - else if (m##name##Name[index] != StringTable->EmptyString())\ - return StringTable->insert(m##name##Name[index]);\ - else\ - return StringTable->EmptyString();\ - }\ - Resource get##name##Resource(const U32& index) \ - {\ - if(index >= sm##name##Count || index < 0)\ - return ResourceManager::get().load( "" );\ - return m##name[index];\ - }\ - bool is##name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); } - -#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS - -#define INITPERSISTFIELD_SHAPEASSET_ARRAY(name, arraySize, consoleClass, docs) \ - addProtectedField(assetText(name, File), TypeShapeFilename, Offset(m##name##Name, consoleClass), _set##name##Data, & defaultProtectedGetFn, arraySize, assetText(name, docs)); \ - addProtectedField(assetText(name, Asset), TypeShapeAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, & defaultProtectedGetFn, arraySize, assetText(name, asset reference.)); - -#else - -#define INITPERSISTFIELD_SHAPEASSET_ARRAY(name, arraySize, consoleClass, docs) \ - addProtectedField(assetText(name, File), TypeShapeFilename, Offset(m##name##Name, consoleClass), _set##name##Data, & defaultProtectedGetFn, arraySize, assetText(name, docs), AbstractClassRep::FIELD_HideInInspectors); \ - addProtectedField(assetText(name, Asset), TypeShapeAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, & defaultProtectedGetFn, arraySize,assetText(name, asset reference.)); - -#endif // SHOW_LEGACY_FILE_FIELDS - -#pragma endregion - - //----------------------------------------------------------------------------- // REFACTOR //----------------------------------------------------------------------------- @@ -557,7 +298,7 @@ public: Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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; } \ - StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } + StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapeFile() : ""; } #define DECLARE_SHAPEASSET_NET_REFACTOR(className, name, mask) \ private: \ @@ -615,10 +356,10 @@ public: Resource get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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; } \ - StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; } + StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapeFile() : ""; } #define INITPERSISTFIELD_SHAPEASSET_REFACTOR(name, consoleClass, docs) \ - addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); \ + addProtectedField(assetText(name, Asset), TypeShapeAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); \ addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, file docs.)); @@ -676,7 +417,7 @@ public: Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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;}\ - StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } + StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapeFile() : ""; } #define DECLARE_SHAPEASSET_ARRAY_NET_REFACTOR(className, name, max, mask) \ private: \ @@ -734,10 +475,10 @@ public: Resource get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return ResourceManager::get().load( "" ); } \ 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;}\ - StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; } + StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapeFile() : ""; } #define INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs) \ - addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));\ + addProtectedField(assetText(name, Asset), TypeShapeAssetPtr, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));\ addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.)); #pragma endregion diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 726f490de..b6ce8b535 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -3035,31 +3035,15 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str()); - String shapeFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension(); + String shapeFileName = "@" + assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension(); String constructorFileName = assetItem->filePath.getFileName() + "." TORQUE_SCRIPT_EXTENSION; String assetPath = targetPath + "/" + shapeFileName; String constructorPath = targetPath + "/" + constructorFileName; + constructorFileName = "@" + constructorFileName; String tamlPath = targetPath + "/" + assetName + ".asset.taml"; String originalPath = assetItem->filePath.getFullPath().c_str(); String originalConstructorPath = assetItem->filePath.getPath() + "/" + constructorFileName; - char qualifiedFromFile[2048]; - char qualifiedToFile[2048]; - char qualifiedFromCSFile[2048]; - char qualifiedToCSFile[2048]; - -#ifndef TORQUE_SECURE_VFS - Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); - Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); - Platform::makeFullPathName(originalConstructorPath.c_str(), qualifiedFromCSFile, sizeof(qualifiedFromCSFile)); - Platform::makeFullPathName(constructorPath.c_str(), qualifiedToCSFile, sizeof(qualifiedToCSFile)); -#else - dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile)); - dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile)); - dStrcpy(qualifiedFromCSFile, originalConstructorPath.c_str(), sizeof(qualifiedFromCSFile)); - dStrcpy(qualifiedToCSFile, constructorPath.c_str(), sizeof(qualifiedToCSFile)); -#endif - newAsset->setAssetName(assetName); newAsset->setShapeFile(shapeFileName.c_str()); newAsset->setShapeConstructorFile(constructorFileName.c_str()); @@ -3076,9 +3060,9 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) //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 - if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile)) + if (!isReimport && Torque::FS::IsFile(originalPath)) { - newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile); + newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, originalPath.c_str()); } //iterate through and write out the material maps dependencies @@ -3118,8 +3102,8 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) if (Con::getBoolVariable("$TSLastDetail::dumpImposters", false)) { - String imposterPath = assetItem->assetName + "_imposter.png"; - String normalsPath = assetItem->assetName + "_imposter_normals.png"; + String imposterPath = "@" + assetItem->assetName + "_imposter.png"; + String normalsPath = "@" + assetItem->assetName + "_imposter_normals.png"; newAsset->setDiffuseImposterFile(imposterPath.c_str()); newAsset->setNormalImposterFile(normalsPath.c_str()); @@ -3138,67 +3122,37 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) bool makeNewConstructor = true; if (!isReimport) { - bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - - if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) + //We're doing an in-place import, so double check we've already got a constructor file in the expected spot + if (Torque::FS::IsFile(constructorPath)) { - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromFile); + //Yup, found it, we're good to go + makeNewConstructor = false; + dSprintf(importLogBuffer, sizeof(importLogBuffer), "Existing TSShape Constructor file %s found", constructorPath.c_str()); activityLog.push_back(importLogBuffer); - return ""; - } - - if (!isInPlace) - { - if (Torque::FS::IsFile(qualifiedFromCSFile)) - { - if (!Torque::FS::CopyFile(qualifiedFromCSFile, qualifiedToCSFile, !isReimport)) - { - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromCSFile); - activityLog.push_back(importLogBuffer); - } - else - { - //We successfully copied the original constructor file, so no extra work required - makeNewConstructor = false; - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Successfully copied original TSShape Constructor file %s", qualifiedFromCSFile); - activityLog.push_back(importLogBuffer); - } - } } else { - //We're doing an in-place import, so double check we've already got a constructor file in the expected spot - if (Torque::FS::IsFile(qualifiedFromCSFile)) + //Didn't work, but it's possible it's using the old .cs extension when our extension variable is set to something else, so check that one as well just to be sure + Torque::Path constrFilePath = constructorPath; + constrFilePath.setExtension("cs"); + + if (Torque::FS::IsFile(constrFilePath.getFullPath().c_str())) { //Yup, found it, we're good to go makeNewConstructor = false; - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Existing TSShape Constructor file %s found", qualifiedFromCSFile); + dSprintf(importLogBuffer, sizeof(importLogBuffer), "Existing TSShape Constructor file %s found", constrFilePath.getFullPath().c_str()); activityLog.push_back(importLogBuffer); } - else - { - //Didn't work, but it's possible it's using the old .cs extension when our extension variable is set to something else, so check that one as well just to be sure - Torque::Path constrFilePath = qualifiedFromCSFile; - constrFilePath.setExtension("cs"); - - if (Torque::FS::IsFile(constrFilePath.getFullPath().c_str())) - { - //Yup, found it, we're good to go - makeNewConstructor = false; - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Existing TSShape Constructor file %s found", constrFilePath.getFullPath().c_str()); - activityLog.push_back(importLogBuffer); - } - } } } if (makeNewConstructor) { - dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning creation of new TSShapeConstructor file: %s", qualifiedToCSFile); + dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning creation of new TSShapeConstructor file: %s", constructorPath.c_str()); activityLog.push_back(importLogBuffer); //find/create shape constructor - TSShapeConstructor* constructor = TSShapeConstructor::findShapeConstructorByFilename(Torque::Path(qualifiedToFile).getFullPath()); + TSShapeConstructor* constructor = TSShapeConstructor::findShapeConstructorByFilename(Torque::Path(constructorPath).getFullPath()); if (constructor == nullptr) { String fullAssetName = assetItem->moduleName + ":" + assetItem->assetName; @@ -3302,7 +3256,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) PersistenceManager* constructorPersist = new PersistenceManager(); constructorPersist->registerObject(); - constructorPersist->setDirty(constructor, qualifiedToCSFile); + constructorPersist->setDirty(constructor, constructorPath); if (!constructorPersist->saveDirtyObject(constructor)) { diff --git a/Engine/source/T3D/guiObjectView.cpp b/Engine/source/T3D/guiObjectView.cpp index 911e52e60..c086c85ac 100644 --- a/Engine/source/T3D/guiObjectView.cpp +++ b/Engine/source/T3D/guiObjectView.cpp @@ -357,7 +357,7 @@ bool GuiObjectView::setObjectModel( const String& modelName ) mModelInstance->reSkin( mSkinName ); TSMaterialList* pMatList = mModelInstance->getMaterialList(); - pMatList->setTextureLookupPath(mModelAsset->getShapeFileName()); + pMatList->setTextureLookupPath(mModelAsset->getShapeFile()); mModelInstance->initMaterialList(); // Initialize camera values. diff --git a/Engine/source/T3D/physics/physicsDebris.cpp b/Engine/source/T3D/physics/physicsDebris.cpp index 7f77f5d0c..35fee7a34 100644 --- a/Engine/source/T3D/physics/physicsDebris.cpp +++ b/Engine/source/T3D/physics/physicsDebris.cpp @@ -119,7 +119,7 @@ void PhysicsDebrisData::initPersistFields() addGroup( "Shapes" ); INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, PhysicsDebrisData, "@brief Shape to use with this debris.\n\n" - "Compatable with Live-Asset Reloading."); + "Compatable with Live-Asset Reloading."); endGroup( "Shapes" ); diff --git a/Engine/source/T3D/physics/physicsShape.cpp b/Engine/source/T3D/physics/physicsShape.cpp index 09e86c530..55e488009 100644 --- a/Engine/source/T3D/physics/physicsShape.cpp +++ b/Engine/source/T3D/physics/physicsShape.cpp @@ -247,7 +247,7 @@ void PhysicsShapeData::_onResourceChanged( const Torque::Path &path ) { return; } - if ( path != Path(mShapeAsset->getShapeFilePath()) ) + if ( path != Path(mShapeAsset->getShapeFile()) ) return; _setShape(_getShapeAssetId()); diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 8e1f19013..af078b2e2 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -363,7 +363,7 @@ bool ShapeBaseData::preload(bool server, String &errorStr) { Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId()); - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapePath()); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapeFile()); if (!fileRef) { diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index ad41f08c6..eccfee97e 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -1587,7 +1587,7 @@ void TSStatic::updateMaterials() String path; if (mShapeAsset->isAssetValid()) - path = mShapeAsset->getShapeFileName(); + path = mShapeAsset->getShapeFile(); else path = mShapeFile; diff --git a/Engine/source/gui/editor/guiShapeEdPreview.cpp b/Engine/source/gui/editor/guiShapeEdPreview.cpp index 1724db214..ff1c8a884 100644 --- a/Engine/source/gui/editor/guiShapeEdPreview.cpp +++ b/Engine/source/gui/editor/guiShapeEdPreview.cpp @@ -420,7 +420,7 @@ bool GuiShapeEdPreview::setObjectShapeAsset(const char* assetId) if (assetType == StringTable->insert("ShapeAsset")) { ShapeAsset* asset = AssetDatabase.acquireAsset(id); - modelName = asset->getShapeFilePath(); + modelName = asset->getShapeFile(); AssetDatabase.releaseAsset(id); } else if (assetType == StringTable->insert("ShapeAnimationAsset")) diff --git a/Engine/source/gui/editor/inspector/group.cpp b/Engine/source/gui/editor/inspector/group.cpp index 6bd243d60..13953ead5 100644 --- a/Engine/source/gui/editor/inspector/group.cpp +++ b/Engine/source/gui/editor/inspector/group.cpp @@ -665,7 +665,7 @@ void GuiInspectorGroup::addInspectorField(StringTableEntry name, StringTableEntr else if (typeName == StringTable->insert("image")) fieldType = TypeImageAssetPtr; else if (typeName == StringTable->insert("shape")) - fieldType = TypeShapeAssetId; + fieldType = TypeShapeAssetPtr; else if (typeName == StringTable->insert("sound")) fieldType = TypeSoundAssetId; else if (typeName == StringTable->insert("bool")) diff --git a/Engine/source/gui/editor/inspector/variableInspector.cpp b/Engine/source/gui/editor/inspector/variableInspector.cpp index 41a165d32..fc78e76b3 100644 --- a/Engine/source/gui/editor/inspector/variableInspector.cpp +++ b/Engine/source/gui/editor/inspector/variableInspector.cpp @@ -205,7 +205,7 @@ void GuiVariableInspector::addField(const char* name, const char* label, const c else if (newField->mFieldTypeName == StringTable->insert("image")) fieldTypeMask = TypeImageAssetPtr; else if (newField->mFieldTypeName == StringTable->insert("shape")) - fieldTypeMask = TypeShapeAssetId; + fieldTypeMask = TypeShapeAssetPtr; else if (newField->mFieldTypeName == StringTable->insert("bool")) fieldTypeMask = TypeBool; else if (newField->mFieldTypeName == StringTable->insert("object")) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index c261f11cd..a8c5e0079 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -993,6 +993,23 @@ TSShape* assimpLoadShape(const Torque::Path &path) tss->write(&dtsStream); } + Torque::Path dsqPath(cachedPath); + dsqPath.setExtension("dsq"); + FileStream animOutStream; + for (S32 i = 0; i < tss->sequences.size(); i++) + { + const String& seqName = tss->getName(tss->sequences[i].nameIndex); + Con::printf("Writing DSQ Animation File for sequence '%s'", seqName.c_str()); + + dsqPath.setFileName(cachedPath.getFileName() + "_" + seqName); + if (animOutStream.open(dsqPath.getFullPath(), Torque::FS::File::Write)) + { + tss->exportSequence(&animOutStream, tss->sequences[i], false); + animOutStream.close(); + } + + } + loader.updateMaterialsScript(path); } loader.releaseImport(); diff --git a/Engine/source/ts/collada/colladaShapeLoader.cpp b/Engine/source/ts/collada/colladaShapeLoader.cpp index 817ca3a6e..f9bc763ba 100644 --- a/Engine/source/ts/collada/colladaShapeLoader.cpp +++ b/Engine/source/ts/collada/colladaShapeLoader.cpp @@ -737,6 +737,23 @@ TSShape* loadColladaShape(const Torque::Path &path) tss->write(&dtsStream); } + Torque::Path dsqPath(cachedPath); + dsqPath.setExtension("dsq"); + FileStream animOutStream; + for (S32 i = 0; i < tss->sequences.size(); i++) + { + const String& seqName = tss->getName(tss->sequences[i].nameIndex); + Con::printf("Writing DSQ Animation File for sequence '%s'", seqName.c_str()); + + dsqPath.setFileName(cachedPath.getFileName() + "_" + seqName); + if (animOutStream.open(dsqPath.getFullPath(), Torque::FS::File::Write)) + { + tss->exportSequence(&animOutStream, tss->sequences[i], false); + animOutStream.close(); + } + + } + #endif // DAE2DTS_TOOL // Add collada materials to materials.tscript diff --git a/Engine/source/ts/tsShapeConstruct.cpp b/Engine/source/ts/tsShapeConstruct.cpp index 65eafc637..f3f540f8a 100644 --- a/Engine/source/ts/tsShapeConstruct.cpp +++ b/Engine/source/ts/tsShapeConstruct.cpp @@ -2138,7 +2138,7 @@ DefineTSShapeConstructorMethod(addSequence, bool, if (assetType == StringTable->insert("ShapeAsset")) { ShapeAsset* asset = AssetDatabase.acquireAsset(assetId); - srcPath = asset->getShapeFilePath(); + srcPath = asset->getShapeFile(); AssetDatabase.releaseAsset(assetId); } else if (assetType == StringTable->insert("ShapeAnimationAsset")) diff --git a/Engine/source/ts/tsShapeConstruct.h b/Engine/source/ts/tsShapeConstruct.h index df04078de..f4f8dfbff 100644 --- a/Engine/source/ts/tsShapeConstruct.h +++ b/Engine/source/ts/tsShapeConstruct.h @@ -236,7 +236,7 @@ public: StringTableEntry getShapePath() const { if (mShapeAsset.notNull()) - return mShapeAsset->getShapeFilePath(); + return mShapeAsset->getShapeFile(); else return StringTable->EmptyString(); } From ff442f5230b56f24a175fab32ba19517622bcc73 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 20 Jun 2025 17:13:20 +0100 Subject: [PATCH 23/23] keep same naming --- Engine/source/T3D/assets/ShapeAsset.cpp | 2 +- Engine/source/T3D/assets/ShapeAsset.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index c3ee4e89e..0ec856cde 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -190,7 +190,7 @@ void ShapeAsset::initPersistFields() addProtectedField("diffuseImposterFileName", TypeAssetLooseFilePath, Offset(mDiffuseImposterFileName, ShapeAsset), &setDiffuseImposterFile, &getDiffuseImposterFile, "Path to the diffuse imposter file we want to render"); addProtectedField("normalImposterFileName", TypeAssetLooseFilePath, Offset(mNormalImposterFileName, ShapeAsset), - &setNormalImposterFile, &getNormalImposterFilePath, "Path to the normal imposter file we want to render"); + &setNormalImposterFile, &getNormalImposterFile, "Path to the normal imposter file we want to render"); } diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 5efd392b0..150f60b80 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -161,7 +161,7 @@ public: inline StringTableEntry getDiffuseImposterFile(void) const { return mDiffuseImposterFileName; }; void setNormalImposterFile(const char* pImageFile); - inline StringTableEntry getNormalImposterFilePath(void) const { return mNormalImposterFileName; }; + inline StringTableEntry getNormalImposterFile(void) const { return mNormalImposterFileName; }; static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* shapeAsset); @@ -193,7 +193,7 @@ protected: static const char* getDiffuseImposterFile(void* obj, const char* data) { return static_cast(obj)->getDiffuseImposterFile(); } static bool setNormalImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast(obj)->setNormalImposterFile(data); return false; } - static const char* getNormalImposterFilePath(void* obj, const char* data) { return static_cast(obj)->getNormalImposterFilePath(); } + static const char* getNormalImposterFile(void* obj, const char* data) { return static_cast(obj)->getNormalImposterFile(); } }; DefineConsoleType(TypeShapeAssetId, String)