Cleans up ShapeAsset of some unnecessary/redundant elements like extra material and animations tracking

Removed the old SHAPE_ASSET macros
Implements AssetRef struct that acts as a universal wrapper for an templated AssetPtr and AssetId pair
Adds Type handling for AssetRef for ShapeAsset to unify handling in classes that utilize a shapeAsset, so assigning an assetPtr or an assetId will keep a record of the assignment in the event the assetPtr is invalid.
Update all classes that utilized the old SHAPE_ASSET macros to utilize the AssetRef struct and updated the class code to utilize it to provide much more clean and concise code that isn't blocked behind macro definitions
Added a new example class: shapeDatablockExample which allows render of a simple shape object utilizing a simple example datablock.
This commit is contained in:
JeffR 2026-05-31 01:19:26 -05:00
parent c2c5674fe9
commit b44158cb89
52 changed files with 1860 additions and 1086 deletions

View file

@ -55,16 +55,12 @@
#include "gfx/bitmap/imageUtils.h"
StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL;
AssetPtr<ShapeAsset> ShapeAsset::smNoShapeAssetFallbackAssetPtr = NULL;
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(ShapeAsset);
//-----------------------------------------------------------------------------
// REFACTOR
//-----------------------------------------------------------------------------
IMPLEMENT_STRUCT(AssetPtr<ShapeAsset>, AssetPtrShapeAsset, , "")
END_IMPLEMENT_STRUCT
@ -131,8 +127,50 @@ ConsoleSetType(TypeShapeAssetId)
}
//-----------------------------------------------------------------------------
// REFACTOR END
//-----------------------------------------------------------------------------
IMPLEMENT_STRUCT(AssetRef<ShapeAsset>, AssetRefShapeAsset, , "")
END_IMPLEMENT_STRUCT
ConsoleType(ShapeAssetRef, TypeShapeAssetRef, AssetRef<ShapeAsset>, ASSET_ID_FIELD_PREFIX)
ConsoleGetType(TypeShapeAssetRef)
{
AssetRef<ShapeAsset>& ref = *((AssetRef<ShapeAsset>*)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<ShapeAsset>* pAssetRef = (AssetRef<ShapeAsset>*)(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<MaterialAsset> 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<ShapeAnimationAsset> 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<ShapeAnimationAsset> 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<AssetErrCode>(load());
if (mShape)
{
return mShape;
}
else if (smNoShapeAssetFallbackAssetPtr.notNull())
{
return smNoShapeAssetFallbackAssetPtr->getShape();
}
return NULL;
}
Resource<TSShape> ShapeAsset::getShapeResource()
{
AssetErrCode result = static_cast<AssetErrCode>(load());
if (mShape)
{
return mShape;
}
else if (smNoShapeAssetFallbackAssetPtr.notNull())
{
return smNoShapeAssetFallbackAssetPtr->getShapeResource();
}
return Resource<TSShape>(NULL);
}
//------------------------------------------------------------------------------
//Utility function to 'fill out' bindings and resources with a matching asset if one exists
U32 ShapeAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr<ShapeAsset>* shapeAsset)
@ -560,6 +541,44 @@ U32 ShapeAsset::getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* 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<Material*>(Sim::findObject(overrideMaterial));
Material* tMat = dynamic_cast<Material*>(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<GuiTextEditCtrl*>(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

View file

@ -77,9 +77,10 @@ public:
};
static StringTableEntry smNoShapeAssetFallback;
static AssetPtr<ShapeAsset> 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<StringTableEntry> mMaterialAssetIds;
Vector<AssetPtr<MaterialAsset>> mMaterialAssets;
//Animation assets we're dependent on and use
Vector<StringTableEntry> mAnimationAssetIds;
Vector<AssetPtr<ShapeAnimationAsset>> mAnimationAssets;
Resource<TSShape> 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<TSShape> getShapeResource() { load(); return mShape; }
void SplitSequencePathAndName(String& srcPath, String& srcName);
TSShape* getShape();
Resource<TSShape> getShapeResource();
U32 getShapeFilenameHash() { return _StringTable::hashString(mShapeFile); }
Vector<AssetPtr<MaterialAsset>> getMaterialAssets() { return mMaterialAssets; }
inline AssetPtr<MaterialAsset> getMaterialAsset(U32 matId)
{
if (matId >= mMaterialAssets.size())
return NULL;
else
return mMaterialAssets[matId];
}
void clearMaterialAssets() { mMaterialAssets.clear(); }
void addMaterialAssets(AssetPtr<MaterialAsset> 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>* shapeAsset);
static StringTableEntry getAssetIdByFilename(StringTableEntry fileName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* 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<ShapeAsset>)
DefineConsoleType(TypeShapeAssetPtr, AssetPtr<ShapeAsset>)
DECLARE_STRUCT(AssetRef<ShapeAsset>)
DefineConsoleType(TypeShapeAssetRef, AssetRef<ShapeAsset>)
#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<ShapeAsset> 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<ShapeAsset> get##name##Asset(void) { return m##name##Asset; } \
static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast<className*>(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<ShapeAsset> 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<ShapeAsset> get##name##Asset(void) { return m##name##Asset; } \
static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast<className*>(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<ShapeAsset> 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<ShapeAsset> 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<className*>(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<ShapeAsset> 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<ShapeAsset> 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<className*>(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

View file

@ -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<TSShape> 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; i<DDC_NUM_EMITTERS; i++ )
{
@ -434,7 +439,7 @@ void DebrisData::unpackData(BitStream* stream)
textureName = stream->readSTString();
UNPACKDATA_ASSET_REFACTOR(Shape);
shapeAssetRef = AssetDatabase.unpackDataAsset(stream);
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{
@ -677,18 +682,19 @@ bool Debris::onAdd()
mFriction = mDataBlock->friction;
// Setup our bounding box
if( mDataBlock->getShape())
mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
Resource<TSShape> 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 )

View file

@ -83,7 +83,7 @@ struct DebrisData : public GameBaseData, protected AssetPtrCallback
F32 terminalVelocity; // max velocity magnitude
bool ignoreWater;
DECLARE_SHAPEASSET_REFACTOR(DebrisData, Shape)
AssetRef<ShapeAsset> shapeAssetRef;
StringTableEntry textureName;

View file

@ -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<TSShape> 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 )

View file

@ -61,7 +61,7 @@ class RenderShapeExample : public SceneObject
//--------------------------------------------------------------------------
// Rendering variables
//--------------------------------------------------------------------------
DECLARE_SHAPEASSET_REFACTOR(RenderShapeExample, Shape)
AssetRef<ShapeAsset> mShapeAssetRef;
// The actual shape instance
TSShapeInstance* mShapeInstance;

View file

@ -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<TSShape> 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<ShapeDatablockExampleData*>(dptr);
if (!mDataBlock)
return false;
if (mShapeInstance)
SAFE_DELETE(mShapeInstance);
if (mDataBlock->shapeAssetRef.isNull())
return false;
Resource<TSShape> 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);
}

View file

@ -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<ShapeAsset> 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

View file

@ -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 <i>ambient</i> 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 <i>ambient</i> 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<TSShape> 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<TSShape> 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();
}

View file

@ -79,7 +79,7 @@ class ExplosionData : public GameBaseData, protected AssetPtrCallback {
Point3F explosionScale;
F32 playSpeed;
DECLARE_SHAPEASSET_REFACTOR(ExplosionData, ExplosionShape)
AssetRef<ShapeAsset> explosionShapeAssetRef;
S32 explosionAnimation;

View file

@ -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<TSShape> 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() );
}
}

