diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index 665497f46..d91f70241 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -55,16 +55,12 @@ #include "gfx/bitmap/imageUtils.h" StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL; +AssetPtr ShapeAsset::smNoShapeAssetFallbackAssetPtr = NULL; //----------------------------------------------------------------------------- IMPLEMENT_CONOBJECT(ShapeAsset); - -//----------------------------------------------------------------------------- -// REFACTOR -//----------------------------------------------------------------------------- - IMPLEMENT_STRUCT(AssetPtr, AssetPtrShapeAsset, , "") END_IMPLEMENT_STRUCT @@ -131,8 +127,50 @@ ConsoleSetType(TypeShapeAssetId) } //----------------------------------------------------------------------------- -// REFACTOR END -//----------------------------------------------------------------------------- +IMPLEMENT_STRUCT(AssetRef, AssetRefShapeAsset, , "") +END_IMPLEMENT_STRUCT + +ConsoleType(ShapeAssetRef, TypeShapeAssetRef, AssetRef, ASSET_ID_FIELD_PREFIX) + + +ConsoleGetType(TypeShapeAssetRef) +{ + AssetRef& ref = *((AssetRef*)dptr); + + if (ref.assetPtr.isNull()) + return ref.assetId; + else + return ref.assetPtr.getAssetId(); + +} + +ConsoleSetType(TypeShapeAssetRef) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + const char* pFieldValue = argv[0]; + + // Fetch asset pointer. + AssetRef* pAssetRef = (AssetRef*)(dptr); + + // Is the asset pointer the correct type? + if (pAssetRef == NULL) + { + Con::warnf("(TypeShapeAssetRef) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + *pAssetRef = pFieldValue; + + return; + } + + // Warn. + Con::warnf("(TypeShapeAssetRef) - Cannot set multiple args to a single asset."); +} const String ShapeAsset::mErrCodeStrings[] = { @@ -170,7 +208,7 @@ void ShapeAsset::consoleInit() Con::addVariable("$Core::NoShapeAssetFallback", TypeString, &smNoShapeAssetFallback, "The assetId of the shape to display when the requested shape asset is missing.\n" "@ingroup GFX\n"); - + smNoShapeAssetFallback = StringTable->insert(Con::getVariable("$Core::NoShapeAssetFallback")); } @@ -194,20 +232,6 @@ void ShapeAsset::initPersistFields() } -void ShapeAsset::setDataField(StringTableEntry slotName, StringTableEntry array, StringTableEntry value) -{ - Parent::setDataField(slotName, array, value); - - //Now, if it's a material slot of some fashion, set it up - StringTableEntry matSlotName = StringTable->insert("materialAsset"); - if (String(slotName).startsWith(matSlotName)) - { - StringTableEntry matId = StringTable->insert(value); - - mMaterialAssetIds.push_back(matId); - } -} - void ShapeAsset::initializeAsset() { // Call parent. @@ -239,6 +263,16 @@ void ShapeAsset::initializeAsset() String normalPath = String(mShapeFile) + "_imposter_normals.dds"; mNormalImposterFileName = StringTable->insert(normalPath.c_str()); } + + //Make sure our fallback is valid + if (smNoShapeAssetFallbackAssetPtr.isNull()) + { + smNoShapeAssetFallbackAssetPtr = smNoShapeAssetFallback; + if (smNoShapeAssetFallbackAssetPtr.isNull()) + Con::errorf("ShapeAsset::initializeAsset could not find fallback asset %s!", smNoShapeAssetFallback); + else + smNoShapeAssetFallbackAssetPtr->load(); + } } void ShapeAsset::setShapeFile(const char* pShapeFile) @@ -313,9 +347,9 @@ void ShapeAsset::setNormalImposterFile(const char* pImageFile) refreshAsset(); } -void ShapeAsset::_onResourceChanged(const Torque::Path &path) +void ShapeAsset::_onResourceChanged(const Torque::Path& path) { - if (path != Torque::Path(mShapeFile) ) + if (path != Torque::Path(mShapeFile)) return; refreshAsset(); @@ -325,117 +359,64 @@ U32 ShapeAsset::load() { if (mLoadedState == AssetErrCode::Ok) return mLoadedState; - mMaterialAssets.clear(); - mMaterialAssetIds.clear(); - - //First, load any material, animation, etc assets we may be referencing in our asset - // Find any asset dependencies. - AssetManager::typeAssetDependsOnHash::Iterator assetDependenciesItr = mpOwningAssetManager->getDependedOnAssets()->find(mpAssetDefinition->mAssetId); - - // Does the asset have any dependencies? - if (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end()) - { - // Iterate all dependencies. - while (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end() && assetDependenciesItr->key == mpAssetDefinition->mAssetId) - { - StringTableEntry assetType = mpOwningAssetManager->getAssetType(assetDependenciesItr->value); - - if (assetType == StringTable->insert("MaterialAsset")) - { - mMaterialAssetIds.push_front(assetDependenciesItr->value); - - //Force the asset to become initialized if it hasn't been already - AssetPtr matAsset = assetDependenciesItr->value; - - mMaterialAssets.push_front(matAsset); - } - else if (assetType == StringTable->insert("ShapeAnimationAsset")) - { - mAnimationAssetIds.push_back(assetDependenciesItr->value); - - //Force the asset to become initialized if it hasn't been already - AssetPtr animAsset = assetDependenciesItr->value; - - mAnimationAssets.push_back(animAsset); - } - - // Next dependency. - assetDependenciesItr++; - } - } - mShape = ResourceManager::get().load(mShapeFile); if (!mShape) { mLoadedState = BadFileReference; + return mLoadedState; //if it failed to load, bail out } + // Construct billboards if not done already if (GFXDevice::devicePresent()) mShape->setupBillboardDetails(mShapeFile, mDiffuseImposterFileName, mNormalImposterFileName); - //If they exist, grab our imposters here and bind them to our shapeAsset - - bool hasBlends = false; - - //Now that we've successfully loaded our shape and have any materials and animations loaded - //we need to set up the animations we're using on our shape - for (S32 i = mAnimationAssets.size()-1; i >= 0; --i) - { - String srcName = mAnimationAssets[i]->getAnimationName(); - String srcPath(mAnimationAssets[i]->getAnimationFilename()); - //SplitSequencePathAndName(srcPath, srcName); - - if (!mShape->addSequence(srcPath, mAnimationAssets[i]->getAssetId(), srcName, srcName, - mAnimationAssets[i]->getStartFrame(), mAnimationAssets[i]->getEndFrame(), mAnimationAssets[i]->getPadRotation(), mAnimationAssets[i]->getPadTransforms())) - { - mLoadedState = MissingAnimatons; - return mLoadedState; - } - if (mAnimationAssets[i]->isBlend()) - hasBlends = true; - } - - //if any of our animations are blends, set those up now - if (hasBlends) - { - for (U32 i=0; i < mAnimationAssets.size(); ++i) - { - if (mAnimationAssets[i]->isBlend() && mAnimationAssets[i]->getBlendAnimationName() != StringTable->EmptyString()) - { - //gotta do a bit of logic here. - //First, we need to make sure the anim asset we depend on for our blend is loaded - AssetPtr blendAnimAsset = mAnimationAssets[i]->getBlendAnimationName(); - - U32 assetStatus = ShapeAnimationAsset::getAssetErrCode(blendAnimAsset); - if (assetStatus != AssetBase::Ok) - { - Con::errorf("ShapeAsset::initializeAsset - Unable to acquire reference animation asset %s for asset %s to blend!", mAnimationAssets[i]->getBlendAnimationName(), mAnimationAssets[i]->getAssetName()); - { - mLoadedState = MissingAnimatons; - return mLoadedState; - } - } - - String refAnimName = blendAnimAsset->getAnimationName(); - if (!mShape->setSequenceBlend(mAnimationAssets[i]->getAnimationName(), true, blendAnimAsset->getAnimationName(), mAnimationAssets[i]->getBlendFrame())) - { - Con::errorf("ShapeAnimationAsset::initializeAsset - Unable to set animation clip %s for asset %s to blend!", mAnimationAssets[i]->getAnimationName(), mAnimationAssets[i]->getAssetName()); - { - mLoadedState = MissingAnimatons; - return mLoadedState; - } - } - } - } - } - mLoadedState = Ok; return mLoadedState; } +bool ShapeAsset::preloadMaterialList() +{ + if (!mShape) + return false; + + return mShape->preloadMaterialList(getShapeFile()); +} + +TSShape* ShapeAsset::getShape() +{ + AssetErrCode result = static_cast(load()); + + if (mShape) + { + return mShape; + } + else if (smNoShapeAssetFallbackAssetPtr.notNull()) + { + return smNoShapeAssetFallbackAssetPtr->getShape(); + } + + return NULL; +} + +Resource ShapeAsset::getShapeResource() +{ + AssetErrCode result = static_cast(load()); + + if (mShape) + { + return mShape; + } + else if (smNoShapeAssetFallbackAssetPtr.notNull()) + { + return smNoShapeAssetFallbackAssetPtr->getShapeResource(); + } + + return Resource(NULL); +} + //------------------------------------------------------------------------------ //Utility function to 'fill out' bindings and resources with a matching asset if one exists U32 ShapeAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr* shapeAsset) @@ -560,6 +541,44 @@ U32 ShapeAsset::getAssetById(StringTableEntry assetId, AssetPtr* sha return AssetErrCode::UsingFallback; } } + +StringTableEntry ShapeAsset::getMaterial(const S32& index) +{ + if (!mShape) + return StringTable->EmptyString(); + + if (index < 0 || index >= mShape->materialList->size()) + return StringTable->EmptyString(); + + return mShape->materialList->getMaterialName(index); +} + +U32 ShapeAsset::getMaterialCount() +{ + if (!mShape) + return 0; + + return mShape->materialList->size(); +} + +StringTableEntry ShapeAsset::getAnimation(const S32& index) +{ + if (!mShape) + return StringTable->EmptyString(); + + if (index < 0 || index >= mShape->sequences.size()) + return StringTable->EmptyString(); + + return mShape->getName(mShape->sequences[index].nameIndex); +} + +U32 ShapeAsset::getAnimationCount() +{ + if (!mShape) + return 0; + + return mShape->sequences.size(); +} //------------------------------------------------------------------------------ void ShapeAsset::copyTo(SimObject* object) @@ -589,10 +608,10 @@ void ShapeAsset::onTamlPreWrite(void) Parent::onTamlPreWrite(); // ensure paths are collapsed. - mShapeFile = collapseAssetFilePath(mShapeFile); - mConstructorFileName = collapseAssetFilePath(mConstructorFileName); - mDiffuseImposterFileName = collapseAssetFilePath(mDiffuseImposterFileName); - mNormalImposterFileName = collapseAssetFilePath(mNormalImposterFileName); + mShapeFile = collapseAssetFilePath(mShapeFile); + mConstructorFileName = collapseAssetFilePath(mConstructorFileName); + mDiffuseImposterFileName = collapseAssetFilePath(mDiffuseImposterFileName); + mNormalImposterFileName = collapseAssetFilePath(mNormalImposterFileName); } void ShapeAsset::onTamlPostWrite(void) @@ -601,42 +620,10 @@ void ShapeAsset::onTamlPostWrite(void) 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 = ""; - - // Determine if there is a sequence name at the end of the source string, and - // if so, split the filename from the sequence name - S32 split = srcPath.find(' ', 0, String::Right); - S32 split2 = srcPath.find('\t', 0, String::Right); - if ((split == String::NPos) || (split2 > split)) - split = split2; - if (split != String::NPos) - { - split2 = split + 1; - while ((srcPath[split2] != '\0') && dIsspace(srcPath[split2])) - split2++; - - // now 'split' is at the end of the path, and 'split2' is at the start of the sequence name - srcName = srcPath.substr(split2); - srcPath = srcPath.erase(split, srcPath.length() - split); - } -} - -ShapeAnimationAsset* ShapeAsset::getAnimation(S32 index) -{ - if (index < mAnimationAssets.size()) - { - return mAnimationAssets[index]; - } - - return NULL; + mShapeFile = expandAssetFilePath(mShapeFile); + mConstructorFileName = expandAssetFilePath(mConstructorFileName); + mDiffuseImposterFileName = expandAssetFilePath(mDiffuseImposterFileName); + mNormalImposterFileName = expandAssetFilePath(mNormalImposterFileName); } #ifdef TORQUE_TOOLS @@ -655,7 +642,7 @@ const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overri if (overrideMaterial.isNotEmpty()) { - Material *tMat = dynamic_cast(Sim::findObject(overrideMaterial)); + Material* tMat = dynamic_cast(Sim::findObject(overrideMaterial)); if (tMat) shape->reSkin(tMat->mMapTo, mShape->materialList->getMaterialName(0)); } @@ -702,7 +689,7 @@ const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overri dSprintf(returnBuffer, 128, "%s", dumpPath.c_str()); imposter->writeBitmap("png", dumpPath); - + delete imposter; delete imposterNrml; @@ -714,6 +701,13 @@ const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overri } #endif +DefineEngineMethod(ShapeAsset, getMaterial, const char*, (S32 index), (0), + "Gets the number of materials for this shape asset.\n" + "@return Material count.\n") +{ + return object->getMaterial(index); +} + DefineEngineMethod(ShapeAsset, getMaterialCount, S32, (), , "Gets the number of materials for this shape asset.\n" "@return Material count.\n") @@ -721,14 +715,7 @@ DefineEngineMethod(ShapeAsset, getMaterialCount, S32, (), , return object->getMaterialCount(); } -DefineEngineMethod(ShapeAsset, getAnimationCount, S32, (), , - "Gets the number of animations for this shape asset.\n" - "@return Animation count.\n") -{ - return object->getAnimationCount(); -} - -DefineEngineMethod(ShapeAsset, getAnimation, ShapeAnimationAsset*, (S32 index), (0), +DefineEngineMethod(ShapeAsset, getAnimation, const char*, (S32 index), (0), "Gets a particular shape animation asset for this shape.\n" "@param animation asset index.\n" "@return Shape Animation Asset.\n") @@ -736,6 +723,13 @@ DefineEngineMethod(ShapeAsset, getAnimation, ShapeAnimationAsset*, (S32 index), return object->getAnimation(index); } +DefineEngineMethod(ShapeAsset, getAnimationCount, S32, (), , + "Gets the number of animations for this shape asset.\n" + "@return Animation count.\n") +{ + return object->getAnimationCount(); +} + DefineEngineMethod(ShapeAsset, getShapePath, const char*, (), , "Gets the shape's file path\n" "@return The filename of the shape file") @@ -784,7 +778,7 @@ ConsoleDocClass(GuiInspectorTypeShapeAssetPtr, "@brief Inspector field type for Shapes\n\n" "Editor use only.\n\n" "@internal" - ); +); void GuiInspectorTypeShapeAssetPtr::consoleInit() { @@ -940,7 +934,7 @@ void GuiInspectorTypeShapeAssetPtr::updatePreviewImage() //if what we're working with isn't even a valid asset, don't present like we found a good one if (!AssetDatabase.isDeclaredAsset(previewImage)) { - mPreviewImage->_setBitmap(StringTable->EmptyString()); + mPreviewImage->setBitmap(StringTable->EmptyString()); return; } @@ -953,7 +947,7 @@ void GuiInspectorTypeShapeAssetPtr::updatePreviewImage() } if (mPreviewImage->getBitmapAsset().isNull()) - mPreviewImage->_setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); + mPreviewImage->setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); } void GuiInspectorTypeShapeAssetPtr::setPreviewImage(StringTableEntry assetId) @@ -961,7 +955,7 @@ void GuiInspectorTypeShapeAssetPtr::setPreviewImage(StringTableEntry assetId) //if what we're working with isn't even a valid asset, don't present like we found a good one if (!AssetDatabase.isDeclaredAsset(assetId)) { - mPreviewImage->_setBitmap(StringTable->EmptyString()); + mPreviewImage->setBitmap(StringTable->EmptyString()); return; } @@ -974,7 +968,7 @@ void GuiInspectorTypeShapeAssetPtr::setPreviewImage(StringTableEntry assetId) } if (mPreviewImage->getBitmapAsset().isNull()) - mPreviewImage->_setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); + mPreviewImage->setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); } IMPLEMENT_CONOBJECT(GuiInspectorTypeShapeAssetId); @@ -991,4 +985,204 @@ void GuiInspectorTypeShapeAssetId::consoleInit() ConsoleBaseType::getType(TypeShapeAssetId)->setInspectorFieldType("GuiInspectorTypeShapeAssetId"); } + +//----------------------------------------------------------------------------- +IMPLEMENT_CONOBJECT(GuiInspectorTypeShapeAssetRef); + +ConsoleDocClass(GuiInspectorTypeShapeAssetRef, + "@brief Inspector field type for Shapes\n\n" + "Editor use only.\n\n" + "@internal" +); + +void GuiInspectorTypeShapeAssetRef::consoleInit() +{ + Parent::consoleInit(); + + ConsoleBaseType::getType(TypeShapeAssetRef)->setInspectorFieldType("GuiInspectorTypeShapeAssetRef"); +} + +GuiControl* GuiInspectorTypeShapeAssetRef::constructEditControl() +{ + // Create base filename edit controls + GuiControl* retCtrl = Parent::constructEditControl(); + if (retCtrl == NULL) + return retCtrl; + + // Change filespec + char szBuffer[512]; + + const char* previewImage; + + if (mInspector->getInspectObject() != NULL) + { + StringBuilder varNameStr; + varNameStr.append(mCaption); + if (mFieldArrayIndex != NULL) + { + varNameStr.append("["); + varNameStr.append(mFieldArrayIndex); + varNameStr.append("]"); + } + + dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %s, \"%s\");", + mInspector->getIdString(), varNameStr.end().c_str()); + mBrowseButton->setField("Command", szBuffer); + + setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString()); + + previewImage = mInspector->getInspectObject()->getDataField(varNameStr.end().c_str(), NULL); + } + else + { + //if we don't have a target object, we'll be manipulating the desination value directly + dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %s, \"%s\");", + mInspector->getIdString(), mVariableName); + mBrowseButton->setField("Command", szBuffer); + + previewImage = Con::getVariable(mVariableName); + } + + mLabel = new GuiTextCtrl(); + mLabel->registerObject(); + mLabel->setControlProfile(mProfile); + mLabel->setText(mCaption); + addObject(mLabel); + + // + GuiTextEditCtrl* editTextCtrl = static_cast(retCtrl); + GuiControlProfile* toolEditProfile; + if (Sim::findObject("ToolsGuiTextEditProfile", toolEditProfile)) + editTextCtrl->setControlProfile(toolEditProfile); + + GuiControlProfile* toolDefaultProfile = NULL; + Sim::findObject("ToolsGuiDefaultProfile", toolDefaultProfile); + + // + mPreviewImage = new GuiBitmapCtrl(); + mPreviewImage->registerObject(); + + if (toolDefaultProfile) + mPreviewImage->setControlProfile(toolDefaultProfile); + + updatePreviewImage(); + + addObject(mPreviewImage); + + // + mPreviewBorderButton = new GuiBitmapButtonCtrl(); + mPreviewBorderButton->registerObject(); + + if (toolDefaultProfile) + mPreviewBorderButton->setControlProfile(toolDefaultProfile); + + mPreviewBorderButton->_setBitmap(StringTable->insert("ToolsModule:cubemapBtnBorder_n_image")); + + mPreviewBorderButton->setField("Command", szBuffer); //clicking the preview does the same thing as the edit button, for simplicity + addObject(mPreviewBorderButton); + + // + // Create "Open in Editor" button + mEditButton = new GuiBitmapButtonCtrl(); + + dSprintf(szBuffer, sizeof(szBuffer), "ShapeEditorPlugin.openShapeAssetId(%d.getText());", retCtrl->getId()); + mEditButton->setField("Command", szBuffer); + + mEditButton->setText("Edit"); + mEditButton->setSizing(horizResizeLeft, vertResizeAspectTop); + + mEditButton->setDataField(StringTable->insert("Profile"), NULL, "ToolsGuiButtonProfile"); + mEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile"); + mEditButton->setDataField(StringTable->insert("hovertime"), NULL, "1000"); + mEditButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this asset in the Shape Editor"); + + mEditButton->registerObject(); + addObject(mEditButton); + + // + mUseHeightOverride = true; + mHeightOverride = 72; + + return retCtrl; +} + +bool GuiInspectorTypeShapeAssetRef::updateRects() +{ + S32 rowSize = 18; + S32 dividerPos, dividerMargin; + mInspector->getDivider(dividerPos, dividerMargin); + Point2I fieldExtent = getExtent(); + Point2I fieldPos = getPosition(); + + mEditCtrlRect.set(0, 0, fieldExtent.x, fieldExtent.y); + mLabel->resize(Point2I(mProfile->mTextOffset.x, 0), Point2I(fieldExtent.x, rowSize)); + + RectI previewRect = RectI(Point2I(mProfile->mTextOffset.x, rowSize), Point2I(50, 50)); + mPreviewBorderButton->resize(previewRect.point, previewRect.extent); + mPreviewImage->resize(previewRect.point, previewRect.extent); + + S32 editPos = previewRect.point.x + previewRect.extent.x + 10; + mEdit->resize(Point2I(editPos, rowSize * 1.5), Point2I(fieldExtent.x - editPos - 5, rowSize)); + + mEditButton->resize(Point2I(fieldExtent.x - 105, previewRect.point.y + previewRect.extent.y - rowSize), Point2I(100, rowSize)); + + mBrowseButton->setHidden(true); + + return true; +} + +void GuiInspectorTypeShapeAssetRef::updateValue() +{ + Parent::updateValue(); + + updatePreviewImage(); +} + +void GuiInspectorTypeShapeAssetRef::updatePreviewImage() +{ + const char* previewImage; + if (mInspector->getInspectObject() != NULL) + previewImage = mInspector->getInspectObject()->getDataField(mCaption, NULL); + else + previewImage = Con::getVariable(mVariableName); + + //if what we're working with isn't even a valid asset, don't present like we found a good one + if (!AssetDatabase.isDeclaredAsset(previewImage)) + { + mPreviewImage->setBitmap(StringTable->EmptyString()); + return; + } + + String shpPreviewAssetId = String(previewImage) + "_PreviewImage"; + shpPreviewAssetId.replace(":", "_"); + shpPreviewAssetId = "ToolsModule:" + shpPreviewAssetId; + if (AssetDatabase.isDeclaredAsset(shpPreviewAssetId.c_str())) + { + mPreviewImage->setBitmap(StringTable->insert(shpPreviewAssetId.c_str())); + } + + if (mPreviewImage->getBitmapAsset().isNull()) + mPreviewImage->setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); +} + +void GuiInspectorTypeShapeAssetRef::setPreviewImage(StringTableEntry assetId) +{ + //if what we're working with isn't even a valid asset, don't present like we found a good one + if (!AssetDatabase.isDeclaredAsset(assetId)) + { + mPreviewImage->setBitmap(StringTable->EmptyString()); + return; + } + + String shpPreviewAssetId = String(assetId) + "_PreviewImage"; + shpPreviewAssetId.replace(":", "_"); + shpPreviewAssetId = "ToolsModule:" + shpPreviewAssetId; + if (AssetDatabase.isDeclaredAsset(shpPreviewAssetId.c_str())) + { + mPreviewImage->setBitmap(StringTable->insert(shpPreviewAssetId.c_str())); + } + + if (mPreviewImage->getBitmapAsset().isNull()) + mPreviewImage->setBitmap(StringTable->insert("ToolsModule:genericAssetIcon_image")); +} #endif diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 3da49e75b..c2345bf4e 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -77,9 +77,10 @@ public: }; static StringTableEntry smNoShapeAssetFallback; + static AssetPtr smNoShapeAssetFallbackAssetPtr; static const String mErrCodeStrings[U32(ShapeAssetErrCode::Extended) - U32(Parent::Extended) + 1]; - static U32 getAssetErrCode(ConcreteAssetPtr checkAsset) { if (checkAsset) return checkAsset->mLoadedState; else return 0; } + static U32 getAssetErrCode(const ConcreteAssetPtr& checkAsset) { if (checkAsset) return checkAsset->mLoadedState; else return 0; } static String getAssetErrstrn(U32 errCode) { @@ -94,14 +95,6 @@ private: 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: @@ -115,39 +108,17 @@ public: static void initPersistFields(); void copyTo(SimObject* object) override; - virtual void setDataField(StringTableEntry slotName, StringTableEntry array, StringTableEntry value); - /// Declare Console Object. DECLARE_CONOBJECT(ShapeAsset); U32 load() override; + bool preloadMaterialList(); - TSShape* getShape() { load(); return mShape; } - - Resource getShapeResource() { load(); return mShape; } - - void SplitSequencePathAndName(String& srcPath, String& srcName); + TSShape* getShape(); + Resource getShapeResource(); U32 getShapeFilenameHash() { return _StringTable::hashString(mShapeFile); } - Vector> getMaterialAssets() { return mMaterialAssets; } - - inline AssetPtr getMaterialAsset(U32 matId) - { - if (matId >= mMaterialAssets.size()) - return NULL; - else - return mMaterialAssets[matId]; - } - - void clearMaterialAssets() { mMaterialAssets.clear(); } - - void addMaterialAssets(AssetPtr matPtr) { mMaterialAssets.push_back(matPtr); } - - S32 getMaterialCount() { return mMaterialAssets.size(); } - S32 getAnimationCount() { return mAnimationAssets.size(); } - ShapeAnimationAsset* getAnimation(S32 index); - void _onResourceChanged(const Torque::Path& path); void setShapeFile(const char* pScriptFile); @@ -163,11 +134,18 @@ public: void setNormalImposterFile(const char* pImageFile); inline StringTableEntry getNormalImposterFile(void) const { return mNormalImposterFileName; }; + static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr* shapeAsset); static StringTableEntry getAssetIdByFilename(StringTableEntry fileName); static U32 getAssetById(StringTableEntry assetId, AssetPtr* shapeAsset); + StringTableEntry getMaterial(const S32& index); + U32 getMaterialCount(); + + StringTableEntry getAnimation(const S32& index); + U32 getAnimationCount(); + #ifdef TORQUE_TOOLS const char* generateCachedPreviewImage(S32 resolution, String overrideMaterial = ""); #endif @@ -201,6 +179,9 @@ DefineConsoleType(TypeShapeAssetId, String) DECLARE_STRUCT(AssetPtr) DefineConsoleType(TypeShapeAssetPtr, AssetPtr) +DECLARE_STRUCT(AssetRef) +DefineConsoleType(TypeShapeAssetRef, AssetRef) + #ifdef TORQUE_TOOLS //----------------------------------------------------------------------------- // TypeAssetId GuiInspectorField Class @@ -236,255 +217,29 @@ public: static void consoleInit(); }; +//----------------------------------------------------------------------------- +class GuiInspectorTypeShapeAssetRef : public GuiInspectorTypeFileName +{ + typedef GuiInspectorTypeFileName Parent; +public: + + GuiTextCtrl* mLabel; + GuiBitmapButtonCtrl* mPreviewBorderButton; + GuiBitmapCtrl* mPreviewImage; + GuiButtonCtrl* mEditButton; + + DECLARE_CONOBJECT(GuiInspectorTypeShapeAssetRef); + static void consoleInit(); + + GuiControl* constructEditControl() override; + bool updateRects() override; + + void updateValue() override; + + void updatePreviewImage(); + void setPreviewImage(StringTableEntry assetId); +}; + #endif -//----------------------------------------------------------------------------- -// 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 || !String::compare(_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(); } \ - TSShape* get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShape(); 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->getShapeFile() : ""; } - -#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 || !String::compare(_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(); } \ - TSShape* get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShape(); 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->getShapeFile() : ""; } - -#define INITPERSISTFIELD_SHAPEASSET_REFACTOR(name, consoleClass, 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.), AbstractClassRep::FIELD_HideInInspectors); - - -#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 || !String::compare(_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(); } \ - TSShape* get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShape(); 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]->getShapeFile() : ""; } - -#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 || !String::compare(_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(); } \ - TSShape* get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShape(); 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]->getShapeFile() : ""; } - -#define INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, 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 - -//----------------------------------------------------------------------------- -// REFACTOR END -//----------------------------------------------------------------------------- - #endif diff --git a/Engine/source/T3D/debris.cpp b/Engine/source/T3D/debris.cpp index 3933a1f13..1e71d69f6 100644 --- a/Engine/source/T3D/debris.cpp +++ b/Engine/source/T3D/debris.cpp @@ -116,7 +116,7 @@ DebrisData::DebrisData() terminalVelocity = 0.0f; ignoreWater = true; - mShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.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; - mShapeAsset = other.mShapeAsset; + shapeAssetRef = other.shapeAssetRef; textureName = other.textureName; explosionId = other.explosionId; // -- for pack/unpack of explosion ptr @@ -190,8 +190,8 @@ DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 } void DebrisData::onPerformSubstitutions() -{ - _setShape(_getShapeAssetId()); +{ + shapeAssetRef = shapeAssetRef.assetId; } bool DebrisData::onAdd() @@ -278,17 +278,21 @@ bool DebrisData::preload(bool server, String &errorStr) if( server ) return true; - if (getShape()) + if (!shapeAssetRef.isNull()) { - TSShapeInstance* pDummy = new TSShapeInstance(getShape(), !server); - delete pDummy; - if (!server && !getShape()->preloadMaterialList(getShapeFile()) && NetConnection::filesWereDownloaded()) + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + if (!server && !shapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) + return false; + } + else + { + errorStr = String::ToString("DebrisData(%s)::preload: Couldn't load shape \"%s\"", getName(), shapeAssetRef.assetId); return false; - } - else if (!mShapeAsset.isNull()) - { - errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", _getShapeAssetId()); - return false; + } } return true; @@ -305,7 +309,8 @@ 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_REFACTOR(Shape, DebrisData, "Shape to use for this debris object."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, DebrisData)) + .doc("Shape to use for this debris object."); endGroup("Shapes"); addGroup("Particle Effects"); @@ -390,7 +395,7 @@ void DebrisData::packData(BitStream* stream) stream->writeString( textureName ); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); for( S32 i=0; ireadSTString(); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); for( S32 i=0; ifriction; // Setup our bounding box - if( mDataBlock->getShape()) + mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); + + Resource shape; + if( mDataBlock->shapeAssetRef.notNull()) { - mObjBox = mDataBlock->getShape()->mBounds; - } - else - { - mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); + shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + mObjBox = shape->mBounds; } - if( mDataBlock->getShape()) + if(shape) { - mShape = new TSShapeInstance( mDataBlock->getShape(), true); + mShape = new TSShapeInstance(shape, true); } if( mPart ) diff --git a/Engine/source/T3D/debris.h b/Engine/source/T3D/debris.h index 9d9065d0b..8cfe49c3a 100644 --- a/Engine/source/T3D/debris.h +++ b/Engine/source/T3D/debris.h @@ -83,7 +83,7 @@ struct DebrisData : public GameBaseData, protected AssetPtrCallback F32 terminalVelocity; // max velocity magnitude bool ignoreWater; - DECLARE_SHAPEASSET_REFACTOR(DebrisData, Shape) + AssetRef shapeAssetRef; StringTableEntry textureName; diff --git a/Engine/source/T3D/examples/renderShapeExample.cpp b/Engine/source/T3D/examples/renderShapeExample.cpp index bbfc7ac30..63d72ef43 100644 --- a/Engine/source/T3D/examples/renderShapeExample.cpp +++ b/Engine/source/T3D/examples/renderShapeExample.cpp @@ -36,7 +36,7 @@ IMPLEMENT_CO_NETOBJECT_V1(RenderShapeExample); ConsoleDocClass( RenderShapeExample, - "@brief An example scene object which renders a DTS.\n\n" + "@brief An example scene object which renders a shape asset.\n\n" "This class implements a basic SceneObject that can exist in the world at a " "3D position and render itself. There are several valid ways to render an " "object in Torque. This class makes use of the 'TS' (three space) shape " @@ -74,7 +74,9 @@ void RenderShapeExample::initPersistFields() docsURL; Parent::initPersistFields(); addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, RenderShapeExample, "The path to the shape file.") + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, RenderShapeExample)) + .doc("The shape asset to render.") + .network(UpdateMask); endGroup( "Shapes" ); // SceneObject already handles exposing the transform @@ -83,10 +85,6 @@ void RenderShapeExample::initPersistFields() void RenderShapeExample::inspectPostApply() { Parent::inspectPostApply(); - - // Flag the network mask to send the updates - // to the client object - setMaskBits( UpdateMask ); } bool RenderShapeExample::onAdd() @@ -146,7 +144,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_REFACTOR(conn, Shape); + AssetDatabase.packUpdateAsset(conn, mask, stream, mShapeAssetRef.assetId); // Allow the server object a chance to handle a new shape createShape(); @@ -170,7 +168,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream) if ( stream->readFlag() ) // UpdateMask { - UNPACK_ASSET_REFACTOR(conn, Shape); + mShapeAssetRef = AssetDatabase.unpackUpdateAsset(conn, stream); if ( isProperlyAdded() ) createShape(); @@ -182,28 +180,35 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream) //----------------------------------------------------------------------------- void RenderShapeExample::createShape() { - if ( mShapeAsset.isNull() ) - return; - // Clean up our previous shape if ( mShapeInstance ) SAFE_DELETE( mShapeInstance ); + if (!mShapeAssetRef.hasAssetId()) //literally nothing to do here + return; + + Resource shape; + + if (mShapeAssetRef.assetPtr.notNull()) + shape = mShapeAssetRef.assetPtr->getShapeResource(); + else + shape = ShapeAsset::smNoShapeAssetFallbackAssetPtr->getShapeResource(); + // Attempt to preload the Materials for this shape if ( isClientObject() && - !getShape()->preloadMaterialList(getShapeFile()) && + !mShapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded() ) { return; } // Update the bounding box - mObjBox = getShape()->mBounds; + mObjBox = shape->mBounds; resetWorldBox(); setRenderTransform(mObjToWorld); // Create the TSShapeInstance - mShapeInstance = new TSShapeInstance(getShape(), isClientObject() ); + mShapeInstance = new TSShapeInstance(shape, isClientObject() ); } void RenderShapeExample::prepRenderImage( SceneRenderState *state ) diff --git a/Engine/source/T3D/examples/renderShapeExample.h b/Engine/source/T3D/examples/renderShapeExample.h index 8160044a6..7fbd98dc3 100644 --- a/Engine/source/T3D/examples/renderShapeExample.h +++ b/Engine/source/T3D/examples/renderShapeExample.h @@ -61,7 +61,7 @@ class RenderShapeExample : public SceneObject //-------------------------------------------------------------------------- // Rendering variables //-------------------------------------------------------------------------- - DECLARE_SHAPEASSET_REFACTOR(RenderShapeExample, Shape) + AssetRef mShapeAssetRef; // The actual shape instance TSShapeInstance* mShapeInstance; diff --git a/Engine/source/T3D/examples/shapeDatablockExample.cpp b/Engine/source/T3D/examples/shapeDatablockExample.cpp new file mode 100644 index 000000000..6d546c53d --- /dev/null +++ b/Engine/source/T3D/examples/shapeDatablockExample.cpp @@ -0,0 +1,320 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2026 Jeff Raab, LLC +// Portions Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/examples/shapeDatablockExample.h" + +#include "math/mathIO.h" +#include "sim/netConnection.h" +#include "scene/sceneRenderState.h" +#include "console/consoleTypes.h" +#include "core/resourceManager.h" +#include "core/stream/bitStream.h" +#include "gfx/gfxTransformSaver.h" +#include "renderInstance/renderPassManager.h" +#include "lighting/lightQuery.h" + +IMPLEMENT_CO_DATABLOCK_V1(ShapeDatablockExampleData); + +ShapeDatablockExampleData::ShapeDatablockExampleData() +{ + shapeAssetRef.assetPtr.registerRefreshNotify(this); +} + +ShapeDatablockExampleData::ShapeDatablockExampleData(const ShapeDatablockExampleData& other, bool temp_clone) : GameBaseData(other, temp_clone) +{ + shapeAssetRef = other.shapeAssetRef; +} + +ShapeDatablockExampleData::~ShapeDatablockExampleData() +{ +} + +void ShapeDatablockExampleData::initPersistFields() +{ + docsURL; + addGroup("Shapes"); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, ShapeDatablockExampleData)) + .doc("The shape asset to render."); + endGroup("Shapes"); + + Parent::initPersistFields(); +} + +bool ShapeDatablockExampleData::preload(bool server, String& errorStr) +{ + if (!shapeAssetRef.isNull()) + { + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + if (!server && !shapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) + return false; + } + else + { + errorStr = String::ToString("ShapeDatablockExampleData(%s)::preload: Couldn't load shape asset\"%s\"", getName(), shapeAssetRef.assetId); + return false; + } + } + + return true; +} + +void ShapeDatablockExampleData::packData(BitStream* stream) +{ + Parent::packData(stream); + + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); +} + +void ShapeDatablockExampleData::unpackData(BitStream* stream) +{ + Parent::unpackData(stream); + + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); +} + +IMPLEMENT_CO_NETOBJECT_V1(ShapeDatablockExample); + +ConsoleDocClass(ShapeDatablockExample, + "@brief An example scene object which renders a shape that utilizes a datablock.\n\n" + "This class implements a basic SceneObject that can exist in the world at a " + "3D position and render itself. There are several valid ways to render an " + "object in Torque. This class makes use of the 'TS' (three space) shape " + "system, while containing the shape data to be rendered in a datablock. " + "TS manages loading the various mesh formats supported by Torque as " + "well was rendering those meshes (including LOD and animation...though this " + "example doesn't include any animation over time).\n\n" + "See the C++ code for implementation details.\n\n" + "@ingroup Examples\n"); + +//----------------------------------------------------------------------------- +// Object setup and teardown +//----------------------------------------------------------------------------- +ShapeDatablockExample::ShapeDatablockExample() +{ + // Flag this object so that it will always + // be sent across the network to clients + mNetFlags.set(Ghostable | ScopeAlways); + + // Set it as a "static" object. + mTypeMask |= StaticObjectType | StaticShapeObjectType; + + mDataBlock = NULL; + + // Make sure to initialize our TSShapeInstance to NULL + mShapeInstance = NULL; +} + +ShapeDatablockExample::~ShapeDatablockExample() +{ + +} + +//----------------------------------------------------------------------------- +// Object Editing +//----------------------------------------------------------------------------- +void ShapeDatablockExample::initPersistFields() +{ + docsURL; + Parent::initPersistFields(); +} + + +bool ShapeDatablockExample::onAdd() +{ + if (!Parent::onAdd()) + return false; + + // Set up a 1x1x1 bounding box + mObjBox.set(Point3F(-0.5f, -0.5f, -0.5f), + Point3F(0.5f, 0.5f, 0.5f)); + + resetWorldBox(); + + // Add this object to the scene + addToScene(); + + if (mDataBlock && !onNewDataBlock(mDataBlock, false)) + return false; + + return true; +} + +bool ShapeDatablockExample::onNewDataBlock(GameBaseData* dptr, bool reload) +{ + // EDITOR FEATURE: Remove us from old datablock's reload signal and + // add us to the new one. + if (!reload) + { + if (mDataBlock) + mDataBlock->mReloadSignal.remove(this, &ShapeDatablockExample::_onDatablockModified); + if (dptr) + dptr->mReloadSignal.notify(this, &ShapeDatablockExample::_onDatablockModified); + } + + mDataBlock = dynamic_cast(dptr); + if (!mDataBlock) + return false; + + if (mShapeInstance) + SAFE_DELETE(mShapeInstance); + + if (mDataBlock->shapeAssetRef.isNull()) + return false; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + + mShapeInstance = new TSShapeInstance(shape); + +#ifdef TORQUE_AFX_ENABLED + // Don't set mask when new datablock is a temp-clone. + if (mDataBlock->isTempClone()) + return true; +#endif + + setMaskBits(DataBlockMask); + return true; +} + +void ShapeDatablockExample::_onDatablockModified() +{ + AssertFatal(mDataBlock, "ShapeDatablockExample::onDatablockModified - mDataBlock is NULL."); + onNewDataBlock(mDataBlock, true); +} + +void ShapeDatablockExample::onRemove() +{ + // Remove this object from the scene + removeFromScene(); + + // Remove our TSShapeInstance + if (mShapeInstance) + SAFE_DELETE(mShapeInstance); + + Parent::onRemove(); +} + +void ShapeDatablockExample::setTransform(const MatrixF& mat) +{ + // Let SceneObject handle all of the matrix manipulation + Parent::setTransform(mat); + + // Dirty our network mask so that the new transform gets + // transmitted to the client object + setMaskBits(TransformMask); +} + +U32 ShapeDatablockExample::packUpdate(NetConnection* conn, U32 mask, BitStream* stream) +{ + // Allow the Parent to get a crack at writing its info + U32 retMask = Parent::packUpdate(conn, mask, stream); + + // Write our transform information + if (stream->writeFlag(mask & TransformMask)) + { + mathWrite(*stream, getTransform()); + mathWrite(*stream, getScale()); + } + + // Write out any of the updated editable properties + if (stream->writeFlag(mask & UpdateMask)) + { + + } + + return retMask; +} + +void ShapeDatablockExample::unpackUpdate(NetConnection* conn, BitStream* stream) +{ + // Let the Parent read any info it sent + Parent::unpackUpdate(conn, stream); + + if (stream->readFlag()) // TransformMask + { + mathRead(*stream, &mObjToWorld); + mathRead(*stream, &mObjScale); + + setTransform(mObjToWorld); + } + + if (stream->readFlag()) // UpdateMask + { + + } +} + +void ShapeDatablockExample::prepRenderImage(SceneRenderState* state) +{ + // Make sure we have a TSShapeInstance + if (!mShapeInstance) + return; + + // Calculate the distance of this object from the camera + Point3F cameraOffset; + getRenderTransform().getColumn(3, &cameraOffset); + cameraOffset -= state->getDiffuseCameraPosition(); + F32 dist = cameraOffset.len(); + if (dist < 0.01f) + dist = 0.01f; + + // Set up the LOD for the shape + F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); + + mShapeInstance->setDetailFromDistance(state, dist * invScale); + + // Make sure we have a valid level of detail + if (mShapeInstance->getCurrentDetail() < 0) + return; + + // GFXTransformSaver is a handy helper class that restores + // the current GFX matrices to their original values when + // it goes out of scope at the end of the function + GFXTransformSaver saver; + + // Set up our TS render state + TSRenderState rdata; + rdata.setSceneState(state); + rdata.setFadeOverride(1.0f); + + // We might have some forward lit materials + // so pass down a query to gather lights. + LightQuery query; + query.init(getWorldSphere()); + rdata.setLightQuery(&query); + + // Set the world matrix to the objects render transform + MatrixF mat = getRenderTransform(); + mat.scale(mObjScale); + GFX->setWorldMatrix(mat); + + // Animate the the shape + mShapeInstance->animate(); + + // Allow the shape to submit the RenderInst(s) for itself + mShapeInstance->render(rdata); +} + diff --git a/Engine/source/T3D/examples/shapeDatablockExample.h b/Engine/source/T3D/examples/shapeDatablockExample.h new file mode 100644 index 000000000..fa33bc048 --- /dev/null +++ b/Engine/source/T3D/examples/shapeDatablockExample.h @@ -0,0 +1,103 @@ +#pragma once + +#ifndef _SHAPEDATABLOCKEXAMPLE_H_ +#define _SHAPEDATABLOCKEXAMPLE_H_ + +#ifndef _GAMEBASE_H_ +#include "T3D/gameBase/gameBase.h" +#endif +#ifndef _TSSHAPEINSTANCE_H_ +#include "ts/tsShapeInstance.h" +#endif + +#include "T3D/assets/ShapeAsset.h" + +struct ShapeDatablockExampleData : public GameBaseData, protected AssetPtrCallback +{ +private: + typedef GameBaseData Parent; + +public: + AssetRef shapeAssetRef; + + // The derived class should provide the following: + DECLARE_CONOBJECT(ShapeDatablockExampleData); + DECLARE_CATEGORY("Datablock"); + ShapeDatablockExampleData(); + ShapeDatablockExampleData(const ShapeDatablockExampleData&, bool = false); + ~ShapeDatablockExampleData(); + + static void initPersistFields(); + bool preload(bool server, String& errorStr) override; + void packData(BitStream* stream) override; + void unpackData(BitStream* stream) override; + +protected: + void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override + { + reloadOnLocalClient(); + } +}; + +class ShapeDatablockExample : public GameBase +{ + typedef GameBase Parent; + + ShapeDatablockExampleData* mDataBlock; + + // Networking masks + // We need to implement a mask specifically to handle + // updating our transform from the server object to its + // client-side "ghost". We also need to implement a + // maks for handling editor updates to our properties + // (like material). + enum MaskBits + { + TransformMask = Parent::NextFreeMask << 0, + UpdateMask = Parent::NextFreeMask << 1, + NextFreeMask = Parent::NextFreeMask << 2 + }; + + // The actual shape instance + TSShapeInstance* mShapeInstance; + +public: + ShapeDatablockExample(); + virtual ~ShapeDatablockExample(); + + // Declare this object as a ConsoleObject so that we can + // instantiate it into the world and network it + DECLARE_CONOBJECT(ShapeDatablockExample); + + //-------------------------------------------------------------------------- + // Object Editing + // Since there is always a server and a client object in Torque and we + // actually edit the server object we need to implement some basic + // networking functions + //-------------------------------------------------------------------------- + // Set up any fields that we want to be editable (like position) + static void initPersistFields(); + + // Handle when we are added to the scene and removed from the scene + bool onAdd() override; + void onRemove() override; + + bool onNewDataBlock(GameBaseData* dptr, bool reload) override; + + // Override this so that we can dirty the network flag when it is called + void setTransform(const MatrixF & mat) override; + + // This function handles sending the relevant data from the server + // object to the client object + U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream) override; + // This function handles receiving relevant data from the server + // object and applying it to the client object + void unpackUpdate(NetConnection* conn, BitStream* stream) override; + + // This is the function that allows this object to submit itself for rendering + void prepRenderImage(SceneRenderState* state) override; + + void _onDatablockModified(); +}; + +#endif diff --git a/Engine/source/T3D/fx/explosion.cpp b/Engine/source/T3D/fx/explosion.cpp index da374984c..ae7c19532 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; - mExplosionShapeAsset.registerRefreshNotify(this); + explosionShapeAssetRef.assetPtr.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; - mExplosionShapeAsset = other.mExplosionShapeAsset; + explosionShapeAssetRef = other.explosionShapeAssetRef; 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,8 +360,6 @@ ExplosionData::~ExplosionData() if (!isTempClone()) return; - mExplosionShapeAsset.unregisterRefreshNotify(); - // particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves #ifdef TRACK_EXPLOSION_DATA_CLONES @@ -395,8 +393,9 @@ void ExplosionData::initPersistFields() { docsURL; addGroup("Shapes"); - 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."); + ADD_FIELD("explosionShapeAsset", TypeShapeAssetRef, Offset(explosionShapeAssetRef, ExplosionData)) + .doc("@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"); addGroup("Sounds"); @@ -673,7 +672,7 @@ void ExplosionData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET_REFACTOR(ExplosionShape); + AssetDatabase.packDataAsset(stream, explosionShapeAssetRef.assetId); //PACKDATA_SOUNDASSET(Sound); PACKDATA_ASSET(Sound); @@ -778,7 +777,7 @@ void ExplosionData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(ExplosionShape); + explosionShapeAssetRef = AssetDatabase.unpackDataAsset(stream); UNPACKDATA_ASSET(Sound); @@ -913,23 +912,21 @@ bool ExplosionData::preload(bool server, String &errorStr) } } - if (getExplosionShape()) { - - // Resolve animations - explosionAnimation = getExplosionShape()->findSequence("ambient"); - - // Preload textures with a dummy instance... - TSShapeInstance* pDummy = new TSShapeInstance(getExplosionShape(), !server); - delete pDummy; - - } - else if (mExplosionShapeAsset.notNull()) + if (!explosionShapeAssetRef.isNull()) { - errorStr = String::ToString("ExplosionData::preload: Couldn't load shape \"%s\"", _getExplosionShapeAssetId()); - return false; - } - else { - explosionAnimation = -1; + Resource shape = explosionShapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + if (!server && !explosionShapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) + return false; + } + else + { + errorStr = String::ToString("ExplosionData(%s)::preload: Couldn't load shape \"%s\"", getName(), explosionShapeAssetRef.assetId); + return false; + } } return true; @@ -1417,8 +1414,12 @@ bool Explosion::explode() launchDebris( mInitialNormal ); spawnSubExplosions(); - if (bool(mDataBlock->getExplosionShape()) && mDataBlock->explosionAnimation != -1) { - mExplosionInstance = new TSShapeInstance(mDataBlock->getExplosionShape(), true); + Resource eShape; + if (mDataBlock->explosionShapeAssetRef.notNull()) + eShape = mDataBlock->explosionShapeAssetRef.assetPtr->getShapeResource(); + + if (bool(eShape) && mDataBlock->explosionAnimation != -1) { + mExplosionInstance = new TSShapeInstance(eShape, true); mExplosionThread = mExplosionInstance->addThread(); mExplosionInstance->setSequence(mExplosionThread, mDataBlock->explosionAnimation, 0); @@ -1428,7 +1429,7 @@ bool Explosion::explode() mEndingMS = U32(mExplosionInstance->getScaledDuration(mExplosionThread) * 1000.0f); mObjScale.convolve(mDataBlock->explosionScale); - mObjBox = mDataBlock->getExplosionShape()->mBounds; + mObjBox = eShape->mBounds; resetWorldBox(); } diff --git a/Engine/source/T3D/fx/explosion.h b/Engine/source/T3D/fx/explosion.h index c00483625..f62b1be0e 100644 --- a/Engine/source/T3D/fx/explosion.h +++ b/Engine/source/T3D/fx/explosion.h @@ -79,7 +79,7 @@ class ExplosionData : public GameBaseData, protected AssetPtrCallback { Point3F explosionScale; F32 playSpeed; - DECLARE_SHAPEASSET_REFACTOR(ExplosionData, ExplosionShape) + AssetRef explosionShapeAssetRef; S32 explosionAnimation; diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index a96c31917..03ad85c6f 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -513,9 +513,6 @@ GroundCover::GroundCover() mLayerAsset[i] = NULL; mLayerFile[i] = StringTable->EmptyString(); - mShapeAsset[i] = NULL; - mShapeFile[i] = StringTable->EmptyString(); - mInvertLayer[i] = NULL; mMinClumpCount[i] = 1; @@ -526,7 +523,7 @@ GroundCover::GroundCover() mBillboardRects[i].point.set( 0.0f, 0.0f ); mBillboardRects[i].extent.set( 1.0f, 1.0f ); - mShapeAsset[i].registerRefreshNotify(this); + mShapeAssetRef[i].assetPtr.registerRefreshNotify(this); mShapeInstances[i] = NULL; @@ -568,7 +565,10 @@ void GroundCover::initPersistFields() addField( "billboardUVs", TypeRectUV, Offset( mBillboardRects, GroundCover ), MAX_COVERTYPES, "Subset material UV coordinates for this cover billboard." ); - INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(Shape, MAX_COVERTYPES, GroundCover, "The cover shape. [Optional]"); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, GroundCover)) + .elements(MAX_COVERTYPES) + .doc("The cover shape. [Optional]") + .network(-1); INITPERSISTFIELD_TERRAINMATERIALASSET_ARRAY(Layer, MAX_COVERTYPES, GroundCover, "Terrain material assetId to limit coverage to, or blank to not limit."); @@ -773,10 +773,11 @@ 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 ); + + AssetDatabase.packUpdateAsset(connection, mask, stream, mShapeAssetRef[i].assetId); } PACK_ASSET_ARRAY_REFACTOR(connection, Layer, MAX_COVERTYPES) - PACK_ASSET_ARRAY_REFACTOR(connection, Shape, MAX_COVERTYPES) stream->writeFlag( mDebugRenderCells ); stream->writeFlag( mDebugNoBillboards ); @@ -844,12 +845,12 @@ 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 ); + + mShapeAssetRef[i] = AssetDatabase.unpackUpdateAsset(connection, stream); } UNPACK_ASSET_ARRAY_REFACTOR(connection, Layer, MAX_COVERTYPES) - UNPACK_ASSET_ARRAY_REFACTOR(connection, Shape, MAX_COVERTYPES) - mDebugRenderCells = stream->readFlag(); mDebugNoBillboards = stream->readFlag(); mDebugNoShapes = stream->readFlag(); @@ -895,17 +896,21 @@ void GroundCover::_initShapes() for ( S32 i=0; i < MAX_COVERTYPES; i++ ) { - if ( mShapeAsset[i].isNull() || getShape(i) == NULL) + if ( mShapeAssetRef[i].isNull()) continue; - if ( isClientObject() && !getShape(i)->preloadMaterialList(getShapeFile(i)) && NetConnection::filesWereDownloaded() ) + Resource shape = mShapeAssetRef[i].assetPtr->getShapeResource(); + if (!shape) + continue; + + if ( isClientObject() && !mShapeAssetRef[i].assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded() ) { - Con::warnf( "GroundCover::_initShapes() material preload failed for shape: %s", _getShapeAssetId(i)); + Con::warnf( "GroundCover::_initShapes() material preload failed for shape: %s", mShapeAssetRef[i].assetId); continue; } // Create the shape instance. - mShapeInstances[i] = new TSShapeInstance(getShape(i), isClientObject() ); + mShapeInstances[i] = new TSShapeInstance(shape, isClientObject() ); } } diff --git a/Engine/source/T3D/fx/groundCover.h b/Engine/source/T3D/fx/groundCover.h index e98a329cb..d7d0ab9cf 100644 --- a/Engine/source/T3D/fx/groundCover.h +++ b/Engine/source/T3D/fx/groundCover.h @@ -345,7 +345,7 @@ protected: RectF mBillboardRects[MAX_COVERTYPES]; /// The cover shape filenames. - DECLARE_SHAPEASSET_ARRAY_NET_REFACTOR(GroundCover, Shape, MAX_COVERTYPES, -1) + AssetRef mShapeAssetRef[MAX_COVERTYPES]; /// The cover shape instances. TSShapeInstance* mShapeInstances[MAX_COVERTYPES]; diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index b9d9e874d..4028aa2b6 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -850,9 +850,6 @@ ConsoleSetType(TypeParticleList) const char* values = argv[0]; numUnits = StringUnit::getUnitCount(values, " "); - if (numUnits > 1) - bool dafgdf = true; - for (U32 i = 0; i < numUnits; i++) { const char* value = StringUnit::getUnit(values, i, " "); @@ -877,7 +874,6 @@ ConsoleSetType(TypeParticleList) Con::printf("TypeParticleList vec results: %s", testVec[x]); } } - bool test = false; } #ifdef TORQUE_TOOLS diff --git a/Engine/source/T3D/guiMaterialPreview.cpp b/Engine/source/T3D/guiMaterialPreview.cpp index 4efda009d..d39c0d4d1 100644 --- a/Engine/source/T3D/guiMaterialPreview.cpp +++ b/Engine/source/T3D/guiMaterialPreview.cpp @@ -259,23 +259,30 @@ void GuiMaterialPreview::onMiddleMouseDragged(const GuiEvent &event) } // This is used to set the model we want to view in the control object. -void GuiMaterialPreview::setObjectModel(StringTableEntry modelName) +void GuiMaterialPreview::setObjectShape(StringTableEntry assetId) { - deleteModel(); + deleteShape(); - _setModel(modelName); + mShapeAssetRef = assetId; - if (!getModel()) + if (mShapeAssetRef.isNull()) { - Con::warnf("GuiMaterialPreview::setObjectModel - Failed to load model '%s'", modelName); + Con::warnf("GuiMaterialPreview::setObjectShape - Invalid assetId specified."); return; } - mModelInstance = new TSShapeInstance(getModel(), true); + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + { + Con::warnf("GuiMaterialPreview::setObjectModel - Failed to load shape '%s'", assetId); + return; + } + + mModelInstance = new TSShapeInstance(shape, true); mModelInstance->resetMaterialList(); mModelInstance->cloneMaterialList(); - AssertFatal(mModelInstance, avar("GuiMaterialPreview: Failed to load model %s. Please check your model name and load a valid model.", modelName)); + AssertFatal(mModelInstance, avar("GuiMaterialPreview: Failed to load model %s. Please check your model name and load a valid model.", assetId)); // Initialize camera values: mOrbitPos = mModelInstance->getShape()->center; @@ -284,7 +291,7 @@ void GuiMaterialPreview::setObjectModel(StringTableEntry modelName) lastRenderTime = Platform::getVirtualMilliseconds(); } -void GuiMaterialPreview::deleteModel() +void GuiMaterialPreview::deleteShape() { SAFE_DELETE(mModelInstance); runThread = 0; @@ -499,17 +506,32 @@ ConsoleDocClass( GuiMaterialPreview, ); // Set the model. -DefineEngineMethod(GuiMaterialPreview, setModel, void, ( const char* shapeName ),, - "Sets the model to be displayed in this control\n\n" - "@param shapeName Name of the model to display.\n") +DefineEngineMethod(GuiMaterialPreview, setModel, void, ( const char* assetId ),, + "Sets the shape to be displayed in this control\n\n" + "@param assetId Id of the shapeAsset to display.\n" + "@Deprecated\n\n") { - object->setObjectModel(StringTable->insert(shapeName)); + object->setObjectShape(StringTable->insert(assetId)); +} + +DefineEngineMethod(GuiMaterialPreview, setShape, void, (const char* assetId), , + "Sets the shape to be displayed in this control\n\n" + "@param assetId Id of the shapeAsset to display.\n") +{ + object->setObjectShape(StringTable->insert(assetId)); } DefineEngineMethod(GuiMaterialPreview, deleteModel, void, (),, + "Deletes the preview model.\n" + "@Deprecated\n\n") +{ + object->deleteShape(); +} + +DefineEngineMethod(GuiMaterialPreview, deleteShape, void, (), , "Deletes the preview model.\n") { - object->deleteModel(); + object->deleteShape(); } // Set orbit distance around the model. diff --git a/Engine/source/T3D/guiMaterialPreview.h b/Engine/source/T3D/guiMaterialPreview.h index 7c5d2ce09..acadf44dc 100644 --- a/Engine/source/T3D/guiMaterialPreview.h +++ b/Engine/source/T3D/guiMaterialPreview.h @@ -52,8 +52,8 @@ protected: MouseState mMouseState; - DECLARE_SHAPEASSET_REFACTOR(GuiMaterialPreview, Model) - DECLARE_SHAPEASSET_REFACTOR(GuiMaterialPreview, MountedModel) + AssetRef mShapeAssetRef; + AssetRef mMountedShapeAssetRef; TSShapeInstance* mModelInstance; TSShapeInstance* mMountedModelInstance; @@ -110,8 +110,8 @@ public: // For changing the ambient light color. void setAmbientLightColor( F32 r, F32 g, F32 b ); - void setObjectModel(const char * modelName); - void deleteModel(); + void setObjectShape(const char * assetId); + void deleteShape(); void resetViewport(); void setOrbitDistance(F32 distance); diff --git a/Engine/source/T3D/guiObjectView.cpp b/Engine/source/T3D/guiObjectView.cpp index f6699c037..c70c22870 100644 --- a/Engine/source/T3D/guiObjectView.cpp +++ b/Engine/source/T3D/guiObjectView.cpp @@ -134,11 +134,16 @@ GuiObjectView::~GuiObjectView() void GuiObjectView::initPersistFields() { docsURL; - addGroup( "Model" ); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Model, GuiObjectView, "The source shape asset."); + addGroup( "Shape" ); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, GuiObjectView)) + .doc("The source shape asset."); + ADD_FIELD("modelAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, GuiObjectView)) + .doc("The source shape asset.") + .withFlags(AbstractClassRep::FieldFlags::FIELD_HideInInspectors | AbstractClassRep::FieldFlags::FIELD_DontWriteToFile); + addField( "skin", TypeRealString, Offset( mSkinName, GuiObjectView ), "The skin to use on the object model." ); - endGroup( "Model" ); + endGroup( "Shape" ); addGroup( "Animation" ); @@ -147,8 +152,12 @@ void GuiObjectView::initPersistFields() endGroup( "Animation" ); - addGroup( "Mounting" ); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(MountedModel, GuiObjectView, "The mounted shape asset."); + addGroup( "Mounting" ); + ADD_FIELD("mountedShapeAsset", TypeShapeAssetRef, Offset(mMountedShapeAssetRef, GuiObjectView)) + .doc("The mounted shape asset."); + ADD_FIELD("mountedModelAsset", TypeShapeAssetRef, Offset(mMountedShapeAssetRef, GuiObjectView)) + .doc("The source shape asset.") + .withFlags(AbstractClassRep::FieldFlags::FIELD_HideInInspectors | AbstractClassRep::FieldFlags::FIELD_DontWriteToFile); addField( "mountedSkin", TypeRealString, Offset( mMountSkinName, GuiObjectView ), "Skin name used on mounted shape file." ); addField( "mountedNode", TypeRealString, Offset( mMountNodeName, GuiObjectView ), @@ -329,27 +338,34 @@ void GuiObjectView::setObjectAnimation( const String& sequenceName ) //------------------------------------------------------------------------------ -bool GuiObjectView::setObjectModel( const String& modelName ) +bool GuiObjectView::setObjectShape( const String& assetId ) { mRunThread = 0; // Load the shape if its not the one already set. - if (modelName.c_str() != _getModelAssetId()) - _setModel(modelName.c_str()); + if (assetId.c_str() != mShapeAssetRef.assetId) + mShapeAssetRef = assetId.c_str(); else return true; - if( !getModel()) + if (mShapeAssetRef.isNull()) { - Con::warnf( "GuiObjectView::setObjectModel - Failed to load model '%s'", modelName.c_str() ); + Con::warnf( "GuiObjectView::setObjectShape(%s) - Failed to load shape assetId '%s'", getName(), assetId.c_str() ); return false; } - if (!getModel()->preloadMaterialList(getModelFile())) return false; + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if( !shape) + { + Con::warnf( "GuiObjectView::setObjectShape(%s) - Failed to load shape '%s'", getName(), assetId.c_str()); + return false; + } + + if (!mShapeAssetRef.assetPtr->preloadMaterialList()) return false; // Instantiate it. - mModelInstance = new TSShapeInstance(getModel(), true ); + mModelInstance = new TSShapeInstance(shape, true ); mModelInstance->resetMaterialList(); mModelInstance->cloneMaterialList(); @@ -357,12 +373,12 @@ bool GuiObjectView::setObjectModel( const String& modelName ) mModelInstance->reSkin( mSkinName ); TSMaterialList* pMatList = mModelInstance->getMaterialList(); - pMatList->setTextureLookupPath(mModelAsset->getShapeFile()); + pMatList->setTextureLookupPath(mShapeAssetRef.assetPtr->getShapeFile()); mModelInstance->initMaterialList(); // Initialize camera values. - mOrbitPos = getModel()->center; - mMinOrbitDist = getModel()->mRadius; + mOrbitPos = shape->center; + mMinOrbitDist = shape->mRadius; // Initialize animation. @@ -384,23 +400,30 @@ void GuiObjectView::setSkin( const String& name ) //------------------------------------------------------------------------------ -bool GuiObjectView::setMountedObject( const String& modelName ) +bool GuiObjectView::setMountedShape( const String& assetId ) { // Load the model if it is not already the asset then set it.. - if (modelName.c_str() != _getMountedModelAssetId()) - _setMountedModel(modelName.c_str()); + if (assetId.c_str() != mMountedShapeAssetRef.assetId) + mMountedShapeAssetRef = assetId.c_str(); else return true; - if (!getMountedModel()) + if (mMountedShapeAssetRef.isNull()) { - Con::warnf("GuiObjectView::setMountedObject - Failed to load model '%s'", modelName.c_str()); + Con::warnf("GuiObjectView::setMountedShape(%s) - Failed to load shape assetId '%s'", getName(), assetId.c_str()); return false; } - if (!getMountedModel()->preloadMaterialList(getMountedModelFile())) return false; + Resource shape = mMountedShapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + { + Con::warnf("GuiObjectView::setMountedShape(%s) - Failed to load model '%s'", getName(), assetId.c_str()); + return false; + } - mMountedModelInstance = new TSShapeInstance(getMountedModel(), true); + if (!mMountedShapeAssetRef.assetPtr->preloadMaterialList()) return false; + + mMountedModelInstance = new TSShapeInstance(shape, true); mMountedModelInstance->resetMaterialList(); mMountedModelInstance->cloneMaterialList(); @@ -628,22 +651,27 @@ void GuiObjectView::setLightDirection( const Point3F& direction ) void GuiObjectView::_initAnimation() { - AssertFatal(getModel(), "GuiObjectView::_initAnimation - No model loaded!" ); + AssertFatal(mModelInstance, "GuiObjectView::_initAnimation - No model loaded!" ); + + if (!mModelInstance) + return; if( mAnimationSeqName.isEmpty() && mAnimationSeq == -1 ) return; + + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); // Look up sequence by name. if( !mAnimationSeqName.isEmpty() ) { - mAnimationSeq = getModel()->findSequence( mAnimationSeqName ); + mAnimationSeq = shape->findSequence( mAnimationSeqName ); if( mAnimationSeq == -1 ) { Con::errorf( "GuiObjectView::_initAnimation - Cannot find animation sequence '%s' on '%s'", mAnimationSeqName.c_str(), - _getModelAssetId() + mShapeAssetRef.assetId ); return; @@ -654,11 +682,11 @@ void GuiObjectView::_initAnimation() if( mAnimationSeq != -1 ) { - if( mAnimationSeq >= getModel()->sequences.size() ) + if( mAnimationSeq >= shape->sequences.size() ) { Con::errorf( "GuiObjectView::_initAnimation - Sequence '%i' out of range for model '%s'", mAnimationSeq, - _getModelAssetId() + mShapeAssetRef.assetId ); mAnimationSeq = -1; @@ -682,6 +710,8 @@ void GuiObjectView::_initMount() if( !mModelInstance) return; + + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); mMountTransform.identity(); @@ -689,12 +719,12 @@ void GuiObjectView::_initMount() if( !mMountNodeName.isEmpty() ) { - mMountNode = getModel()->findNode( mMountNodeName ); + mMountNode = shape->findNode( mMountNodeName ); if( mMountNode == -1 ) { Con::errorf( "GuiObjectView::_initMount - No node '%s' on '%s'", mMountNodeName.c_str(), - _getModelAssetId() + mShapeAssetRef.assetId ); return; @@ -703,24 +733,28 @@ void GuiObjectView::_initMount() // Make sure mount node is valid. - if( mMountNode != -1 && mMountNode >= getModel()->nodes.size() ) + if( mMountNode != -1 && mMountNode >= shape->nodes.size() ) { Con::errorf( "GuiObjectView::_initMount - Mount node index '%i' out of range for '%s'", mMountNode, - _getModelAssetId() + mShapeAssetRef.assetId ); mMountNode = -1; return; } + + Resource mountShape; + if (mMountedShapeAssetRef.notNull()) + mountShape = mMountedShapeAssetRef.assetPtr->getShapeResource(); // Look up node on the mounted model from // which to mount to the primary model's node. - if (!getMountedModel()) return; - S32 mountPoint = getMountedModel()->findNode( "mountPoint" ); + if (!mountShape) return; + S32 mountPoint = mountShape->findNode( "mountPoint" ); if( mountPoint != -1 ) { - getMountedModel()->getNodeWorldTransform(mountPoint, &mMountTransform), + mountShape->getNodeWorldTransform(mountPoint, &mMountTransform), mMountTransform.inverse(); } } @@ -738,26 +772,28 @@ DefineEngineMethod( GuiObjectView, getModel, const char*, (),, "// Request the displayed model name from the GuiObjectView object.\n" "%modelName = %thisGuiObjectView.getModel();\n" "@endtsexample\n\n" - "@return Name of the displayed model.\n\n" - "@see GuiControl") + "@return Id of the displayed shape.\n\n" + "@see GuiControl\n" + "@Deprecated\n\n") { - return Con::getReturnBuffer( object->_getModelAssetId() ); + return Con::getReturnBuffer( object->getObjectShapeId() ); } //----------------------------------------------------------------------------- -DefineEngineMethod( GuiObjectView, setModel, bool, (const char* shapeName),, +DefineEngineMethod( GuiObjectView, setModel, bool, (const char* assetId),, "@brief Sets the model to be displayed in this control.\n\n" - "@param shapeName Name of the model to display.\n" + "@param shapassetIdeName Name of the shapeAsset to display.\n" "@tsexample\n" - "// Define the model we want to display\n" - "%shapeName = \"gideon.dts\";\n\n" + "// Define the shapeAsset we want to display\n" + "%assetId = \"MyModule:MyShapeAsset\";\n\n" "// Tell the GuiObjectView object to display the defined model\n" - "%thisGuiObjectView.setModel(%shapeName);\n" + "%thisGuiObjectView.setModel(%assetId);\n" "@endtsexample\n\n" - "@see GuiControl") + "@see GuiControl\n" + "@Deprecated\n\n") { - return object->setObjectModel( shapeName ); + return object->setObjectShape(assetId); } //----------------------------------------------------------------------------- @@ -769,25 +805,86 @@ DefineEngineMethod( GuiObjectView, getMountedModel, const char*, (),, "%mountedModelName = %thisGuiObjectView.getMountedModel();\n" "@endtsexample\n\n" "@return Name of the mounted model.\n\n" - "@see GuiControl") + "@see GuiControl\n" + "@Deprecated\n\n") { - return Con::getReturnBuffer( object->_getMountedModelAssetId() ); + return Con::getReturnBuffer( object->getMountedShapeId() ); } //----------------------------------------------------------------------------- -DefineEngineMethod( GuiObjectView, setMountedModel, void, (const char* shapeName),, +DefineEngineMethod( GuiObjectView, setMountedModel, void, (const char* assetId),, "@brief Sets the model to be mounted on the primary model.\n\n" - "@param shapeName Name of the model to mount.\n" + "@param assetId Name of the shapeAsset to mount.\n" "@tsexample\n" "// Define the model name to mount\n" - "%modelToMount = \"GideonGlasses.dts\";\n\n" + "%shapeToMount = \"MyModule:MyMountedShapeAsset\";\n\n" "// Inform the GuiObjectView object to mount the defined model to the existing model in the control\n" - "%thisGuiObjectView.setMountedModel(%modelToMount);\n" + "%thisGuiObjectView.setMountedModel(%shapeToMount);\n" + "@endtsexample\n\n" + "@see GuiControl\n" + "@Deprecated\n\n") +{ + object->setMountedShape(assetId); +} + +//----------------------------------------------------------------------------- +DefineEngineMethod(GuiObjectView, getShape, const char*, (), , + "@brief Return the model displayed in this view.\n\n" + "@tsexample\n" + "// Request the displayed model name from the GuiObjectView object.\n" + "%modelName = %thisGuiObjectView.getModel();\n" + "@endtsexample\n\n" + "@return Id of the displayed shape.\n\n" + "@see GuiControl") +{ + return Con::getReturnBuffer(object->getObjectShapeId()); +} + +//----------------------------------------------------------------------------- + +DefineEngineMethod(GuiObjectView, setShape, bool, (const char* assetId), , + "@brief Sets the shape to be displayed in this control.\n\n" + "@param shapassetIdeName Name of the shapeAsset to display.\n" + "@tsexample\n" + "// Define the shapeAsset we want to display\n" + "%assetId = \"MyModule:MyShapeAsset\";\n\n" + "// Tell the GuiObjectView object to display the defined model\n" + "%thisGuiObjectView.setshape(%assetId);\n" "@endtsexample\n\n" "@see GuiControl") { - object->setObjectModel(shapeName); + return object->setObjectShape(assetId); +} + +//----------------------------------------------------------------------------- + +DefineEngineMethod(GuiObjectView, getMountedShape, const char*, (), , + "@brief Return the id of the mounted shape.\n\n" + "@tsexample\n" + "// Request the id of the mounted shape from the GuiObjectView object\n" + "%mountedShapeId = %thisGuiObjectView.getMounteShape();\n" + "@endtsexample\n\n" + "@return Name of the mounted shape.\n\n" + "@see GuiControl") +{ + return Con::getReturnBuffer(object->getMountedShapeId()); +} + +//----------------------------------------------------------------------------- + +DefineEngineMethod(GuiObjectView, setMountedShape, void, (const char* assetId), , + "@brief Sets the shape to be mounted on the primary shape.\n\n" + "@param assetId Name of the shapeAsset to mount.\n" + "@tsexample\n" + "// Define the shapeAsset name to mount\n" + "%shapeToMount = \"MyModule:MyMountedShapeAsset\";\n\n" + "// Inform the GuiObjectView object to mount the defined shapeAsset to the existing shape in the control\n" + "%thisGuiObjectView.setMountedShape(%shapeToMount);\n" + "@endtsexample\n\n" + "@see GuiControl") +{ + object->setMountedShape(assetId); } //----------------------------------------------------------------------------- @@ -873,20 +970,20 @@ DefineEngineMethod( GuiObjectView, setSeq, void, (const char* indexOrName),, //----------------------------------------------------------------------------- -DefineEngineMethod( GuiObjectView, setMount, void, ( const char* shapeName, const char* mountNodeIndexOrName),, +DefineEngineMethod( GuiObjectView, setMount, void, ( const char* assetId, const char* mountNodeIndexOrName),, "@brief Mounts the given model to the specified mount point of the primary model displayed in this control.\n\n" "Detailed description\n\n" - "@param shapeName Name of the model to mount.\n" + "@param assetId Name of the shapeAsset to mount.\n" "@param mountNodeIndexOrName Index or name of the mount point to be mounted to. If index, corresponds to \"mountN\" in your shape where N is the number passed here.\n" "@tsexample\n" "// Set the shapeName to mount\n" - "%shapeName = \"GideonGlasses.dts\"\n\n" + "%assetId = \"MyModule:MyMountedShapeAsset\"\n\n" "// Set the mount node of the primary model in the control to mount the new shape at\n" "%mountNodeIndexOrName = \"3\";\n" "//OR:\n" "%mountNodeIndexOrName = \"Face\";\n\n" "// Inform the GuiObjectView object to mount the shape at the specified node.\n" - "%thisGuiObjectView.setMount(%shapeName,%mountNodeIndexOrName);\n" + "%thisGuiObjectView.setMount(%assetId,%mountNodeIndexOrName);\n" "@endtsexample\n\n" "@see GuiControl") { @@ -895,7 +992,7 @@ DefineEngineMethod( GuiObjectView, setMount, void, ( const char* shapeName, cons else object->setMountNode( mountNodeIndexOrName ); - object->setMountedObject( shapeName ); + object->setMountedShape(assetId); } //----------------------------------------------------------------------------- diff --git a/Engine/source/T3D/guiObjectView.h b/Engine/source/T3D/guiObjectView.h index da460e452..52a11833b 100644 --- a/Engine/source/T3D/guiObjectView.h +++ b/Engine/source/T3D/guiObjectView.h @@ -66,11 +66,12 @@ class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback /// @} - /// @name Model + /// @name Shape /// @{ - ///Model loaded for display. - DECLARE_SHAPEASSET_REFACTOR(GuiObjectView, Model) + ///Shape loaded for display. + /// + AssetRef mShapeAssetRef; TSShapeInstance* mModelInstance; /// Name of skin to use on model. @@ -102,7 +103,7 @@ class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback /// @{ ///Model to mount to the primary model. - DECLARE_SHAPEASSET_REFACTOR(GuiObjectView, MountedModel) + AssetRef mMountedShapeAssetRef; TSShapeInstance* mMountedModelInstance; /// @@ -176,8 +177,11 @@ class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback /// Set the skin to use on the primary model. void setSkin( const String& name ); - /// Set the model to show in this view. - bool setObjectModel( const String& modelName ); + /// Set the shape to show in this view. + bool setObjectShape( const String& assetId ); + + /// Get the shape currently shown in this view. + StringTableEntry getObjectShapeId() const { return mShapeAssetRef.assetId; } /// @} @@ -210,7 +214,8 @@ class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback void setMountNode( const String& nodeName ); /// - bool setMountedObject( const String& modelName ); + bool setMountedShape( const String& assetId ); + StringTableEntry getMountedShapeId() const { return mMountedShapeAssetRef.assetId; } /// @} @@ -274,11 +279,11 @@ class GuiObjectView : public GuiTSCtrl, protected AssetPtrCallback protected: void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override { - if (getModel()) - setObjectModel(_getModelAssetId()); + if (mShapeAssetRef.notNull()) + setObjectShape(mShapeAssetRef.assetId); - if (getMountedModel()) - setMountedObject(_getMountedModelAssetId()); + if (mMountedShapeAssetRef.notNull()) + setMountedShape(mMountedShapeAssetRef.assetId); } }; diff --git a/Engine/source/T3D/item.cpp b/Engine/source/T3D/item.cpp index e8ca24611..335ae64ed 100644 --- a/Engine/source/T3D/item.cpp +++ b/Engine/source/T3D/item.cpp @@ -657,11 +657,18 @@ void Item::setTransform(const MatrixF& mat) //---------------------------------------------------------------------------- void Item::updateWorkingCollisionSet(const U32 mask, const F32 dt) { + if (mDataBlock->shapeAssetRef.isNull()) + return; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return; + // It is assumed that we will never accelerate more than 10 m/s for gravity... // Point3F scaledVelocity = mVelocity * dt * TickSec; F32 len = scaledVelocity.len(); - F32 newLen = len + (mDataBlock->getShape()->mRadius * dt * TickSec); + F32 newLen = len + (shape->mRadius * dt * TickSec); // Check to see if it is actually necessary to construct the new working list, // or if we can use the cached version from the last query. We use the x diff --git a/Engine/source/T3D/missionMarker.cpp b/Engine/source/T3D/missionMarker.cpp index a3e380951..752e44971 100644 --- a/Engine/source/T3D/missionMarker.cpp +++ b/Engine/source/T3D/missionMarker.cpp @@ -473,14 +473,23 @@ void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream) { delete mShapeInstance; ShapeBaseData *spawnedDatablock = dynamic_cast(Sim::findObject(mSpawnDataBlock.c_str())); - if (spawnedDatablock && spawnedDatablock->getShape()) + if (spawnedDatablock) { - mShapeInstance = new TSShapeInstance(spawnedDatablock->getShape()); + if (spawnedDatablock->shapeAssetRef.notNull()) + { + Resource shape = spawnedDatablock->shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + mShapeInstance = new TSShapeInstance(shape); + } } else if (mDataBlock) { - if (mDataBlock->getShape()) - mShapeInstance = new TSShapeInstance(mDataBlock->getShape()); + if (mDataBlock->shapeAssetRef.notNull()) + { + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + mShapeInstance = new TSShapeInstance(shape); + } } } stream->read(&mSpawnName); diff --git a/Engine/source/T3D/physics/physicsDebris.cpp b/Engine/source/T3D/physics/physicsDebris.cpp index 010d1aff5..c96519ab8 100644 --- a/Engine/source/T3D/physics/physicsDebris.cpp +++ b/Engine/source/T3D/physics/physicsDebris.cpp @@ -74,12 +74,11 @@ PhysicsDebrisData::PhysicsDebrisData() lifetime = 5.0f; lifetimeVariance = 0.0f; - mShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.registerRefreshNotify(this); } PhysicsDebrisData::~PhysicsDebrisData() { - mShapeAsset.unregisterRefreshNotify(); } bool PhysicsDebrisData::onAdd() @@ -97,17 +96,21 @@ bool PhysicsDebrisData::preload( bool server, String &errorStr ) if ( server ) return true; - if ( getShape() ) + if (!shapeAssetRef.isNull()) { - // Create a dummy shape to force the generation of shaders and materials - // during the level load and not during gameplay. - TSShapeInstance *pDummy = new TSShapeInstance( getShape(), !server); - delete pDummy; - } - else - { - errorStr = String::ToString("PhysicsDebrisData::load: Couldn't load shape asset \"%s\"", _getShapeAssetId()); - return false; + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + // Create a dummy shape to force the generation of shaders and materials + // during the level load and not during gameplay. + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + } + else + { + errorStr = String::ToString("PhysicsDebrisData(%s)::preload: Couldn't load shape asset\"%s\"", getName(), shapeAssetRef.assetId); + return false; + } } return true; @@ -118,8 +121,9 @@ void PhysicsDebrisData::initPersistFields() docsURL; addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, PhysicsDebrisData, "@brief Shape to use with this debris.\n\n" - "Compatable with Live-Asset Reloading."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, PhysicsDebrisData)) + .doc("@brief Shape to use with this debris.\n\n" + "Compatable with Live-Asset Reloading."); endGroup( "Shapes" ); @@ -218,7 +222,7 @@ void PhysicsDebrisData::packData(BitStream* stream) stream->write( waterDampingScale ); stream->write( buoyancyDensity ); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); } void PhysicsDebrisData::unpackData(BitStream* stream) @@ -239,7 +243,7 @@ void PhysicsDebrisData::unpackData(BitStream* stream) stream->read( &waterDampingScale ); stream->read( &buoyancyDensity ); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); } DefineEngineMethod( PhysicsDebrisData, preload, void, (), , @@ -250,7 +254,7 @@ DefineEngineMethod( PhysicsDebrisData, preload, void, (), , { String errorStr; - object->_setShape(object->_getShapeAssetId()); + object->shapeAssetRef = object->shapeAssetRef.assetId; if( !object->preload( false, errorStr ) ) Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() ); @@ -356,6 +360,19 @@ bool PhysicsDebris::onAdd() return false; } + if ( !mDataBlock->shapeAssetRef.notNull() ) + { + Con::errorf("PhysicsDebris::onAdd - Fail - No shape asset \"%s\"", mDataBlock->shapeAssetRef.assetId); + return false; + } + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + { + Con::errorf("PhysicsDebris::onAdd - Fail - Unable to load shape asset \"%s\"", mDataBlock->shapeAssetRef.assetId); + return false; + } + // If it has a fixed lifetime then calculate it. if ( mDataBlock->lifetime > 0.0f ) { @@ -364,7 +381,7 @@ bool PhysicsDebris::onAdd() } // Setup our bounding box - mObjBox = mDataBlock->getShape()->mBounds; + mObjBox = shape->mBounds; resetWorldBox(); // Add it to the client scene. @@ -627,7 +644,7 @@ void PhysicsDebris::_createFragments() if ( !mWorld ) return; - TSShape *shape = mDataBlock->getShape(); + TSShape *shape = mDataBlock->shapeAssetRef.assetPtr->getShape(); mShapeInstance = new TSShapeInstance( shape, true ); mShapeInstance->animate(); @@ -701,7 +718,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->getShape(); + TSShape *shape = mDataBlock->shapeAssetRef.assetPtr->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 3b5371647..48f0e4918 100644 --- a/Engine/source/T3D/physics/physicsDebris.h +++ b/Engine/source/T3D/physics/physicsDebris.h @@ -86,7 +86,7 @@ public: /// Is rendererd during shadow passes. bool castShadows; - DECLARE_SHAPEASSET_REFACTOR(PhysicsDebrisData, Shape) + AssetRef shapeAssetRef; PhysicsDebrisData(); virtual ~PhysicsDebrisData(); diff --git a/Engine/source/T3D/physics/physicsShape.cpp b/Engine/source/T3D/physics/physicsShape.cpp index da95d4ef7..48b3b9b48 100644 --- a/Engine/source/T3D/physics/physicsShape.cpp +++ b/Engine/source/T3D/physics/physicsShape.cpp @@ -78,12 +78,11 @@ PhysicsShapeData::PhysicsShapeData() buoyancyDensity( 0.0f ), simType( SimType_ClientServer ) { - mShapeAsset.registerRefreshNotify(this); + shapeAsset.assetPtr.registerRefreshNotify(this); } PhysicsShapeData::~PhysicsShapeData() { - mShapeAsset.unregisterRefreshNotify(); } void PhysicsShapeData::initPersistFields() @@ -91,8 +90,9 @@ void PhysicsShapeData::initPersistFields() docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, PhysicsShapeData, "@brief Shape asset to be used with this physics object.\n\n" - "Compatable with Live-Asset Reloading. ") + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAsset, PhysicsShapeData)) + . doc("@brief Shape asset to be used with this physics object.\n\n" + "Compatable with Live-Asset Reloading. "); addField( "debris", TYPEID< SimObjectRef >(), Offset( debris, PhysicsShapeData ), "@brief Name of a PhysicsDebrisData to spawn when this shape is destroyed (optional)." ); @@ -181,7 +181,7 @@ void PhysicsShapeData::packData( BitStream *stream ) { Parent::packData( stream ); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAsset.assetId); stream->write( mass ); stream->write( dynamicFriction ); @@ -205,7 +205,7 @@ void PhysicsShapeData::unpackData( BitStream *stream ) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAsset = AssetDatabase.unpackDataAsset(stream); stream->read( &mass ); stream->read( &dynamicFriction ); @@ -242,27 +242,28 @@ void PhysicsShapeData::onRemove() void PhysicsShapeData::_onResourceChanged( const Torque::Path &path ) { - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(shapeAsset.assetPtr); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; } - if ( path != Path(mShapeAsset->getShapeFile()) ) + + if ( path != Path(shapeAsset.assetPtr->getShapeFile()) ) return; - _setShape(_getShapeAssetId()); + shapeAsset = shapeAsset.assetId; // Reload the changed shape. PhysicsCollisionRef reloadcolShape; - - if ( !getShape()) + Resource shape = shapeAsset.assetPtr->getShapeResource(); + if ( !shape) { Con::warnf( ConsoleLogEntry::General, "PhysicsShapeData::_onResourceChanged: Could not reload %s.", path.getFileName().c_str() ); return; } // Reload the collision shape. - reloadcolShape = getShape()->buildColShape( false, Point3F::One ); + reloadcolShape = shape->buildColShape( false, Point3F::One ); if ( bool(reloadcolShape)) colShape = reloadcolShape; @@ -283,34 +284,41 @@ bool PhysicsShapeData::preload( bool server, String &errorBuffer ) return false; } - bool shapeError = false; - - if (getShape()) + if (shapeAsset.isNull()) { - if (!server && !getShape()->preloadMaterialList(getShapeFile()) && NetConnection::filesWereDownloaded()) + errorBuffer = String::ToString("PhysicsShapeData::preload(%s) - No shape asset!", getName()); + return false; + } + + bool shapeError = false; + Resource shape = shapeAsset.assetPtr->getShapeResource(); + + if (shape) + { + if (!server && !shapeAsset.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) shapeError = true; } else { - errorBuffer = String::ToString("PhysicsShapeData: Couldn't load shape \"%s\"", _getShapeAssetId()); + errorBuffer = String::ToString("PhysicsShapeData: Couldn't load shape! AssetId \"%s\"", shapeAsset.assetId); return false; } // Prepare the shared physics collision shape. - if ( !colShape && getShape()) + if ( !colShape && shape) { - colShape = getShape()->buildColShape( false, Point3F::One ); + colShape = shape->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", _getShapeAssetId()); - Point3F halfWidth = getShape()->mBounds.getExtents() * 0.5f; + Con::warnf( "PhysicsShapeData::preload - No collision found for shape '%s', auto-creating one", shapeAsset.assetId); + Point3F halfWidth = shape->mBounds.getExtents() * 0.5f; colShape = PHYSICSMGR->createCollision(); MatrixF centerXfm(true); - centerXfm.setPosition(getShape()->mBounds.getCenter()); + centerXfm.setPosition(shape->mBounds.getCenter()); colShape->addBox(halfWidth, centerXfm); return true; } @@ -703,11 +711,12 @@ bool PhysicsShape::_createShape() mAmbientSeq = -1; PhysicsShapeData *db = getDataBlock(); - if ( !db || !db->getShape()) + Resource shape; + if ( !db || !(shape = db->shapeAsset.assetPtr->getShapeResource())) return false; // Set the world box. - mObjBox = db->getShape()->mBounds; + mObjBox = shape->mBounds; resetWorldBox(); // If this is the server and its a client only simulation @@ -721,11 +730,11 @@ bool PhysicsShape::_createShape() } // Create the shape instance. - mShapeInst = new TSShapeInstance( db->getShape(), isClientObject() ); + mShapeInst = new TSShapeInstance(shape, isClientObject() ); if ( isClientObject() ) { - mAmbientSeq = db->getShape()->findSequence( "ambient" ); + mAmbientSeq = shape->findSequence( "ambient" ); _initAmbient(); } diff --git a/Engine/source/T3D/physics/physicsShape.h b/Engine/source/T3D/physics/physicsShape.h index 7419c2442..7c9ae7491 100644 --- a/Engine/source/T3D/physics/physicsShape.h +++ b/Engine/source/T3D/physics/physicsShape.h @@ -74,7 +74,7 @@ public: public: - DECLARE_SHAPEASSET_REFACTOR(PhysicsShapeData, Shape) + AssetRef shapeAsset; /// The shared unscaled collision shape. PhysicsCollisionRef colShape; diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 1b9af0ea6..5cc7f1045 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -299,7 +299,7 @@ PlayerData::PlayerData() imageAnimPrefixFP = StringTable->EmptyString(); for (U32 i=0; i shape; + if (shapeAssetRef.notNull()) + shape = shapeAssetRef.assetPtr->getShapeResource(); + // If we don't have a shape don't crash out trying to // setup animations and sequences. - if (getShape()) + if (shape) { // Go ahead a pre-load the player shape - TSShapeInstance* si = new TSShapeInstance(getShape(), false); + TSShapeInstance* si = new TSShapeInstance(shape, false); TSThread* thread = si->addThread(); // Extract ground transform velocity from animations @@ -522,7 +526,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 = getShape()->findSequence(sp->name); + dp->sequence = shape->findSequence(sp->name); // If this is a sprint action and is missing a sequence, attempt to use // the standard run ones. @@ -530,7 +534,7 @@ bool PlayerData::preload(bool server, String &errorStr) { S32 offset = i-SprintRootAnim; ActionAnimationDef *standDef = &ActionAnimationList[RootAnim+offset]; - dp->sequence = getShape()->findSequence(standDef->name); + dp->sequence = shape->findSequence(standDef->name); } dp->velocityScale = true; @@ -538,12 +542,12 @@ bool PlayerData::preload(bool server, String &errorStr) if (dp->sequence != -1) getGroundInfo(si,thread,dp); } - for (S32 b = 0; b < getShape()->sequences.size(); b++) + for (S32 b = 0; b < shape->sequences.size(); b++) { if (!isTableSequence(b)) { dp->sequence = b; - dp->name = getShape()->getName(getShape()->sequences[b].nameIndex); + dp->name = shape->getName(shape->sequences[b].nameIndex); dp->velocityScale = false; getGroundInfo(si,thread,dp++); } @@ -560,17 +564,17 @@ bool PlayerData::preload(bool server, String &errorStr) lookAction = c; // Resolve spine - 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"); + spineNode[0] = shape->findNode("Bip01 Pelvis"); + spineNode[1] = shape->findNode("Bip01 Spine"); + spineNode[2] = shape->findNode("Bip01 Spine1"); + spineNode[3] = shape->findNode("Bip01 Spine2"); + spineNode[4] = shape->findNode("Bip01 Neck"); + spineNode[5] = shape->findNode("Bip01 Head"); // Recoil animations - recoilSequence[0] = getShape()->findSequence("light_recoil"); - recoilSequence[1] = getShape()->findSequence("medium_recoil"); - recoilSequence[2] = getShape()->findSequence("heavy_recoil"); + recoilSequence[0] = shape->findSequence("light_recoil"); + recoilSequence[1] = shape->findSequence("medium_recoil"); + recoilSequence[2] = shape->findSequence("heavy_recoil"); } // Convert pickupRadius to a delta of boundingBox @@ -613,40 +617,44 @@ bool PlayerData::preload(bool server, String &errorStr) { bool shapeError = false; - if (mShapeFPAsset[i].notNull()) + if (shapeFPAssetRef[i].isNull()) + continue; + + Resource shapeFP = shapeFPAssetRef[i].assetPtr->getShapeResource(); + + if (!shapeFP) { - if (!getShapeFP(i)) + errorStr = String::ToString("PlayerData: Couldn't load mounted image %d shape \"%s\"", i, shapeFPAssetRef[i].assetId); + return false; + } + + if (!server && !shapeFPAssetRef[i].assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) + shapeError = true; + + if (computeCRC) + { + Con::printf("Validation required for mounted image %d shape: %s", i, shapeFPAssetRef[i].assetId); + + Torque::Path shapeFPFilePath = shapeFPAssetRef[i].assetPtr->getShapeFile(); + + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(shapeFPFilePath); + + if (!fileRef) { - errorStr = String::ToString("PlayerData: Couldn't load mounted image %d shape \"%s\"", i, _getShapeFPAssetId(i)); + errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.", i, shapeFPFilePath.getFullPath().c_str()); return false; } - if (!server && !getShapeFP(i)->preloadMaterialList(getShapeFPFile(i)) && NetConnection::filesWereDownloaded()) - shapeError = true; - - if (computeCRC) + if (server) + mCRCFP[i] = fileRef->getChecksum(); + else if (mCRCFP[i] != fileRef->getChecksum()) { - Con::printf("Validation required for mounted image %d shape: %s", i, _getShapeFPAssetId(i)); - - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(getShapeFPFile(i)); - - if (!fileRef) - { - errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.", i, getShapeFPFile(i)); - return false; - } - - if (server) - 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, _getShapeFPAssetId(i)); - return false; - } + errorStr = String::ToString("PlayerData: Mounted image %d shape \"%s\" does not match version on server.", i, shapeFPAssetRef[i].assetId); + return false; } - - mValidShapeFP[i] = true; } + + mValidShapeFP[i] = true; } return true; @@ -1150,7 +1158,9 @@ void PlayerData::initPersistFields() // Mounted images arrays addArray( "Mounted Images", ShapeBase::MaxMountedImages ); - 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" + ADD_FIELD("shapeFPAsset", TypeShapeAssetRef, Offset(shapeFPAssetRef, PlayerData)) + .elements(ShapeBase::MaxMountedImages) + .doc("@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"); @@ -1357,9 +1367,9 @@ void PlayerData::packData(BitStream* stream) { stream->write(mCRCFP[i]); } - } - PACKDATA_ASSET_ARRAY_REFACTOR(ShapeFP, ShapeBase::MaxMountedImages) + AssetDatabase.packDataAsset(stream, shapeFPAssetRef[i].assetId); + } } void PlayerData::unpackData(BitStream* stream) @@ -1539,9 +1549,10 @@ void PlayerData::unpackData(BitStream* stream) { stream->read(&(mCRCFP[i])); } + + shapeFPAssetRef[i] = AssetDatabase.unpackDataAsset(stream); } - UNPACKDATA_ASSET_ARRAY_REFACTOR(ShapeFP, ShapeBase::MaxMountedImages) } @@ -1878,9 +1889,13 @@ bool Player::onNewDataBlock( GameBaseData *dptr, bool reload ) { for (U32 i=0; igetShapeFP(i))) + if (mDataBlock->shapeFPAssetRef[i].isNull()) + continue; + + Resource shapeFP = mDataBlock->shapeFPAssetRef[i].assetPtr->getShapeResource(); + if (bool(shapeFP)) { - mShapeFPInstance[i] = new TSShapeInstance(mDataBlock->getShapeFP(i), isClientObject()); + mShapeFPInstance[i] = new TSShapeInstance(shapeFP, isClientObject()); mShapeFPInstance[i]->cloneMaterialList(); @@ -6166,6 +6181,13 @@ void Player::buildConvex(const Box3F& box, Convex* convex) void Player::updateWorkingCollisionSet() { + if (mDataBlock->shapeAssetRef.isNull()) + return; + + Resource shape = mDataBlock->shapeFPAssetRef->assetPtr->getShapeResource(); + if (!shape) + return; + // First, we need to adjust our velocity for possible acceleration. It is assumed // that we will never accelerate more than 20 m/s for gravity, plus 10 m/s for // jetting, and an equivalent 10 m/s for jumping. We also assume that the @@ -6173,7 +6195,7 @@ void Player::updateWorkingCollisionSet() // box by the possible movement in that tick. Point3F scaledVelocity = mVelocity * TickSec; F32 len = scaledVelocity.len(); - F32 newLen = len + (mDataBlock->getShape()->mRadius * TickSec); + F32 newLen = len + (shape->mRadius * TickSec); // Check to see if it is actually necessary to construct the new working list, // or if we can use the cached version from the last query. We use the x @@ -7571,9 +7593,17 @@ F32 Player::getAnimationDurationByID(U32 anim_id) { if (anim_id == BAD_ANIM_ID) return 0.0f; + + if (mDataBlock->shapeAssetRef.isNull()) + return 0.0f; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return 0.0f; + S32 seq_id = mDataBlock->actionList[anim_id].sequence; - if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) - return mDataBlock->getShape()->sequences[seq_id].duration; + if (seq_id >= 0 && seq_id < shape->sequences.size()) + return shape->sequences[seq_id].duration; return 0.0f; } @@ -7584,10 +7614,16 @@ bool Player::isBlendAnimation(const char* name) if (anim_id == BAD_ANIM_ID) return false; - S32 seq_id = mDataBlock->actionList[anim_id].sequence; - if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) - return mDataBlock->getShape()->sequences[seq_id].isBlend(); + if (mDataBlock->shapeAssetRef.isNull()) + return false; + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return false; + + S32 seq_id = mDataBlock->actionList[anim_id].sequence; + if (seq_id >= 0 && seq_id < shape->sequences.size()) + return shape->sequences[seq_id].isBlend(); return false; } diff --git a/Engine/source/T3D/player.h b/Engine/source/T3D/player.h index 3ed8b4355..af9477fd8 100644 --- a/Engine/source/T3D/player.h +++ b/Engine/source/T3D/player.h @@ -82,7 +82,7 @@ struct PlayerData: public ShapeBaseData /*protected AssetPtrCallback < already i /// that we don't create a TSThread on the player if we don't /// need to. - DECLARE_SHAPEASSET_ARRAY_REFACTOR(PlayerData, ShapeFP, ShapeBase::MaxMountedImages) + AssetRef shapeFPAssetRef[ShapeBase::MaxMountedImages]; StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify /// animation sequences played in first person. [optional] diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index 4476d70dd..58faad6ea 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -145,7 +145,7 @@ U32 Projectile::smProjectileWarpTicks = 5; // ProjectileData::ProjectileData() { - mProjectileShapeAsset.registerRefreshNotify(this); + projectileShapeAssetRef.assetPtr.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 - mProjectileShapeAsset = other.mProjectileShapeAsset;// -- TSShape loads using mProjectileShapeName + projectileShapeAssetRef = other.projectileShapeAssetRef;// -- TSShape loads using projectileShapeAssetRef activateSeq = other.activateSeq; // -- from projectileShape sequence "activate" maintainSeq = other.maintainSeq; // -- from projectileShape sequence "maintain" particleEmitter = other.particleEmitter; @@ -237,7 +237,8 @@ void ProjectileData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(ProjectileShape, ProjectileData, "@brief The model of the projectile.\n\n"); + ADD_FIELD("projectileShapeAsset", TypeShapeAssetRef, Offset(projectileShapeAssetRef, ProjectileData)) + .doc("@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"); @@ -422,18 +423,21 @@ bool ProjectileData::preload(bool server, String &errorStr) Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockid(lightDesc): %d", lightDescId); } - if (getProjectileShape()) + if (!projectileShapeAssetRef.isNull()) { - activateSeq = getProjectileShape()->findSequence("activate"); - maintainSeq = getProjectileShape()->findSequence("maintain"); - - TSShapeInstance* pDummy = new TSShapeInstance(getProjectileShape(), !server); - delete pDummy; - } - else if (mProjectileShapeAsset.notNull()) - { - errorStr = String::ToString("ProjectileData::preload: Couldn't load shape \"%s\"", _getProjectileShapeAssetId()); - return false; + Resource shape = projectileShapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + if (!server && !projectileShapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) + return false; + } + else + { + errorStr = String::ToString("ProjectileData(%s)::preload: Couldn't load shape \"%s\"", getName(), projectileShapeAssetRef.assetId); + return false; + } } return true; @@ -444,7 +448,7 @@ void ProjectileData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET_REFACTOR(ProjectileShape); + AssetDatabase.packDataAsset(stream, projectileShapeAssetRef.assetId);; stream->writeFlag(faceViewer); if(stream->writeFlag(scale.x != 1 || scale.y != 1 || scale.z != 1)) @@ -509,7 +513,7 @@ void ProjectileData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(ProjectileShape); + projectileShapeAssetRef = AssetDatabase.unpackDataAsset(stream); faceViewer = stream->readFlag(); if(stream->readFlag()) @@ -808,6 +812,8 @@ bool Projectile::onAdd() return false; } + Resource pShape; + if (isServerObject()) { ShapeBase* ptr; @@ -835,15 +841,19 @@ bool Projectile::onAdd() } else { - if (bool(mDataBlock->getProjectileShape())) + if (mDataBlock->projectileShapeAssetRef.notNull()) { - mProjectileShape = new TSShapeInstance(mDataBlock->getProjectileShape(), isClientObject()); - - if (mDataBlock->activateSeq != -1) + pShape = mDataBlock->projectileShapeAssetRef.assetPtr->getShapeResource(); + if (pShape) { - mActivateThread = mProjectileShape->addThread(); - mProjectileShape->setTimeScale(mActivateThread, 1); - mProjectileShape->setSequence(mActivateThread, mDataBlock->activateSeq, 0); + mProjectileShape = new TSShapeInstance(pShape, isClientObject()); + + if (mDataBlock->activateSeq != -1) + { + mActivateThread = mProjectileShape->addThread(); + mProjectileShape->setTimeScale(mActivateThread, 1); + mProjectileShape->setSequence(mActivateThread, mDataBlock->activateSeq, 0); + } } } if (mDataBlock->particleEmitter != NULL) @@ -876,8 +886,8 @@ bool Projectile::onAdd() processAfter(mSourceObject); // Setup our bounding box - if (bool(mDataBlock->getProjectileShape()) == true) - mObjBox = mDataBlock->getProjectileShape()->mBounds; + if (bool(pShape) == true) + mObjBox = pShape->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 af1b3e8d3..cc28d00b1 100644 --- a/Engine/source/T3D/projectile.h +++ b/Engine/source/T3D/projectile.h @@ -71,7 +71,7 @@ protected: bool onAdd() override; public: - DECLARE_SHAPEASSET_REFACTOR(ProjectileData, ProjectileShape) + AssetRef projectileShapeAssetRef; /// Set to true if it is a billboard and want it to always face the viewer, false otherwise bool faceViewer; diff --git a/Engine/source/T3D/proximityMine.cpp b/Engine/source/T3D/proximityMine.cpp index 86c9807b6..4b7cef8f6 100644 --- a/Engine/source/T3D/proximityMine.cpp +++ b/Engine/source/T3D/proximityMine.cpp @@ -144,11 +144,15 @@ bool ProximityMineData::preload( bool server, String& errorStr ) } } - if ( getShape() ) + if (shapeAssetRef.notNull()) { - // Lookup animation sequences - armingSequence = getShape()->findSequence( "armed" ); - triggerSequence = getShape()->findSequence( "triggered" ); + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + // Lookup animation sequences + armingSequence = shape->findSequence("armed"); + triggerSequence = shape->findSequence("triggered"); + } } return true; diff --git a/Engine/source/T3D/rigidShape.cpp b/Engine/source/T3D/rigidShape.cpp index 4caac7ddb..425143f3c 100644 --- a/Engine/source/T3D/rigidShape.cpp +++ b/Engine/source/T3D/rigidShape.cpp @@ -281,7 +281,8 @@ RigidShapeData::RigidShapeData() dustTrailEmitter = NULL; dustTrailID = 0; - _setShape(ShapeAsset::smNoShapeAssetFallback); + + shapeAssetRef = ShapeAsset::smNoShapeAssetFallback; } RigidShapeData::~RigidShapeData() @@ -340,7 +341,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\"", getShapeAsset().getAssetId()); + errorStr = String::ToString("RigidShapeData: Couldn't load shape asset \"%s\"", shapeAssetRef.assetId); return false; } @@ -1443,13 +1444,20 @@ void RigidShape::updateWorkingCollisionSet(const U32 mask) { PROFILE_SCOPE( Vehicle_UpdateWorkingCollisionSet ); + if (mDataBlock->shapeAssetRef.isNull()) + return; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return; + // First, we need to adjust our velocity for possible acceleration. It is assumed // that we will never accelerate more than 20 m/s for gravity, plus 30 m/s for // jetting, and an equivalent 10 m/s for vehicle accel. We also assume that our // working list is updated on a Tick basis, which means we only expand our box by // the possible movement in that tick, plus some extra for caching purposes Box3F convexBox = mConvex.getBoundingBox(getTransform(), getScale()); - F32 len = (mRigid.linVelocity.len() + mDataBlock->getShape()->mRadius) * TickSec; + F32 len = (mRigid.linVelocity.len() + shape->mRadius) * TickSec; F32 l = (len * 1.1) + 0.1; // fudge factor convexBox.minExtents -= Point3F(l, l, l); convexBox.maxExtents += Point3F(l, l, l); diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 44fe70382..96f41f39b 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -205,8 +205,8 @@ ShapeBaseData::ShapeBaseData() remap_txr_tags = NULL; remap_buffer = NULL; silent_bbox_check = false; - mShapeAsset.registerRefreshNotify(this); - mDebrisShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.registerRefreshNotify(this); + debrisShapeAssetRef.assetPtr.registerRefreshNotify(this); } ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : GameBaseData(other, temp_clone) @@ -216,13 +216,13 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game shadowProjectionDistance = other.shadowProjectionDistance; shadowSphereAdjust = other.shadowSphereAdjust; cloakTexName = other.cloakTexName; - mShapeAsset = other.mShapeAsset; + shapeAssetRef = other.shapeAssetRef; cubeDescName = other.cubeDescName; cubeDescId = other.cubeDescId; reflectorDesc = other.reflectorDesc; debris = other.debris; debrisID = other.debrisID; // -- for pack/unpack of debris ptr - mDebrisShapeAsset = other.mDebrisShapeAsset; + debrisShapeAssetRef = other.debrisShapeAssetRef; explosion = other.explosion; explosionID = other.explosionID; // -- for pack/unpack of explosion ptr underwaterExplosion = other.underwaterExplosion; @@ -299,12 +299,8 @@ static ShapeBaseDataProto gShapeBaseDataProto; ShapeBaseData::~ShapeBaseData() { - if (remap_buffer && !isTempClone()) dFree(remap_buffer); - - mShapeAsset.unregisterRefreshNotify(); - mDebrisShapeAsset.unregisterRefreshNotify(); } bool ShapeBaseData::preload(bool server, String &errorStr) @@ -350,32 +346,38 @@ bool ShapeBaseData::preload(bool server, String &errorStr) "ShapeBaseData::preload: invalid debris data"); } - if(getDebrisShape()) + if (debrisShapeAssetRef.notNull()) { - TSShapeInstance* pDummy = new TSShapeInstance(getDebrisShape(), !server); - delete pDummy; + Resource dShape = debrisShapeAssetRef.assetPtr->getShapeResource(); + if (dShape) + { + TSShapeInstance* pDummy = new TSShapeInstance(dShape, !server); + delete pDummy; + } } } + Resource shape; + S32 i; - if (getShape()) + if (shapeAssetRef.notNull() && (shape = shapeAssetRef.assetPtr->getShapeResource())) { //mShapeAsset->load(); - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(shapeAssetRef.assetPtr); if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) { - if (!server && !getShape()->preloadMaterialList(getShapeFile()) && NetConnection::filesWereDownloaded()) + if (!server && !shapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) shapeError = true; if (computeCRC) { - Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId()); + Con::printf("Validation required for shape asset: %s", shapeAssetRef.assetId); - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapeFile()); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(shapeAssetRef.assetPtr->getShapeFile()); if (!fileRef) { - errorStr = String::ToString("ShapeBaseData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId()); + errorStr = String::ToString("ShapeBaseData(%s): Couldn't load shape asset \"%s\"", getName(), shapeAssetRef.assetId); return false; } @@ -383,36 +385,36 @@ bool ShapeBaseData::preload(bool server, String &errorStr) mCRC = fileRef->getChecksum(); else if (mCRC != fileRef->getChecksum()) { - errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", mShapeAsset.getAssetId()); + errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", shapeAssetRef.assetId); return false; } } // Resolve details and camera node indexes. static const String sCollisionStr("collision-"); - for (i = 0; i < getShape()->details.size(); i++) + for (i = 0; i < shape->details.size(); i++) { - const String& name = getShape()->names[getShape()->details[i].nameIndex]; + const String& name = shape->names[shape->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()); + shape->computeBounds(collisionDetails.last(), collisionBounds.last()); + shape->getAccelerator(collisionDetails.last()); - if (!getShape()->mBounds.isContained(collisionBounds.last())) + if (!shape->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; + Con::warnf("Warning: shape asset %s collision detail %d (Collision-%d) bounds exceed that of shape.", shapeAssetRef.assetId, collisionDetails.size() - 1, collisionDetails.last()); + collisionBounds.last() = shape->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; + Con::errorf("Error: shape asset %s-collision detail %d (Collision-%d) bounds box invalid!", shapeAssetRef.assetId, collisionDetails.size() - 1, collisionDetails.last()); + collisionBounds.last() = shape->mBounds; } // The way LOS works is that it will check to see if there is a LOS detail that matches @@ -422,7 +424,7 @@ bool ShapeBaseData::preload(bool server, String &errorStr) LOSDetails.increment(); String buff = String::ToString("LOS-%d", i + 1 + MaxCollisionShapes); - U32 los = getShape()->findDetail(buff); + U32 los = shape->findDetail(buff); if (los == -1) LOSDetails.last() = i; else @@ -433,9 +435,9 @@ bool ShapeBaseData::preload(bool server, String &errorStr) // Snag any "unmatched" LOS details static const String sLOSStr("LOS-"); - for (i = 0; i < getShape()->details.size(); i++) + for (i = 0; i < shape->details.size(); i++) { - const String& name = getShape()->names[getShape()->details[i].nameIndex]; + const String& name = shape->names[shape->details[i].nameIndex]; if (name.compare(sLOSStr, sLOSStr.length(), String::NoCase) == 0) { @@ -455,12 +457,12 @@ bool ShapeBaseData::preload(bool server, String &errorStr) } } - debrisDetail = getShape()->findDetail("Debris-17"); - eyeNode = getShape()->findNode("eye"); - earNode = getShape()->findNode("ear"); + debrisDetail = shape->findDetail("Debris-17"); + eyeNode = shape->findNode("eye"); + earNode = shape->findNode("ear"); if (earNode == -1) earNode = eyeNode; - cameraNode = getShape()->findNode("cam"); + cameraNode = shape->findNode("cam"); if (cameraNode == -1) cameraNode = eyeNode; @@ -468,18 +470,18 @@ bool ShapeBaseData::preload(bool server, String &errorStr) for (i = 0; i < SceneObject::NumMountPoints; i++) { char fullName[256]; dSprintf(fullName, sizeof(fullName), "mount%d", i); - mountPointNode[i] = getShape()->findNode(fullName); + mountPointNode[i] = shape->findNode(fullName); } // find the AIRepairNode - hardcoded to be the last node in the array... - mountPointNode[AIRepairNode] = getShape()->findNode("AIRepairNode"); + mountPointNode[AIRepairNode] = shape->findNode("AIRepairNode"); // - hulkSequence = getShape()->findSequence("Visibility"); - damageSequence = getShape()->findSequence("Damage"); + hulkSequence = shape->findSequence("Visibility"); + damageSequence = shape->findSequence("Damage"); // - F32 w = getShape()->mBounds.len_y() / 2; + F32 w = shape->mBounds.len_y() / 2; if (cameraMaxDist < w) cameraMaxDist = w; // just parse up the string and collect the remappings in txr_tag_remappings. @@ -507,7 +509,7 @@ bool ShapeBaseData::preload(bool server, String &errorStr) } } else - Con::errorf("ShapeBaseData::preload -%s failed: %s", mShapeAsset.getAssetId(), ShapeAsset::getAssetErrstrn(assetStatus).c_str()); + Con::errorf("ShapeBaseData::preload(%s) -%s failed: %s", getName(), shapeAssetRef.assetId, ShapeAsset::getAssetErrstrn(assetStatus).c_str()); } if(!server) @@ -557,12 +559,14 @@ void ShapeBaseData::initPersistFields() { docsURL; addGroup( "Shapes" ); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, ShapeBaseData, "The source shape asset."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, ShapeBaseData)) + .doc("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_REFACTOR(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional."); + ADD_FIELD("debrisShapeAsset", TypeShapeAssetRef, Offset(debrisShapeAssetRef, ShapeBaseData)) + .doc("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), @@ -691,12 +695,16 @@ 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->getShape()) == false) + if (object->shapeAssetRef.isNull()) + return false; + + Resource shape = object->shapeAssetRef.assetPtr->getShapeResource(); + if (bool(shape) == false) return false; MatrixF mat = txfm.getMatrix(); - Box3F objBox = object->getShape()->mBounds; + Box3F objBox = shape->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; @@ -766,8 +774,8 @@ void ShapeBaseData::packData(BitStream* stream) stream->write(shadowProjectionDistance); stream->write(shadowSphereAdjust); - PACKDATA_ASSET_REFACTOR(Shape); - PACKDATA_ASSET_REFACTOR(DebrisShape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); + AssetDatabase.packDataAsset(stream, debrisShapeAssetRef.assetId); stream->writeString(cloakTexName); if(stream->writeFlag(mass != gShapeBaseDataProto.mass)) @@ -843,8 +851,8 @@ void ShapeBaseData::unpackData(BitStream* stream) stream->read(&shadowProjectionDistance); stream->read(&shadowSphereAdjust); - UNPACKDATA_ASSET_REFACTOR(Shape); - UNPACKDATA_ASSET_REFACTOR(DebrisShape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); + debrisShapeAssetRef = AssetDatabase.unpackDataAsset(stream); cloakTexName = stream->readSTString(); if(stream->readFlag()) @@ -1224,12 +1232,14 @@ 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->getShape())) { + Resource shape; + if (bool(mDataBlock->shapeAssetRef.notNull() && (shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource()))) + { delete mShapeInstance; if (isClientObject() && mDataBlock->txr_tag_remappings.size() > 0) { // temporarily substitute material tags with alternates - TSMaterialList* mat_list = mDataBlock->getShape()->materialList; + TSMaterialList* mat_list = shape->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -1249,7 +1259,7 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) } } } - mShapeInstance = new TSShapeInstance(mDataBlock->getShape(), isClientObject()); + mShapeInstance = new TSShapeInstance(shape, isClientObject()); if (isClientObject()) { mShapeInstance->cloneMaterialList(); @@ -1257,7 +1267,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->getShape()->materialList; + TSMaterialList* mat_list = shape->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -1283,11 +1293,11 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload ) } } - mObjBox = mDataBlock->getShape()->mBounds; + mObjBox = shape->mBounds; resetWorldBox(); // Set the initial mesh hidden state. - mMeshHidden.setSize(mDataBlock->getShape()->objects.size()); + mMeshHidden.setSize(shape->objects.size()); mMeshHidden.clear(); // Initialize the threads @@ -1311,11 +1321,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->getShape(); + const TSShape* prevShape = prevDB->shapeAssetRef.assetPtr->getShape(); const TSShape::Sequence& prevSeq = prevShape->sequences[st.sequence]; const String& prevSeqName = prevShape->names[prevSeq.nameIndex]; - st.sequence = mDataBlock->getShape()->findSequence(prevSeqName); + st.sequence = shape->findSequence(prevSeqName); if (st.sequence != -1) { @@ -1991,13 +2001,14 @@ void ShapeBase::blowUp() TSShapeInstance *debShape = NULL; - if( mDataBlock->getDebrisShape() == NULL) + Resource debrisShape; + if( mDataBlock->debrisShapeAssetRef.isNull() || !(debrisShape = mDataBlock->debrisShapeAssetRef.assetPtr->getShapeResource()) ) { return; } else { - debShape = new TSShapeInstance( mDataBlock->getDebrisShape(), true); + debShape = new TSShapeInstance(debrisShape, true); } @@ -2069,7 +2080,11 @@ Point3F ShapeBase::getAIRepairPoint() //---------------------------------------------------------------------------- void ShapeBase::getNodeTransform(const char* nodeName, MatrixF* outMat) { - S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName); + Resource shape; + if (mDataBlock->shapeAssetRef.isNull() || !(shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource())) + return; + + S32 nodeIDx = shape->findNode(nodeName); const MatrixF& xfm = isMounted() ? mMount.xfm : MatrixF::Identity; MatrixF nodeTransform(xfm); @@ -2236,7 +2251,9 @@ void ShapeBase::getNodeTransform(const char* nodeName, const MatrixF& xfm, Matri if (!mShapeInstance) return; - S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName); + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + + S32 nodeIDx = shape->findNode(nodeName); MatrixF nodeTransform(xfm); const Point3F& scale = getScale(); @@ -5045,7 +5062,14 @@ void ShapeBase::_updateHiddenMeshes() void ShapeBase::setMeshHidden( const char *meshName, bool forceHidden ) { - setMeshHidden( mDataBlock->getShape()->findObject(meshName), forceHidden); + if (mDataBlock->shapeAssetRef.isNull()) + return; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return; + + setMeshHidden(shape->findObject(meshName), forceHidden); } void ShapeBase::setMeshHidden( S32 meshIndex, bool forceHidden ) @@ -5114,7 +5138,8 @@ void ShapeBase::dumpMeshVisibility() { const TSShapeInstance::MeshObjectInstance &mesh = meshes[i]; - const String &meshName = mDataBlock->getShape()->getMeshName( i ); + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + const String &meshName = shape->getMeshName( i ); Con::printf( "%d - %s - forceHidden = %s, visibility = %f", i, @@ -5395,9 +5420,16 @@ F32 ShapeBase::getAnimationDurationByID(U32 anim_id) if (anim_id == BAD_ANIM_ID) return 0.0f; + if (mDataBlock->shapeAssetRef.isNull()) + return 0.0f; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return 0.0f; + S32 seq_id = (S32) anim_id; - if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) - return mDataBlock->getShape()->sequences[seq_id].duration; + if (seq_id >= 0 && seq_id < shape->sequences.size()) + return shape->sequences[seq_id].duration; return 0.0f; } @@ -5408,9 +5440,16 @@ bool ShapeBase::isBlendAnimation(const char* name) if (anim_id == BAD_ANIM_ID) return false; + if (mDataBlock->shapeAssetRef.isNull()) + return 0.0f; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return 0.0f; + S32 seq_id = (S32) anim_id; - if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size()) - return mDataBlock->getShape()->sequences[seq_id].isBlend(); + if (seq_id >= 0 && seq_id < shape->sequences.size()) + return shape->sequences[seq_id].isBlend(); return false; } @@ -5420,13 +5459,20 @@ const char* ShapeBase::getLastClipName(U32 clip_tag) if (clip_tag != last_anim_tag) return ""; + if (mDataBlock->shapeAssetRef.isNull()) + return ""; + + Resource shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return ""; + S32 seq_id = (S32) last_anim_id; - S32 idx = mDataBlock->getShape()->sequences[seq_id].nameIndex; - if (idx < 0 || idx >= mDataBlock->getShape()->names.size()) + S32 idx = shape->sequences[seq_id].nameIndex; + if (idx < 0 || idx >= shape->names.size()) return 0; - return mDataBlock->getShape()->names[idx]; + return shape->names[idx]; } // diff --git a/Engine/source/T3D/shapeBase.h b/Engine/source/T3D/shapeBase.h index 71967bbe1..e53ab5e1d 100644 --- a/Engine/source/T3D/shapeBase.h +++ b/Engine/source/T3D/shapeBase.h @@ -381,7 +381,7 @@ struct ShapeBaseImageData: public GameBaseData, protected AssetPtrCallback F32 scriptAnimTransitionTime; ///< The amount of time to transition between the previous sequence and new sequence ///< when the script prefix has changed. - DECLARE_SHAPEASSET_ARRAY_REFACTOR(ShapeBaseImageData, Shape, MaxShapes) ///< Name of shape to render. + AssetRef shapeAssetRef[MaxShapes]; StringTableEntry imageAnimPrefix; ///< Passed along to the mounting shape to modify /// animation sequences played in 3rd person. [optional] @@ -556,7 +556,7 @@ public: F32 shadowProjectionDistance; F32 shadowSphereAdjust; - DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, Shape) + AssetRef shapeAssetRef; StringTableEntry cloakTexName; @@ -572,7 +572,7 @@ public: DebrisData * debris; S32 debrisID; - DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, DebrisShape) + AssetRef debrisShapeAssetRef; ExplosionData* explosion; S32 explosionID; diff --git a/Engine/source/T3D/shapeImage.cpp b/Engine/source/T3D/shapeImage.cpp index 79b218f11..c613f5268 100644 --- a/Engine/source/T3D/shapeImage.cpp +++ b/Engine/source/T3D/shapeImage.cpp @@ -293,7 +293,7 @@ ShapeBaseImageData::ShapeBaseImageData() isAnimated[i] = false; hasFlash[i] = false; shapeIsValid[i] = false; - mShapeAsset[i].registerRefreshNotify(this); + shapeAssetRef[i].assetPtr.registerRefreshNotify(this); } shakeCamera = false; @@ -439,7 +439,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) if (i == FirstPersonImageShape) { - if ((useEyeOffset || useEyeNode) && !mShapeAsset[i].isNull()) + if ((useEyeOffset || useEyeNode) && !shapeAssetRef[i].isNull()) { // Make use of the first person shape useFirstPersonShape = true; @@ -451,21 +451,22 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) } } - if (!mShapeAsset[i].isNull()) + if (shapeAssetRef[i].notNull()) { - if (!bool(getShape(i))) { - errorStr = String::ToString("Unable to load shape asset: %s", mShapeAsset[i]->getAssetId()); + Resource shape = shapeAssetRef[i].assetPtr->getShapeResource(); + if (!shape) { + errorStr = String::ToString("ShapeBaseImageData(%s)::preload: Couldn't to load shape asset: %s", getName(), shapeAssetRef[i].assetId); return false; } if(computeCRC) { - Con::printf("Validation required for shape asset: %s", mShapeAsset[i]->getAssetId()); + Con::printf("ShapeBaseImageData(%s)::preload: Validation required for shape asset: %s", getName(), shapeAssetRef[i].assetId); - Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(getShapeFile(i)); + Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(shapeAssetRef[i].assetPtr->getShapeFile()); if (!fileRef) { - errorStr = String::ToString("ShapeBaseImageData: Couldn't load shape asset\"%s\"", mShapeAsset[i]->getAssetId()); + errorStr = String::ToString("ShapeBaseImageData(%s)::preload: Couldn't find shape asset \"%s\"'s file", getName(), shapeAssetRef[i].assetId); return false; } @@ -475,29 +476,29 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) } else if(mCRC[i] != fileRef->getChecksum()) { - errorStr = String::ToString("Shape asset\"%s\" does not match version on server.", mShapeAsset[i]->getAssetId()); + errorStr = String::ToString("ShapeBaseImageData(%s)::preload: Shape asset\"%s\" does not match version on server.", getName(), shapeAssetRef[i].assetId); return false; } } // Resolve nodes & build mount transform - eyeMountNode[i] = getShape(i)->findNode("eyeMount"); - eyeNode[i] = getShape(i)->findNode("eye"); + eyeMountNode[i] = shape->findNode("eyeMount"); + eyeNode[i] = shape->findNode("eye"); if (eyeNode[i] == -1) eyeNode[i] = eyeMountNode[i]; - ejectNode[i] = getShape(i)->findNode("ejectPoint"); - muzzleNode[i] = getShape(i)->findNode("muzzlePoint"); - retractNode[i] = getShape(i)->findNode("retractionPoint"); + ejectNode[i] = shape->findNode("ejectPoint"); + muzzleNode[i] = shape->findNode("muzzlePoint"); + retractNode[i] = shape->findNode("retractionPoint"); mountTransform[i] = mountOffset; - S32 node = getShape(i)->findNode("mountPoint"); + S32 node = shape->findNode("mountPoint"); if (node != -1) { MatrixF total(1); do { MatrixF nmat; QuatF q; - TSTransform::setMatrix(getShape(i)->defaultRotations[node].getQuatF(&q), getShape(i)->defaultTranslations[node],&nmat); + TSTransform::setMatrix(shape->defaultRotations[node].getQuatF(&q), shape->defaultTranslations[node],&nmat); total.mul(nmat); - node = getShape(i)->nodes[node].parentIndex; + node = shape->nodes[node].parentIndex; } while(node != -1); total.inverse(); @@ -510,7 +511,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] = getShape(i)->findSequence(stateSequence[j]); + s.sequence[i] = shape->findSequence(stateSequence[j]); if (s.sequence[i] != -1) { // This state has an animation sequence @@ -521,7 +522,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) char bufferVis[128]; dStrncpy(bufferVis, stateSequence[j], 100); dStrcat(bufferVis, "_vis", 128); - s.sequenceVis[i] = getShape(i)->findSequence(bufferVis); + s.sequenceVis[i] = shape->findSequence(bufferVis); } if (s.sequenceVis[i] != -1) { @@ -533,13 +534,13 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) s.ignoreLoadedForReady = stateIgnoreLoadedForReady[j]; if (stateEmitterNode[j] && stateEmitterNode[j][0]) - s.emitterNode[i] = getShape(i)->findNode(stateEmitterNode[j]); + s.emitterNode[i] = shape->findNode(stateEmitterNode[j]); if (s.emitterNode[i] == -1) s.emitterNode[i] = muzzleNode[i]; } - ambientSequence[i] = getShape(i)->findSequence("ambient"); - spinSequence[i] = getShape(i)->findSequence("spin"); + ambientSequence[i] = shape->findSequence("ambient"); + spinSequence[i] = shape->findSequence("spin"); shapeIsValid[i] = true; } @@ -564,7 +565,9 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr) { if( shapeIsValid[i] ) { - TSShapeInstance* pDummy = new TSShapeInstance(getShape(i), !server); + Resource shape = shapeAssetRef[i].assetPtr->getShapeResource(); + + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); delete pDummy; } } @@ -625,7 +628,9 @@ void ShapeBaseImageData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(Shape, MaxShapes, ShapeBaseImageData, "The shape assets for this shape image") + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, ShapeBaseImageData)) + .doc("The shape assets for this shape image") + .elements(MaxShapes); addField("casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData), "@brief DebrisData datablock to use for ejected casings.\n\n" @@ -999,7 +1004,10 @@ void ShapeBaseImageData::packData(BitStream* stream) } } - PACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes); // shape 0 for normal use, shape 1 for first person use (optional) + for (U32 j = 0; j < MaxShapes; ++j) + { + AssetDatabase.packDataAsset(stream, shapeAssetRef[j].assetId); // shape 0 for normal use, shape 1 for first person use (optional) + } stream->writeString(imageAnimPrefix); stream->writeString(imageAnimPrefixFP); @@ -1180,7 +1188,10 @@ void ShapeBaseImageData::unpackData(BitStream* stream) } } - UNPACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes); // shape 0 for normal use, shape 1 for first person use (optional) + for (U32 j = 0; j < MaxShapes; ++j) + { + shapeAssetRef[j] = AssetDatabase.unpackDataAsset(stream); + } imageAnimPrefix = stream->readSTString(); imageAnimPrefixFP = stream->readSTString(); @@ -2139,9 +2150,17 @@ S32 ShapeBase::getNodeIndex(U32 imageSlot,StringTableEntry nodeName) { MountedImage& image = mMountedImageList[imageSlot]; if (image.dataBlock) - return image.dataBlock->getShape(getImageShapeIndex(image))->findNode(nodeName); - else - return -1; + { + U32 imageShapeidx = getImageShapeIndex(image); + if (image.dataBlock->shapeAssetRef[imageShapeidx].notNull()) + { + Resource shape = image.dataBlock->shapeAssetRef[imageShapeidx].assetPtr->getShapeResource(); + if (shape) + return shape->findNode(nodeName); + } + } + + return -1; } // Modify muzzle if needed to aim at whatever is straight in front of the camera. Let the @@ -2329,7 +2348,10 @@ void ShapeBase::setImage( U32 imageSlot, for (U32 i=0; ishapeIsValid[i]) - image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->getShape(i), isClientObject()); + { + Resource shape = image.dataBlock->shapeAssetRef[i].assetPtr->getShapeResource(); + image.shapeInstance[i] = new TSShapeInstance(shape, isClientObject()); + } } if (isClientObject()) diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index a6a39a4ce..2c4b7fc14 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -152,14 +152,14 @@ TSStatic::TSStatic() mAnimOffset = 0.0f; mAnimSpeed = 1.0f; - mShapeAsset.registerRefreshNotify(this); + mShapeAssetRef.assetPtr.registerRefreshNotify(this); } TSStatic::~TSStatic() { delete mConvexList; mConvexList = NULL; - mShapeAsset.unregisterRefreshNotify(); + if (mCubeReflector) { mCubeReflector->unregisterReflector(); @@ -187,7 +187,9 @@ void TSStatic::initPersistFields() docsURL; addGroup("Shape"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, TSStatic, "Model to use for this TSStatic"); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, TSStatic)) + .doc("Model to use for this TSStatic") + .network(AdvancedStaticOptionsMask); endGroup("Shape"); @@ -403,17 +405,26 @@ bool TSStatic::_createShape() mAmbientThread = NULL; //mShape = NULL; - if (getShape()) + if (mShapeAssetRef.assetId == StringTable->EmptyString()) + return false; + + Resource shape; + if (!mShapeAssetRef.assetPtr.isValid()) + shape = ShapeAsset::smNoShapeAssetFallbackAssetPtr->getShapeResource(); + else + shape = mShapeAssetRef.assetPtr->getShapeResource(); + + if (shape) { if (isClientObject() && - !getShape()->preloadMaterialList(getShapeFile()) && + !mShapeAssetRef.assetPtr->preloadMaterialList() && NetConnection::filesWereDownloaded()) return false; - mObjBox = getShape()->mBounds; + mObjBox = shape->mBounds; resetWorldBox(); - mShapeInstance = new TSShapeInstance(getShape(), true); + mShapeInstance = new TSShapeInstance(shape, true); mShapeInstance->resetMaterialList(); mShapeInstance->cloneMaterialList(); @@ -429,7 +440,7 @@ bool TSStatic::_createShape() prepCollision(); // Find the "ambient" animation if it exists - S32 ambientSeq = getShape()->findSequence("ambient"); + S32 ambientSeq = shape->findSequence("ambient"); if (ambientSeq > -1 && !mAmbientThread) mAmbientThread = mShapeInstance->addThread(); @@ -449,77 +460,13 @@ bool TSStatic::_createShape() } else { - Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId()); + Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAssetRef.assetId); return false; } - //Set up the material slot vars for easy manipulation - /*S32 materialCount = mShape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount(); - - //Temporarily disabled until fixup of materialName->assetId lookup logic is sorted for easy persistance - if (isServerObject()) - { - char matFieldName[128]; - - for (U32 i = 0; i < materialCount; i++) - { - StringTableEntry materialname = StringTable->insert(mShape->materialList->getMaterialName(i).c_str()); - - dSprintf(matFieldName, 128, "MaterialSlot%d", i); - StringTableEntry matFld = StringTable->insert(matFieldName); - - setDataField(matFld, NULL, materialname); - } - }*/ - return true; } -void TSStatic::onDynamicModified(const char* slotName, const char* newValue) -{ - if (FindMatch::isMatch("materialslot*", slotName, false)) - { - if (!getShape()) - return; - - S32 slot = -1; - String outStr(String::GetTrailingNumber(slotName, slot)); - - if (slot == -1) - return; - - //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name - MaterialAsset* matAsset = AssetDatabase.acquireAsset(newValue); - if (!matAsset) - return; - - bool found = false; - for (U32 i = 0; i < mChangingMaterials.size(); i++) - { - if (mChangingMaterials[i].slot == slot) - { - mChangingMaterials[i].matAsset = matAsset; - mChangingMaterials[i].assetId = newValue; - found = true; - } - } - - if (!found) - { - matMap newMatMap; - newMatMap.slot = slot; - newMatMap.matAsset = matAsset; - newMatMap.assetId = newValue; - - mChangingMaterials.push_back(newMatMap); - } - - setMaskBits(MaterialMask); - } - - Parent::onDynamicModified(slotName, newValue); -} - void TSStatic::prepCollision() { // Let the client know that the collision was updated @@ -536,22 +483,24 @@ void TSStatic::prepCollision() mLOSDetails.clear(); mConvexList->nukeList(); + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh) { - getShape()->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD); + shape->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD); if (mDecalType == mCollisionType) { mDecalDetailsPtr = &mCollisionDetails; } else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) { - getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); + shape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); mDecalDetailsPtr = &mDecalDetails; } } else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) { - getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); + shape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD); mDecalDetailsPtr = &mDecalDetails; } @@ -565,16 +514,18 @@ void TSStatic::_updatePhysics() if (!PHYSICSMGR || mCollisionType == None) return; + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + PhysicsCollision* colShape = NULL; if (mCollisionType == Bounds) { MatrixF offset(true); - offset.setPosition(getShape()->center); + offset.setPosition(shape->center); colShape = PHYSICSMGR->createCollision(); colShape->addBox(getObjBox().getExtents() * 0.5f * mObjScale, offset); } else - colShape = getShape()->buildColShape(mCollisionType == VisibleMesh, getScale()); + colShape = shape->buildColShape(mCollisionType == VisibleMesh, getScale()); if (colShape) { @@ -727,7 +678,7 @@ void TSStatic::_updateShouldTick() void TSStatic::prepRenderImage(SceneRenderState* state) { - if (!mShapeAsset.isValid() || !mShapeInstance) + if (!mShapeAssetRef.isValid() || !mShapeInstance) return; Point3F cameraOffset; @@ -967,7 +918,7 @@ U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream) if (stream->writeFlag(mask & AdvancedStaticOptionsMask)) { - PACK_ASSET_REFACTOR(con, Shape); + AssetDatabase.packUpdateAsset(con, mask, stream, mShapeAssetRef.assetId); stream->writeInt(mDecalType,4); @@ -1086,7 +1037,7 @@ void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream) if (stream->readFlag()) // AdvancedStaticOptionsMask { - UNPACK_ASSET_REFACTOR(con, Shape); + mShapeAssetRef = AssetDatabase.unpackUpdateAsset(con, stream); mDecalType = (MeshType)stream->readInt(4); @@ -1611,10 +1562,10 @@ void TSStatic::updateMaterials() TSMaterialList* pMatList = mShapeInstance->getMaterialList(); String path; - if (mShapeAsset->isAssetValid()) - path = mShapeAsset->getShapeFile(); + if (mShapeAssetRef.assetPtr->isAssetValid()) + path = mShapeAssetRef.assetPtr->getShapeFile(); else - path = mShapeFile; + return; pMatList->setTextureLookupPath(path); @@ -1643,10 +1594,10 @@ void TSStatic::updateMaterials() void TSStatic::getUtilizedAssets(Vector* usedAssetsList) { - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAssetRef.assetPtr); if (assetStatus == AssetBase::Ok) { - usedAssetsList->push_back_unique(mShapeAsset->getAssetId()); + usedAssetsList->push_back_unique(mShapeAssetRef.assetId); } } @@ -1796,7 +1747,16 @@ DefineEngineMethod(TSStatic, changeMaterial, void, (const char* mapTo, Material* return; } - TSMaterialList* shapeMaterialList = object->getShape()->materialList; + const AssetPtr shapeAsset = object->getShapeAsset(); + + if (shapeAsset.isNull()) + return; + + Resource shape = shapeAsset->getShapeResource(); + if (!shape) + return; + + TSMaterialList* shapeMaterialList = shape->materialList; // Check the mapTo name exists for this shape S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo)); @@ -1836,7 +1796,11 @@ DefineEngineMethod(TSStatic, getModelFile, const char*, (), , "@endtsexample\n" ) { - return object->getShapeFile(); + const AssetPtr shapeAsset = object->getShapeAsset(); + if (shapeAsset.isNull()) + return ""; + + return shapeAsset->getShapeFile(); } void TSStatic::set_special_typing() @@ -1880,15 +1844,27 @@ void TSStatic::setSelectionFlags(U8 flags) bool TSStatic::hasNode(const char* nodeName) { + if (mShapeAssetRef.isNull()) + return false; - S32 nodeIDx = getShape()->findNode(nodeName); + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return false; + + S32 nodeIDx = shape->findNode(nodeName); return nodeIDx >= 0; } void TSStatic::getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat) { + if (mShapeAssetRef.isNull()) + return; - S32 nodeIDx = getShape()->findNode(nodeName); + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return; + + S32 nodeIDx = shape->findNode(nodeName); MatrixF nodeTransform(xfm); const Point3F& scale = getScale(); diff --git a/Engine/source/T3D/tsStatic.h b/Engine/source/T3D/tsStatic.h index 7ab21ba0a..626eabb16 100644 --- a/Engine/source/T3D/tsStatic.h +++ b/Engine/source/T3D/tsStatic.h @@ -176,8 +176,6 @@ protected: void interpolateTick(F32 delta) override; void advanceTime(F32 dt) override; - void onDynamicModified(const char* slotName, const char* newValue) override; - /// Start or stop processing ticks depending on our state. void _updateShouldTick(); @@ -196,7 +194,7 @@ protected: Convex* mConvexList; - DECLARE_SHAPEASSET_NET_REFACTOR(TSStatic, Shape, AdvancedStaticOptionsMask) + AssetRef mShapeAssetRef; U32 mShapeHash; Vector mCollisionDetails; @@ -244,7 +242,7 @@ public: DECLARE_CATEGORY("Object \t Simple"); static void initPersistFields(); /// returns the shape asset used for this object - StringTableEntry getTypeHint() const override { return (mShapeAsset.notNull()) ? mShapeAsset->getAssetName(): StringTable->EmptyString(); } + StringTableEntry getTypeHint() const override { return (mShapeAssetRef.notNull()) ? mShapeAssetRef.assetPtr->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); @@ -289,6 +287,8 @@ public: void getUtilizedAssets(Vector* usedAssetsList) override; + const AssetPtr& getShapeAsset() const { return mShapeAssetRef.assetPtr; } + private: void onStaticModified(const char* slotName, const char* newValue = NULL) override; protected: diff --git a/Engine/source/T3D/turret/aiTurretShape.cpp b/Engine/source/T3D/turret/aiTurretShape.cpp index cedb51af2..0b307ea2d 100644 --- a/Engine/source/T3D/turret/aiTurretShape.cpp +++ b/Engine/source/T3D/turret/aiTurretShape.cpp @@ -245,9 +245,11 @@ bool AITurretShapeData::preload(bool server, String &errorStr) if (!Parent::preload(server, errorStr)) return false; + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + // We have mShape at this point. Resolve nodes. - scanNode = getShape()->findNode("scanPoint"); - aimNode = getShape()->findNode("aimPoint"); + scanNode = shape->findNode("scanPoint"); + aimNode = shape->findNode("aimPoint"); if (scanNode == -1) scanNode = pitchNode; if (scanNode == -1) scanNode = headingNode; @@ -259,7 +261,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 = getShape()->findSequence(stateSequence[j]); + s.sequence = shape->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 ea32f975f..16d39d58d 100644 --- a/Engine/source/T3D/turret/turretShape.cpp +++ b/Engine/source/T3D/turret/turretShape.cpp @@ -216,36 +216,43 @@ bool TurretShapeData::preload(bool server, String &errorStr) if (!Parent::preload(server, errorStr)) return false; + if (shapeAssetRef.isNull()) + return false; + + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + return false; + // We have mShape at this point. Resolve nodes. - headingNode = getShape()->findNode("heading"); - pitchNode = getShape()->findNode("pitch"); + headingNode = shape->findNode("heading"); + pitchNode = shape->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] = getShape()->findNode(name); + pitchNodes[i] = shape->findNode(name); dSprintf(name, 31, "heading%d", i+1); - headingNodes[i] = getShape()->findNode(name); + headingNodes[i] = shape->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] = getShape()->findNode(fullName); + weaponMountNode[i] = shape->findNode(fullName); } // Recoil animations - recoilSequence[0] = getShape()->findSequence("light_recoil"); - recoilSequence[1] = getShape()->findSequence("medium_recoil"); - recoilSequence[2] = getShape()->findSequence("heavy_recoil"); + recoilSequence[0] = shape->findSequence("light_recoil"); + recoilSequence[1] = shape->findSequence("medium_recoil"); + recoilSequence[2] = shape->findSequence("heavy_recoil"); // Optional sequences used when the turret rotates - pitchSequence = getShape()->findSequence("pitch"); - headingSequence = getShape()->findSequence("heading"); + pitchSequence = shape->findSequence("pitch"); + headingSequence = shape->findSequence("heading"); return true; } diff --git a/Engine/source/T3D/vehicles/flyingVehicle.cpp b/Engine/source/T3D/vehicles/flyingVehicle.cpp index 6dfe8d8de..6d0de749f 100644 --- a/Engine/source/T3D/vehicles/flyingVehicle.cpp +++ b/Engine/source/T3D/vehicles/flyingVehicle.cpp @@ -135,7 +135,9 @@ bool FlyingVehicleData::preload(bool server, String &errorStr) if (!Parent::preload(server, errorStr)) return false; - TSShapeInstance* si = new TSShapeInstance(getShape(), false); + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + + TSShapeInstance* si = new TSShapeInstance(shape, false); // Resolve objects transmitted from server if (!server) { @@ -165,7 +167,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr) // Resolve jet nodes for (S32 j = 0; j < MaxJetNodes; j++) - jetNode[j] = getShape()->findNode(sJetNode[j]); + jetNode[j] = shape->findNode(sJetNode[j]); // maxSpeed = maneuveringForce / minDrag; diff --git a/Engine/source/T3D/vehicles/hoverVehicle.cpp b/Engine/source/T3D/vehicles/hoverVehicle.cpp index 43321abc3..d7a6bef83 100644 --- a/Engine/source/T3D/vehicles/hoverVehicle.cpp +++ b/Engine/source/T3D/vehicles/hoverVehicle.cpp @@ -332,9 +332,12 @@ bool HoverVehicleData::preload(bool server, String &errorStr) return false; } } + + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + // Resolve jet nodes for (S32 j = 0; j < MaxJetNodes; j++) - jetNode[j] = getShape()->findNode(sJetNode[j]); + jetNode[j] = shape->findNode(sJetNode[j]); return true; } diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index fa7b5b160..2fb632113 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\"", getShapeAsset().getAssetId()); + errorStr = String::ToString("VehicleData: Couldn't load shape asset \"%s\"", shapeAssetRef.assetId); return false; } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.cpp b/Engine/source/T3D/vehicles/wheeledVehicle.cpp index dec634690..212822e7b 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.cpp +++ b/Engine/source/T3D/vehicles/wheeledVehicle.cpp @@ -86,24 +86,28 @@ WheeledVehicleTire::WheeledVehicleTire() longitudinalDamping = 1; longitudinalRelaxation = 1; mass = 1.f; - mShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.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 (!getShape()) + if (!shapeAssetRef.isNull()) { - errorStr = String::ToString("WheeledVehicleTire: Couldn't load shape \"%s\"", _getShapeAssetId()); - return false; - } - else - { - // Determinw wheel radius from the shape's bounding box. + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + // 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 = getShape()->mBounds.len_z() / 2; + radius = shape->mBounds.len_z() / 2; + } + else + { + errorStr = String::ToString("WheeledVehicleTire::preload Couldn't load shape \"%s\"", shapeAssetRef.assetId); + return false; + } } return true; @@ -112,7 +116,8 @@ bool WheeledVehicleTire::preload(bool server, String &errorStr) void WheeledVehicleTire::initPersistFields() { docsURL; - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, WheeledVehicleTire, "The shape to use for the wheel."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, WheeledVehicleTire)) + .doc("The shape to use for the wheel."); addFieldV( "mass", TypeRangedF32, Offset(mass, WheeledVehicleTire), &CommonValidators::PositiveFloat, "The mass of the wheel.\nCurrently unused." ); @@ -177,7 +182,7 @@ void WheeledVehicleTire::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); stream->write(mass); stream->write(staticFriction); @@ -196,7 +201,7 @@ void WheeledVehicleTire::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); stream->read(&mass); stream->read(&staticFriction); @@ -340,9 +345,11 @@ bool WheeledVehicleData::preload(bool server, String &errorStr) if (!Parent::preload(server, errorStr)) return false; + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + // A temporary shape instance is created so that we can // animate the shape and extract wheel information. - TSShapeInstance* si = new TSShapeInstance(getShape(), false); + TSShapeInstance* si = new TSShapeInstance(shape, false); // Resolve objects transmitted from server if (!server) { @@ -367,14 +374,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 = getShape()->findNode(buff); + wp->springNode = shape->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 = getShape()->findSequence(buff); + wp->springSequence = shape->findSequence(buff); if (wp->springSequence == -1) si->mNodeTransforms[wp->springNode].getColumn(3, &wp->pos); else { @@ -403,17 +410,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 = getShape()->findSequence("steering"); + steeringSequence = shape->findSequence("steering"); // Brakes - brakeLightSequence = getShape()->findSequence("brakelight"); + brakeLightSequence = shape->findSequence("brakelight"); // Extract collision planes from shape collision detail level if (collisionDetails[0] != -1) { MatrixF imat(1); SphereF sphere; - sphere.center = getShape()->center; - sphere.radius = getShape()->mRadius; + sphere.center = shape->center; + sphere.radius = shape->mRadius; PlaneExtractorPolyList polyList; polyList.mPlaneList = &rigidBody.mPlaneList; polyList.setTransform(&imat, Point3F(1,1,1)); @@ -1581,8 +1588,15 @@ void WheeledVehicle::unpackUpdate(NetConnection *con, BitStream *stream) // Create an instance of the tire for rendering delete wheel->shapeInstance; - wheel->shapeInstance = (wheel->tire->getShape() == NULL) ? 0: - new TSShapeInstance(wheel->tire->getShape()); + + if (wheel->tire->shapeAssetRef.notNull()) + { + Resource shape = wheel->tire->shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + wheel->shapeInstance = new TSShapeInstance(shape); + } + } } } } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.h b/Engine/source/T3D/vehicles/wheeledVehicle.h index 17164a286..b701257f6 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.h +++ b/Engine/source/T3D/vehicles/wheeledVehicle.h @@ -43,7 +43,7 @@ struct WheeledVehicleTire: public SimDataBlock, protected AssetPtrCallback { typedef SimDataBlock Parent; - DECLARE_SHAPEASSET_REFACTOR(WheeledVehicleTire, Shape) + AssetRef shapeAssetRef; // Physical properties F32 mass; // Mass of the whole wheel diff --git a/Engine/source/afx/afxMagicMissile.cpp b/Engine/source/afx/afxMagicMissile.cpp index 645ca4d32..7f9f1d278 100644 --- a/Engine/source/afx/afxMagicMissile.cpp +++ b/Engine/source/afx/afxMagicMissile.cpp @@ -241,13 +241,13 @@ afxMagicMissileData::afxMagicMissileData() caster_safety_time = U32_MAX; - mProjectileShapeAsset.registerRefreshNotify(this); + projectileShapeAssetRef.assetPtr.registerRefreshNotify(this); projectileShape = NULL; } afxMagicMissileData::afxMagicMissileData(const afxMagicMissileData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - mProjectileShapeAsset = other.mProjectileShapeAsset; + projectileShapeAssetRef = other.projectileShapeAssetRef; projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName CLONE_ASSET(ProjectileSound); splash = other.splash; @@ -307,8 +307,6 @@ afxMagicMissileData::~afxMagicMissileData() { if (wiggle_axis) delete [] wiggle_axis; - - mProjectileShapeAsset.unregisterRefreshNotify(); } afxMagicMissileData* afxMagicMissileData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) @@ -338,7 +336,8 @@ void afxMagicMissileData::initPersistFields() static IRangeValidatorScaled ticksFromMS(TickMs, 0, MaxLifetimeTicks); addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(ProjectileShape, afxMagicMissileData, "Shape for the projectile"); + ADD_FIELD("projectileShapeAsset", TypeShapeAssetRef, Offset(projectileShapeAssetRef, afxMagicMissileData)) + .doc("Shape for the projectile"); addField("scale", TypePoint3F, Offset(scale, afxMagicMissileData)); addField("missileShapeScale", TypePoint3F, myOffset(scale)); endGroup("Shapes"); @@ -531,16 +530,20 @@ bool afxMagicMissileData::preload(bool server, String &errorStr) if (Sim::findObject(lightDescId, lightDesc) == false) Con::errorf(ConsoleLogEntry::General, "afxMagicMissileData::preload: Invalid packet, bad datablockid(lightDesc): %d", lightDescId); } - - if (getProjectileShape()) + + if (projectileShapeAssetRef.notNull()) { - TSShapeInstance* pDummy = new TSShapeInstance(getProjectileShape(), !server); - delete pDummy; - } - else if (mProjectileShapeAsset.notNull()) - { - errorStr = String::ToString("afxMagicMissileData::preload: Couldn't load shape \"%s\"", _getProjectileShapeAssetId()); - return false; + Resource shape = projectileShapeAssetRef.assetPtr->getShapeResource(); + if (shape) + { + TSShapeInstance* pDummy = new TSShapeInstance(shape, !server); + delete pDummy; + } + else + { + errorStr = String::ToString("afxMagicMissileData(%s)::preload: Couldn't load shape \"%s\"", getName(), projectileShapeAssetRef.assetId); + return false; + } } return true; @@ -580,7 +583,7 @@ void afxMagicMissileData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET_REFACTOR(ProjectileShape); + AssetDatabase.packDataAsset(stream, projectileShapeAssetRef.assetId); /* From stock Projectile code... stream->writeFlag(faceViewer); @@ -691,7 +694,7 @@ void afxMagicMissileData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(ProjectileShape); + projectileShapeAssetRef = AssetDatabase.unpackDataAsset(stream); /* From stock Projectile code... faceViewer = stream->readFlag(); */ diff --git a/Engine/source/afx/afxMagicMissile.h b/Engine/source/afx/afxMagicMissile.h index 15c8b2b71..fcd03f7c9 100644 --- a/Engine/source/afx/afxMagicMissile.h +++ b/Engine/source/afx/afxMagicMissile.h @@ -69,7 +69,7 @@ public: public: // variables set in datablock definition: // Shape related - DECLARE_SHAPEASSET_REFACTOR(afxMagicMissileData, ProjectileShape) + AssetRef projectileShapeAssetRef; //StringTableEntry projectileShapeName; //bool hasLight; diff --git a/Engine/source/afx/ce/afxModel.cpp b/Engine/source/afx/ce/afxModel.cpp index 4915bae76..b702c5302 100644 --- a/Engine/source/afx/ce/afxModel.cpp +++ b/Engine/source/afx/ce/afxModel.cpp @@ -79,12 +79,12 @@ afxModelData::afxModelData() shadowProjectionDistance = 10.0f; shadowSphereAdjust = 1.0; - mShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.registerRefreshNotify(this); } afxModelData::afxModelData(const afxModelData& other, bool temp_clone) : GameBaseData(other, temp_clone) { - mShapeAsset = other.mShapeAsset; + shapeAssetRef = other.shapeAssetRef; sequence = other.sequence; seq_rate = other.seq_rate; seq_offset = other.seq_offset; @@ -114,8 +114,6 @@ afxModelData::~afxModelData() { if (remap_buffer) dFree(remap_buffer); - - mShapeAsset.unregisterRefreshNotify(); } bool afxModelData::preload(bool server, String &errorStr) @@ -126,8 +124,12 @@ bool afxModelData::preload(bool server, String &errorStr) // don't need to do this stuff on the server if (server) return true; - - if (getShape()) + + if (shapeAssetRef.isNull()) + return false; + + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (shape) { // just parse up the string and collect the remappings in txr_tag_remappings. if (remap_txr_tags != ST_NULLSTRING) @@ -157,13 +159,13 @@ 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(getShape()); + TSShapeInstance* pDummy = new TSShapeInstance(shape); delete pDummy; } } else { - errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", _getShapeAssetId()); + errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", shapeAssetRef.assetId); return false; } return true; @@ -175,7 +177,8 @@ void afxModelData::initPersistFields() { docsURL; addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, afxModelData, "The name of a .dts format file to use for the model."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, afxModelData)) + .doc("The id of a shapeAsset to use for the shape."); endGroup("Shapes"); addGroup("Animation"); @@ -259,7 +262,8 @@ void afxModelData::packData(BitStream* stream) { Parent::packData(stream); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); + stream->writeString(sequence); stream->write(seq_rate); stream->write(seq_offset); @@ -290,7 +294,8 @@ void afxModelData::unpackData(BitStream* stream) { Parent::unpackData(stream); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); + sequence = stream->readSTString(); stream->read(&seq_rate); stream->read(&seq_offset); @@ -319,9 +324,15 @@ void afxModelData::unpackData(BitStream* stream) void afxModelData::onPerformSubstitutions() { - if (!getShape()) + if (!shapeAssetRef.isNull()) { - Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", _getShapeAssetId()); + Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape asset \"%s\"", shapeAssetRef.assetId); + } + + Resource shape = shapeAssetRef.assetPtr->getShapeResource(); + if (!shape) + { + Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", shapeAssetRef.assetId); return; } } @@ -395,19 +406,22 @@ bool afxModel::onAdd() if (!conn || !Parent::onAdd()) return false; - // setup our bounding box - if (mDataBlock->getShape()) - mObjBox = mDataBlock->getShape()->mBounds; - else - mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); + Resource shape; + mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); + if (!mDataBlock->shapeAssetRef.isNull()) + { + shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource(); + if (shape) + mObjBox = shape->mBounds; + } // setup the shape instance and sequence - if (mDataBlock->getShape()) + if (shape) { if (/*isClientObject() && */mDataBlock->txr_tag_remappings.size() > 0) { // temporarily substitute material tags with alternates - TSMaterialList* mat_list = mDataBlock->getShape()->materialList; + TSMaterialList* mat_list = shape->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -428,7 +442,7 @@ bool afxModel::onAdd() } } - shape_inst = new TSShapeInstance(mDataBlock->getShape()); + shape_inst = new TSShapeInstance(shape); if (true) // isClientObject()) { @@ -437,7 +451,7 @@ bool afxModel::onAdd() // restore the material tags to original form if (mDataBlock->txr_tag_remappings.size() > 0) { - TSMaterialList* mat_list = mDataBlock->getShape()->materialList; + TSMaterialList* mat_list = shape->materialList; if (mat_list) { for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) @@ -466,7 +480,6 @@ bool afxModel::onAdd() else { // here we start the default animation sequence - TSShape* shape = shape_inst->getShape(); main_seq_id = shape->findSequence(mDataBlock->sequence); if (main_seq_id != -1) { @@ -503,14 +516,14 @@ bool afxModel::onAdd() resetWorldBox(); - if (mDataBlock->getShape()) + if (shape) { // Scan out the collision hulls... static const String sCollisionStr( "collision-" ); - for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++) + for (U32 i = 0; i < shape->details.size(); i++) { - const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex]; + const String &name = shape->names[shape->details[i].nameIndex]; if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0) { @@ -524,7 +537,7 @@ bool afxModel::onAdd() char buff[128]; dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + 8/*MaxCollisionShapes*/); - U32 los = mDataBlock->getShape()->findDetail(buff); + U32 los = shape->findDetail(buff); if (los == -1) mLOSDetails.last() = i; else @@ -535,9 +548,9 @@ bool afxModel::onAdd() // Snag any "unmatched" LOS details static const String sLOSStr( "LOS-" ); - for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++) + for (U32 i = 0; i < shape->details.size(); i++) { - const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex]; + const String &name = shape->names[shape->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 ce7fb19ac..b57683731 100644 --- a/Engine/source/afx/ce/afxModel.h +++ b/Engine/source/afx/ce/afxModel.h @@ -43,7 +43,7 @@ struct afxModelData : public GameBaseData, protected AssetPtrCallback { typedef GameBaseData Parent; - DECLARE_SHAPEASSET_REFACTOR(afxModelData, Shape) + AssetRef shapeAssetRef; StringTableEntry sequence; @@ -155,9 +155,21 @@ public: void setSequenceRateFactor(F32 factor); void setSortPriority(S8 priority) { sort_priority = priority; } - const char* getShapeFileName() const { return mDataBlock->getShapeFile(); } + const char* getShapeFileName() const + { + if (mDataBlock->shapeAssetRef.isNull()) + return ""; + + return mDataBlock->shapeAssetRef.assetPtr->getShapeFile(); + } void setVisibility(bool flag) { is_visible = flag; } - TSShape* getTSShape() { return mDataBlock->getShape(); } + TSShape* getTSShape() + { + if (mDataBlock->shapeAssetRef.isNull()) + return nullptr; + + return mDataBlock->shapeAssetRef.assetPtr->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 fce335f90..ea31a2383 100644 --- a/Engine/source/afx/ce/afxStaticShape.h +++ b/Engine/source/afx/ce/afxStaticShape.h @@ -85,7 +85,13 @@ public: U32 packUpdate(NetConnection*, U32, BitStream*) override; void unpackUpdate(NetConnection*, BitStream*) override; - const char* getShapeFileName() const { return mDataBlock->getShapeFile(); } + const char* getShapeFileName() const + { + if (mDataBlock->shapeAssetRef.isNull()) + return ""; + + return mDataBlock->shapeAssetRef.assetPtr->getShapeFile(); + } void setVisibility(bool flag) { mIs_visible = flag; } DECLARE_CONOBJECT(afxStaticShape); diff --git a/Engine/source/assets/assetPtr.h b/Engine/source/assets/assetPtr.h index 5d5f4173f..4271d0df9 100644 --- a/Engine/source/assets/assetPtr.h +++ b/Engine/source/assets/assetPtr.h @@ -182,4 +182,54 @@ public: bool isValid(void) const { return notNull() && static_cast(mpAsset.getObject())->isAssetValid(); } }; +//----------------------------------------------------------------------------- +// AssetRef is a simple struct that contains an asset Id and an AssetPtr. +// This is used in cases where we want to be able to track the asset Id even if the asset pointer is null (e.g. when the asset fails to load and we want to keep the asset Id around so that we can retry loading it later). +//----------------------------------------------------------------------------- +template +struct AssetRef +{ + StringTableEntry assetId; + AssetPtr assetPtr; + + AssetRef() + { + assetId = StringTable->EmptyString(); + } + AssetRef& operator=(const char* pAssetId) + { + assetId = StringTable->insert(pAssetId); + assetPtr = pAssetId; + + // Return Reference. + return *this; + } + AssetRef& operator=(const AssetPtr& pAssetPtr) + { + if (pAssetPtr.notNull()) + assetId = StringTable->insert(pAssetPtr->getAssetId()); + + assetPtr = pAssetPtr; + + // Return Reference. + return *this; + } + AssetRef& operator=(const AssetRef& pAssetRef) + { + assetId = pAssetRef.assetId; + assetPtr = pAssetRef.assetPtr; + + // Return Reference. + return *this; + } + + StringTableEntry getAssetId(void) const { return assetId; } + bool isAssetId(const char* pAssetId) const { return assetId == StringTable->insert(pAssetId); } + bool hasAssetId() const { return assetId != StringTable->EmptyString(); } + + /// Validity. + bool isNull(void) const { return assetPtr.isNull(); } + bool notNull(void) const { return !assetPtr.isNull(); } + bool isValid(void) const { return notNull() && static_cast(assetPtr)->isAssetValid(); } +}; #endif // _ASSET_PTR_H_ diff --git a/Engine/source/environment/VolumetricFog.cpp b/Engine/source/environment/VolumetricFog.cpp index be8b8a2cc..4243b7514 100644 --- a/Engine/source/environment/VolumetricFog.cpp +++ b/Engine/source/environment/VolumetricFog.cpp @@ -162,7 +162,9 @@ void VolumetricFog::initPersistFields() docsURL; Parent::initPersistFields(); addGroup("Shapes"); - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, VolumetricFog, "The source shape asset."); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(mShapeAssetRef, VolumetricFog)) + .doc("The source shape asset.") + .network(FogShapeMask); endGroup("Shapes"); addGroup("VolumetricFogData"); @@ -340,7 +342,7 @@ void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize) bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId) { - _setShape(shapeAssetId); + mShapeAssetRef = shapeAssetId; LoadShape(); return true; @@ -349,27 +351,28 @@ bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId) bool VolumetricFog::LoadShape() { GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip }; - U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); + U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAssetRef.assetPtr); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { Con::errorf("[VolumetricFog] Failed to load shape asset."); return false; } - if (!getShape()) + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + if (!shape) { Con::errorf("VolumetricFog::_createShape() - Shape Asset had no valid shape!"); return false; } - mObjBox = getShape()->mBounds; - mRadius = getShape()->mRadius; + mObjBox = shape->mBounds; + mRadius = shape->mRadius; resetWorldBox(); if (!isClientObject()) return false; - TSShapeInstance *mShapeInstance = new TSShapeInstance(getShape(), false); + TSShapeInstance *mShapeInstance = new TSShapeInstance(shape, false); meshes mesh_detail; for (S32 i = 0; i < det_size.size(); i++) @@ -385,9 +388,9 @@ bool VolumetricFog::LoadShape() // browsing model for detail levels - for (U32 i = 0; i < getShape()->details.size(); i++) + for (U32 i = 0; i < shape->details.size(); i++) { - const TSDetail *detail = &getShape()->details[i]; + const TSDetail *detail = &shape->details[i]; mesh_detail.det_size = detail->size; mesh_detail.sub_shape = detail->subShapeNum; mesh_detail.obj_det = detail->objectDetailNum; @@ -403,8 +406,8 @@ bool VolumetricFog::LoadShape() const S32 ss = det_size[i].sub_shape; if (ss >= 0) { - const S32 start = getShape()->subShapeFirstObject[ss]; - const S32 end = start + getShape()->subShapeNumObjects[ss]; + const S32 start = shape->subShapeFirstObject[ss]; + const S32 end = start + shape->subShapeNumObjects[ss]; for (S32 j = start; j < end; j++) { // Loading shape, only the first mesh for each detail will be used! @@ -566,14 +569,17 @@ U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream) } if (stream->writeFlag(mask & FogShapeMask)) { - PACK_ASSET_REFACTOR(con, Shape); + AssetDatabase.packUpdateAsset(conn, mask, stream, mShapeAssetRef.assetId); + mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); - if (mShapeAsset.notNull()) + if (mShapeAssetRef.isValid()) { - mObjBox = mShapeAsset->getShapeResource()->mBounds; - mRadius = mShapeAsset->getShapeResource()->mRadius; + Resource shape = mShapeAssetRef.assetPtr->getShapeResource(); + + mObjBox = shape->mBounds; + mRadius = shape->mRadius; } else { @@ -595,8 +601,8 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) VectorF scale; VectorF mOldScale = getScale(); StringTableEntry oldTextureName = mTextureAsset.getAssetId(); - StringTableEntry oldShapeAsset = _getShapeAssetId(); - StringTableEntry oldShape = getShapeFile(); + StringTableEntry oldShapeAsset = mShapeAssetRef.assetId; + StringTableEntry oldShape = mShapeAssetRef.assetPtr->getShapeFile(); if (stream->readFlag())// Fog color stream->read(&mFogColor); @@ -665,11 +671,11 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) } if (stream->readFlag())//Fog shape { - UNPACK_ASSET_REFACTOR(con, Shape); + mShapeAssetRef = AssetDatabase.unpackUpdateAsset(conn, stream); mathRead(*stream, &mat); mathRead(*stream, &scale); - if (strcmp(oldShapeAsset, _getShapeAssetId()) != 0 || strcmp(oldShape, getShapeFile()) != 0) + if (strcmp(oldShapeAsset, mShapeAssetRef.assetId) != 0 || strcmp(oldShape, mShapeAssetRef.assetPtr->getShapeFile()) != 0) { mIsVBDirty = true; mShapeLoaded = LoadShape(); diff --git a/Engine/source/environment/VolumetricFog.h b/Engine/source/environment/VolumetricFog.h index 76519f654..98021194d 100644 --- a/Engine/source/environment/VolumetricFog.h +++ b/Engine/source/environment/VolumetricFog.h @@ -84,7 +84,7 @@ class VolumetricFog : public SceneObject Vector *indices; }; - DECLARE_SHAPEASSET_REFACTOR(VolumetricFog, Shape) + AssetRef mShapeAssetRef; protected: // Rendertargets; diff --git a/Engine/source/forest/forestItem.cpp b/Engine/source/forest/forestItem.cpp index 36c12e8a7..08ee56f63 100644 --- a/Engine/source/forest/forestItem.cpp +++ b/Engine/source/forest/forestItem.cpp @@ -54,15 +54,15 @@ ForestItemData::ForestItemData() mDampingCoefficient( 0.7f ) { mShape = NULL; - mShapeAsset.registerRefreshNotify(this); + shapeAssetRef.assetPtr.registerRefreshNotify(this); } void ForestItemData::initPersistFields() { docsURL; addGroup( "Shapes" ); - - INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, ForestItemData, "Shape asset for this item type"); + ADD_FIELD("shapeAsset", TypeShapeAssetRef, Offset(shapeAssetRef, ForestItemData)) + .doc("Shape asset for this item type"); endGroup( "Shapes" ); @@ -163,7 +163,7 @@ void ForestItemData::packData(BitStream* stream) stream->write( localName ); - PACKDATA_ASSET_REFACTOR(Shape); + AssetDatabase.packDataAsset(stream, shapeAssetRef.assetId); stream->writeFlag( mCollidable ); @@ -189,7 +189,7 @@ void ForestItemData::unpackData(BitStream* stream) stream->read( &localName ); setInternalName( localName ); - UNPACKDATA_ASSET_REFACTOR(Shape); + shapeAssetRef = AssetDatabase.unpackDataAsset(stream); mCollidable = stream->readFlag(); diff --git a/Engine/source/forest/forestItem.h b/Engine/source/forest/forestItem.h index 3f01571f0..fb2258cf0 100644 --- a/Engine/source/forest/forestItem.h +++ b/Engine/source/forest/forestItem.h @@ -61,8 +61,8 @@ protected: virtual void _preload() {} public: - - DECLARE_SHAPEASSET_REFACTOR(ForestItemData, Shape) + + AssetRef shapeAssetRef; /// This is the radius used during placement to ensure /// the element isn't crowded up against other trees. diff --git a/Engine/source/forest/ts/tsForestItemData.cpp b/Engine/source/forest/ts/tsForestItemData.cpp index e27c4c80e..201cd38e6 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(_getShapeAssetId()); + U32 assetStatus = ShapeAsset::getAssetErrCode(shapeAssetRef.assetPtr); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; } - if ( path != Path(getShapeFile()) ) + if ( path != Path(shapeAssetRef.assetPtr->getShapeFile()) ) return; SAFE_DELETE( mShapeInstance ); @@ -116,8 +116,11 @@ void TSForestItemData::_onResourceChanged( const Torque::Path &path ) void TSForestItemData::_loadShape() { - mShape = getShape(); - U32 assetStatus = ShapeAsset::getAssetErrCode(_getShapeAssetId()); + if (shapeAssetRef.assetPtr.isNull()) + return; + + mShape = shapeAssetRef.assetPtr->getShape(); + U32 assetStatus = ShapeAsset::getAssetErrCode(shapeAssetRef.assetPtr); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; @@ -127,7 +130,7 @@ void TSForestItemData::_loadShape() return; if ( mIsClientObject && - !mShape->preloadMaterialList(getShapeFile()) ) + !mShape->preloadMaterialList(shapeAssetRef.assetPtr->getShapeFile()) ) return; // Lets add an autobillboard detail if don't have one. @@ -165,7 +168,7 @@ TSShapeInstance* TSForestItemData::_getShapeInstance() const void TSForestItemData::_checkLastDetail() { - U32 assetStatus = ShapeAsset::getAssetErrCode(_getShapeAssetId()); + U32 assetStatus = ShapeAsset::getAssetErrCode(shapeAssetRef.assetPtr); if (assetStatus != AssetBase::Ok && assetStatus != AssetBase::UsingFallback) { return; @@ -177,7 +180,7 @@ void TSForestItemData::_checkLastDetail() // TODO: Expose some real parameters to the datablock maybe? if ( detail->subShapeNum != -1 ) { - mShape->addImposter(getShapeFile(), 10, 4, 0, 0, 256, 0, 0); + mShape->addImposter(shapeAssetRef.assetPtr->getShapeFile(), 10, 4, 0, 0, 256, 0, 0); // HACK: If i don't do this it crashes! while ( mShape->detailCollisionAccelerators.size() < mShape->details.size() )