View file

@ -345,7 +345,7 @@ protected:
RectF mBillboardRects[MAX_COVERTYPES];
/// The cover shape filenames.
DECLARE_SHAPEASSET_ARRAY_NET_REFACTOR(GroundCover, Shape, MAX_COVERTYPES, -1)
AssetRef<ShapeAsset> mShapeAssetRef[MAX_COVERTYPES];
/// The cover shape instances.
TSShapeInstance* mShapeInstances[MAX_COVERTYPES];

View file

@ -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

View file

@ -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<TSShape> 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.

View file

@ -52,8 +52,8 @@ protected:
MouseState mMouseState;
DECLARE_SHAPEASSET_REFACTOR(GuiMaterialPreview, Model)
DECLARE_SHAPEASSET_REFACTOR(GuiMaterialPreview, MountedModel)
AssetRef<ShapeAsset> mShapeAssetRef;
AssetRef<ShapeAsset> 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);

View file

@ -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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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);
}
//-----------------------------------------------------------------------------

View file

@ -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<ShapeAsset> 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<ShapeAsset> 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);
}
};

View file

@ -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<TSShape> 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

View file

@ -473,14 +473,23 @@ void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream)
{
delete mShapeInstance;
ShapeBaseData *spawnedDatablock = dynamic_cast<ShapeBaseData *>(Sim::findObject(mSpawnDataBlock.c_str()));
if (spawnedDatablock && spawnedDatablock->getShape())
if (spawnedDatablock)
{
mShapeInstance = new TSShapeInstance(spawnedDatablock->getShape());
if (spawnedDatablock->shapeAssetRef.notNull())
{
Resource<TSShape> 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<TSShape> shape = mDataBlock->shapeAssetRef.assetPtr->getShapeResource();
if (shape)
mShapeInstance = new TSShapeInstance(shape);
}
}
}
stream->read(&mSpawnName);

View file

@ -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<TSShape> 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<TSShape> 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<U32> &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;

View file

@ -86,7 +86,7 @@ public:
/// Is rendererd during shadow passes.
bool castShadows;
DECLARE_SHAPEASSET_REFACTOR(PhysicsDebrisData, Shape)
AssetRef<ShapeAsset> shapeAssetRef;
PhysicsDebrisData();
virtual ~PhysicsDebrisData();

View file

@ -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<PhysicsDebrisData> >(), 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<TSShape> 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<TSShape> 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<TSShape> 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();
}

View file

@ -74,7 +74,7 @@ public:
public:
DECLARE_SHAPEASSET_REFACTOR(PhysicsShapeData, Shape)
AssetRef<ShapeAsset> shapeAsset;
/// The shared unscaled collision shape.
PhysicsCollisionRef colShape;

View file

@ -299,7 +299,7 @@ PlayerData::PlayerData()
imageAnimPrefixFP = StringTable->EmptyString();
for (U32 i=0; i<ShapeBase::MaxMountedImages; ++i)
{
mShapeFPAsset[i].registerRefreshNotify(this);
shapeFPAssetRef[i].assetPtr.registerRefreshNotify(this);
mCRCFP[i] = 0;
mValidShapeFP[i] = false;
}
@ -506,12 +506,16 @@ bool PlayerData::preload(bool server, String &errorStr)
Con::printf("PlayerData:: Jump delay exceeds range (0-%d)",jumpDelay);
}
Resource<TSShape> 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<TSShape> 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; i<ShapeBase::MaxMountedImages; ++i)
{
if (bool(mDataBlock->getShapeFP(i)))
if (mDataBlock->shapeFPAssetRef[i].isNull())
continue;
Resource<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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;
}

View file

@ -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<ShapeAsset> shapeFPAssetRef[ShapeBase::MaxMountedImages];
StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify
/// animation sequences played in first person. [optional]

View file

@ -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<TSShape> 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<TSShape> 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));

View file

@ -71,7 +71,7 @@ protected:
bool onAdd() override;
public:
DECLARE_SHAPEASSET_REFACTOR(ProjectileData, ProjectileShape)
AssetRef<ShapeAsset> projectileShapeAssetRef;
/// Set to true if it is a billboard and want it to always face the viewer, false otherwise
bool faceViewer;

View file

@ -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<TSShape> shape = shapeAssetRef.assetPtr->getShapeResource();
if (shape)
{
// Lookup animation sequences
armingSequence = shape->findSequence("armed");
triggerSequence = shape->findSequence("triggered");
}
}
return true;

View file

@ -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<TSShape> 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);

View file

@ -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<TSShape> dShape = debrisShapeAssetRef.assetPtr->getShapeResource();
if (dShape)
{
TSShapeInstance* pDummy = new TSShapeInstance(dShape, !server);
delete pDummy;
}
}
}
Resource<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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<TSShape> 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];
}
//

View file

@ -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<ShapeAsset> 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<ShapeAsset> shapeAssetRef;
StringTableEntry cloakTexName;
@ -572,7 +572,7 @@ public:
DebrisData * debris;
S32 debrisID;
DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, DebrisShape)
AssetRef<ShapeAsset> debrisShapeAssetRef;
ExplosionData* explosion;
S32 explosionID;

View file

@ -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<TSShape> 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<TSShape> 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<TSShape> 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; i<ShapeBaseImageData::MaxShapes; ++i)
{
if (image.dataBlock->shapeIsValid[i])
image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->getShape(i), isClientObject());
{
Resource<TSShape> shape = image.dataBlock->shapeAssetRef[i].assetPtr->getShapeResource();
image.shapeInstance[i] = new TSShapeInstance(shape, isClientObject());
}
}
if (isClientObject())

View file

@ -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<TSShape> 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<MaterialAsset>(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<TSShape> 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<TSShape> 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<StringTableEntry>* 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> shapeAsset = object->getShapeAsset();
if (shapeAsset.isNull())
return;
Resource<TSShape> 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> 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<TSShape> 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<TSShape> shape = mShapeAssetRef.assetPtr->getShapeResource();
if (!shape)
return;
S32 nodeIDx = shape->findNode(nodeName);
MatrixF nodeTransform(xfm);
const Point3F& scale = getScale();

View file

@ -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<ShapeAsset> mShapeAssetRef;
U32 mShapeHash;
Vector<S32> 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<StringTableEntry>* usedAssetsList) override;
const AssetPtr<ShapeAsset>& getShapeAsset() const { return mShapeAssetRef.assetPtr; }
private:
void onStaticModified(const char* slotName, const char* newValue = NULL) override;
protected:

View file

@ -245,9 +245,11 @@ bool AITurretShapeData::preload(bool server, String &errorStr)
if (!Parent::preload(server, errorStr))
return false;
Resource<TSShape> 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

View file

@ -216,36 +216,43 @@ bool TurretShapeData::preload(bool server, String &errorStr)
if (!Parent::preload(server, errorStr))
return false;
if (shapeAssetRef.isNull())
return false;
Resource<TSShape> 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;
}

View file

@ -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<TSShape> 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;

View file

@ -332,9 +332,12 @@ bool HoverVehicleData::preload(bool server, String &errorStr)
return false;
}
}
Resource<TSShape> 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;
}

View file

@ -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;
}

View file

@ -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<TSShape> 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<TSShape> 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<TSShape> shape = wheel->tire->shapeAssetRef.assetPtr->getShapeResource();
if (shape)
{
wheel->shapeInstance = new TSShapeInstance(shape);
}
}
}
}
}

View file

@ -43,7 +43,7 @@ struct WheeledVehicleTire: public SimDataBlock, protected AssetPtrCallback
{
typedef SimDataBlock Parent;
DECLARE_SHAPEASSET_REFACTOR(WheeledVehicleTire, Shape)
AssetRef<ShapeAsset> shapeAssetRef;
// Physical properties
F32 mass; // Mass of the whole wheel