Merge branch 'Preview4_0' into str_cpp_memory_experiment

This commit is contained in:
Robert MacGregor 2022-06-09 22:49:43 -04:00
commit 1e9aa8b86f
4161 changed files with 514029 additions and 215418 deletions

View file

@ -85,7 +85,7 @@ AccumulationVolume::AccumulationVolume()
mWorldToObj.identity();
// Accumulation Texture.
INIT_IMAGEASSET(Texture);
INIT_ASSET(Texture);
resetWorldBox();
}
@ -236,7 +236,7 @@ U32 AccumulationVolume::packUpdate( NetConnection *connection, U32 mask, BitStre
if (stream->writeFlag(mask & InitialUpdateMask))
{
PACK_IMAGEASSET(connection, Texture);
PACK_ASSET(connection, Texture);
}
return retMask;
@ -248,7 +248,7 @@ void AccumulationVolume::unpackUpdate( NetConnection *connection, BitStream *str
if (stream->readFlag())
{
UNPACK_IMAGEASSET(connection, Texture);
UNPACK_ASSET(connection, Texture);
//setTexture(mTextureName);
}
}

View file

@ -62,7 +62,7 @@ class AccumulationVolume : public ScenePolyhedralSpace
virtual void _renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat );
DECLARE_IMAGEASSET(AccumulationVolume, Texture, onTextureChanged, GFXStaticTextureSRGBProfile);
DECLARE_IMAGEASSET_NET_SETGET(AccumulationVolume, Texture, -1);
DECLARE_ASSET_NET_SETGET(AccumulationVolume, Texture, -1);
void onTextureChanged() {}

View file

@ -199,7 +199,7 @@ GuiControl* GuiInspectorTypeCubemapAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"CubemapAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
mInspector->getInspectObject(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
setDataField(StringTable->insert("object"), NULL, String::ToString(mInspector->getInspectObject()).c_str());

View file

@ -65,8 +65,6 @@ ConsoleSetType(TypeGUIAssetPtr)
if (argc == 1)
{
// Yes, so fetch field value.
const char* pFieldValue = argv[0];
*((const char**)dptr) = StringTable->insert(argv[0]);
return;
@ -104,7 +102,7 @@ void GUIAsset::initPersistFields()
&setScriptFile, &getScriptFile, "Path to the script file for the gui");
addProtectedField("GUIFile", TypeAssetLooseFilePath, Offset(mGUIFile, GUIAsset),
&setScriptFile, &getScriptFile, "Path to the gui file");
&setGUIFile, &getGUIFile, "Path to the gui file");
}
//------------------------------------------------------------------------------
@ -117,28 +115,28 @@ void GUIAsset::copyTo(SimObject* object)
void GUIAsset::initializeAsset()
{
mGUIPath = getOwned() ? expandAssetFilePath(mGUIFile) : mGUIPath;
if (Torque::FS::IsScriptFile(mGUIPath))
Con::executeFile(mGUIPath, false, false);
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
mGUIPath = getOwned() ? expandAssetFilePath(mGUIFile) : mGUIPath;
if (Torque::FS::IsScriptFile(mGUIPath))
Con::executeFile(mGUIPath, false, false);
}
void GUIAsset::onAssetRefresh()
{
mGUIPath = getOwned() ? expandAssetFilePath(mGUIFile) : mGUIPath;
if (Torque::FS::IsScriptFile(mGUIPath))
Con::executeFile(mGUIPath, false, false);
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
mGUIPath = getOwned() ? expandAssetFilePath(mGUIFile) : mGUIPath;
if (Torque::FS::IsScriptFile(mGUIPath))
Con::executeFile(mGUIPath, false, false);
}
void GUIAsset::setGUIFile(const char* pScriptFile)
@ -221,6 +219,20 @@ DefineEngineStaticMethod(GUIAsset, getAssetIdByGUIName, const char*, (const char
{
return GUIAsset::getAssetIdByGUIName(StringTable->insert(guiName));
}
DefineEngineMethod(GUIAsset, getScriptPath, const char*, (), ,
"Gets the script file path associated to this asset.\n"
"@return The full script file path.")
{
return object->getScriptPath();
}
DefineEngineMethod(GUIAsset, getGUIPath, const char*, (), ,
"Gets the GUI file path associated to this asset.\n"
"@return The full script file path.")
{
return object->getGUIPath();
}
#endif
//-----------------------------------------------------------------------------
@ -252,7 +264,7 @@ GuiControl* GuiInspectorTypeGUIAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"GUIAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
mInspector->getComponentGroupTargetId(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
// Create "Open in ShapeEditor" button

View file

@ -58,7 +58,7 @@ StringTableEntry ImageAsset::smNoImageAssetFallback = NULL;
IMPLEMENT_CONOBJECT(ImageAsset);
ConsoleType(ImageAssetPtr, TypeImageAssetPtr, const char*, ASSET_ID_FIELD_PREFIX)
ConsoleType(ImageAssetPtr, TypeImageAssetPtr, const char*, "")
//-----------------------------------------------------------------------------
@ -85,7 +85,7 @@ ConsoleSetType(TypeImageAssetPtr)
Con::warnf("(TypeImageAssetPtr) - Cannot set multiple args to a single asset.");
}
ConsoleType(assetIdString, TypeImageAssetId, const char*, ASSET_ID_FIELD_PREFIX)
ConsoleType(assetIdString, TypeImageAssetId, const char*, "")
ConsoleGetType(TypeImageAssetId)
{
@ -147,7 +147,7 @@ void ImageAsset::consoleInit()
Con::addVariable("$Core::NoImageAssetFallback", TypeString, &smNoImageAssetFallback,
"The assetId of the texture to display when the requested image asset is missing.\n"
"@ingroup GFX\n");
smNoImageAssetFallback = StringTable->insert(Con::getVariable("$Core::NoImageAssetFallback"));
}
@ -219,6 +219,10 @@ StringTableEntry ImageAsset::getAssetIdByFilename(StringTableEntry fileName)
//acquire and bind the asset, and return it out
imageAssetId = query.mAssetList[0];
}
else
{
AssetPtr<ImageAsset> imageAsset = imageAssetId; //ensures the fallback is loaded
}
return imageAssetId;
}
@ -274,22 +278,8 @@ void ImageAsset::loadImage()
mLoadedState = Ok;
mIsValidImage = true;
return;
//GFXTexHandle texture = getTexture(&GFXStaticTextureSRGBProfile);
//mTexture.set(mImagePath, &GFXStaticTextureSRGBProfile, avar("%s() - mImage (line %d)", __FUNCTION__, __LINE__));
/*if (texture.isValid())
{
mIsValidImage = true;
//mBitmap = texture.getBitmap();
return;
}*/
mChangeSignal.trigger();
return;
}
mLoadedState = BadFileReference;
@ -494,21 +484,17 @@ GuiControl* GuiInspectorTypeImageAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ImageAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getInspectObject()->getIdString(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
const char* id = mInspector->getInspectObject()->getIdString();
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
// Create "Open in ShapeEditor" button
mImageEdButton = new GuiBitmapButtonCtrl();
dSprintf(szBuffer, sizeof(szBuffer), "ShapeEditorPlugin.openShapeAssetId(%d.getText());", retCtrl->getId());
mImageEdButton->setField("Command", szBuffer);
char bitmapName[512] = "ToolsModule:GameTSCtrl_image";
mImageEdButton->setBitmap(StringTable->insert(bitmapName));
mImageEdButton->setHidden(true);
mImageEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
mImageEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
@ -565,11 +551,24 @@ bool GuiInspectorTypeImageAssetPtr::renderTooltip(const Point2I& hoverPos, const
if (!filename || !filename[0])
return false;
GFXTexHandle texture(filename, &GFXStaticTextureSRGBProfile, avar("%s() - tooltip texture (line %d)", __FUNCTION__, __LINE__));
StringTableEntry previewFilename = filename;
if (Con::isFunction("getAssetPreviewImage"))
{
ConsoleValue consoleRet = Con::executef("getAssetPreviewImage", filename);
previewFilename = StringTable->insert(consoleRet.getString());
if (AssetDatabase.isDeclaredAsset(previewFilename))
{
ImageAsset* previewAsset = AssetDatabase.acquireAsset<ImageAsset>(previewFilename);
previewFilename = previewAsset->getImagePath();
}
}
GFXTexHandle texture(previewFilename, &GFXStaticTextureSRGBProfile, avar("%s() - tooltip texture (line %d)", __FUNCTION__, __LINE__));
if (texture.isNull())
return false;
// Render image at a reasonable screen size while
// Render image at a reasonable screen size while
// keeping its aspect ratio...
Point2I screensize = getRoot()->getWindowSize();
Point2I offset = hoverPos;

View file

@ -47,7 +47,7 @@
#include "sim/netConnection.h"
#include <string>
#include "assetMacroHelpers.h"
//-----------------------------------------------------------------------------
class ImageAsset : public AssetBase
{
@ -248,7 +248,7 @@ public: \
Con::errorf("%s(%s)::_set%s() - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ImageAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
return false; \
}\
else if (m##name)\
else if (!m##name)\
{\
Con::errorf("%s(%s)::_set%s() - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), _in);\
return false;\
@ -270,46 +270,8 @@ public: \
GFXTexHandle get##name##Resource() \
{\
return m##name;\
}
#define DECLARE_IMAGEASSET_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
return ret;\
}
#define DECLARE_IMAGEASSET_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
#define DEF_IMAGEASSET_BINDS(className,name)\
DefineEngineMethod(className, get##name, const char*, (), , "get name")\
{\
return object->get##name(); \
}\
DefineEngineMethod(className, get##name##Asset, const char*, (), , assetText(name, asset reference))\
{\
return object->m##name##AssetId; \
}\
DefineEngineMethod(className, set##name, bool, (const char* map), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(map));\
}
#define INIT_IMAGEASSET(name) \
m##name##Name = StringTable->EmptyString(); \
m##name##AssetId = StringTable->EmptyString(); \
m##name##Asset = NULL;
}\
bool name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
@ -325,11 +287,6 @@ DefineEngineMethod(className, set##name, bool, (const char* map), , assetText(na
#endif // SHOW_LEGACY_FILE_FIELDS
#define CLONE_IMAGEASSET(name) \
m##name##Name = other.m##name##Name;\
m##name##AssetId = other.m##name##AssetId;\
m##name##Asset = other.m##name##Asset;
#define LOAD_IMAGEASSET(name)\
if (m##name##AssetId != StringTable->EmptyString())\
{\
@ -341,53 +298,19 @@ if (m##name##AssetId != StringTable->EmptyString())\
else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId, ImageAsset::getAssetErrstrn(assetState).c_str());\
}
#define PACKDATA_IMAGEASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
stream->writeString(m##name##Asset.getAssetId());\
_set##name(m##name##AssetId);\
}\
else\
stream->writeString(m##name##Name);
#define UNPACKDATA_IMAGEASSET(name)\
if (stream->readFlag())\
{\
m##name##AssetId = stream->readSTString();\
}\
else\
m##name##Name = stream->readSTString();
#define PACK_IMAGEASSET(netconn, name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset.getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name);
#define UNPACK_IMAGEASSET(netconn, name)\
if (stream->readFlag())\
{\
m##name##AssetId = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
#pragma endregion
#pragma region Arrayed Asset Macros
//Arrayed Assets
#define DECLARE_IMAGEASSET_ARRAY(className, name, profile, max) public: \
#define DECLARE_IMAGEASSET_ARRAY(className, name, max) public: \
static const U32 sm##name##Count = max;\
GFXTexHandle m##name[max];\
StringTableEntry m##name##Name[max]; \
StringTableEntry m##name##AssetId[max];\
AssetPtr<ImageAsset> m##name##Asset[max];\
GFXTextureProfile * m##name##Profile = &profile;\
GFXTextureProfile * m##name##Profile[max];\
public: \
const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\
void set##name##File(const FileName &_in, const U32& index) { m##name##Name[index] = StringTable->insert(_in.c_str());}\
@ -451,7 +374,7 @@ public: \
}\
if (get##name(index) != StringTable->EmptyString() && m##name##Name[index] != StringTable->insert("texhandle"))\
{\
m##name[index].set(get##name(index), m##name##Profile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
m##name[index].set(get##name(index), m##name##Profile[index], avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));\
}\
else\
{\
@ -467,7 +390,7 @@ public: \
Con::errorf("%s(%s)::_set%s(%i) - image asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), index, _in, ImageAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\
return false; \
}\
else if (bool(m##name[index]) == NULL)\
else if (!m##name[index])\
{\
Con::errorf("%s(%s)::_set%s(%i) - Couldn't load image \"%s\"", macroText(className), getName(), macroText(name), index, _in);\
return false; \
@ -482,7 +405,12 @@ public: \
else if (m##name##AssetId[index] != StringTable->EmptyString())\
return m##name##AssetId[index];\
else if (m##name##Name[index] != StringTable->EmptyString())\
return StringTable->insert(Platform::makeRelativePathName(m##name##Name[index], Platform::getMainDotCsDir()));\
{\
if (String(m##name##Name[index]).startsWith("#") || String(m##name##Name[index]).startsWith("$"))\
return StringTable->insert(m##name##Name[index]);\
else\
return StringTable->insert(Platform::makeRelativePathName(m##name##Name[index], Platform::getMainDotCsDir()));\
}\
else\
return StringTable->EmptyString();\
}\
@ -491,7 +419,8 @@ public: \
if(index >= sm##name##Count || index < 0)\
return nullptr;\
return m##name[index];\
}
}\
bool name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); }
#define DECLARE_IMAGEASSET_ARRAY_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
@ -521,6 +450,15 @@ public: \
return ret;\
}
#define INIT_IMAGEASSET_ARRAY(name, profile, index) \
{\
m##name##Name[index] = StringTable->EmptyString(); \
m##name##AssetId[index] = StringTable->EmptyString(); \
m##name##Asset[index] = NULL;\
m##name[index] = NULL;\
m##name##Profile[index] = &profile;\
}
#define DEF_IMAGEASSET_ARRAY_BINDS(className,name)\
DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\
{\
@ -537,13 +475,6 @@ DefineEngineMethod(className, set##name, bool, (const char* map, S32 index), , a
return object->_set##name(StringTable->insert(map), index);\
}
#define INIT_IMAGEASSET_ARRAY(name, index) \
{\
m##name##Name[index] = StringTable->EmptyString(); \
m##name##AssetId[index] = StringTable->EmptyString(); \
m##name##Asset[index] = NULL;\
}
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
#define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \
@ -558,13 +489,6 @@ DefineEngineMethod(className, set##name, bool, (const char* map, S32 index), , a
#endif
#define CLONE_IMAGEASSET_ARRAY(name, index) \
{\
m##name##Name[index] = other.m##name##Name[index];\
m##name##AssetId[index] = other.m##name##AssetId[index];\
m##name##Asset[index] = other.m##name##Asset[index];\
}
#define LOAD_IMAGEASSET_ARRAY(name, index)\
if (m##name##AssetId[index] != StringTable->EmptyString())\
{\
@ -576,41 +500,6 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\
else Con::warnf("Warning: %s::LOAD_IMAGEASSET(%s)-%s", mClassName, m##name##AssetId[index], ImageAsset::getAssetErrstrn(assetState).c_str());\
}
#define PACKDATA_IMAGEASSET_ARRAY(name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
stream->writeString(m##name##Asset[index].getAssetId());\
}\
else\
stream->writeString(m##name##Name[index]);
#define UNPACKDATA_IMAGEASSET_ARRAY(name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
}\
else\
m##name##Name[index] = stream->readSTString();
#define PACK_IMAGEASSET_ARRAY(netconn, name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset[index].getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name[index]);
#define UNPACK_IMAGEASSET_ARRAY(netconn, name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId[index], index);\
}\
else\
m##name##Name[index] = stream->readSTString();
#pragma endregion

View file

@ -391,6 +391,20 @@ DefineEngineMethod(LevelAsset, getDecalsPath, const char*, (), ,
return object->getDecalsPath();
}
DefineEngineMethod(LevelAsset, getForestPath, const char*, (), ,
"Gets the full path of the asset's defined forest file.\n"
"@return The string result of the forest path")
{
return object->getForestPath();
}
DefineEngineMethod(LevelAsset, getNavmeshPath, const char*, (), ,
"Gets the full path of the asset's defined navmesh file.\n"
"@return The string result of the navmesh path")
{
return object->getNavmeshPath();
}
DefineEngineMethod(LevelAsset, loadDependencies, void, (), ,
"Initiates the loading of asset dependencies for this level.")
{

View file

@ -19,7 +19,6 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#pragma once
#ifndef MATERIALASSET_H
#include "MaterialAsset.h"
@ -155,8 +154,9 @@ void MaterialAsset::initPersistFields()
Parent::initPersistFields();
//addField("shaderGraph", TypeRealString, Offset(mShaderGraphFile, MaterialAsset), "");
addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset),
&setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
//addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset),
// &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
addField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset), "");
addField("materialDefinitionName", TypeString, Offset(mMatDefinitionName, MaterialAsset), "Name of the material definition this asset is for.");
}
@ -168,8 +168,34 @@ void MaterialAsset::initializeAsset()
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
if (mMatDefinitionName == StringTable->EmptyString())
{
mLoadedState = Failed;
return;
}
if (size() != 0 && mScriptPath == StringTable->EmptyString())
{
mLoadedState = EmbeddedDefinition;
}
else if (Torque::FS::IsScriptFile(mScriptPath))
{
if (!Sim::findObject(mMatDefinitionName))
{
if (Con::executeFile(mScriptPath, false, false))
{
mLoadedState = ScriptLoaded;
}
else
{
mLoadedState = Failed;
}
}
else
{
mLoadedState = DefinitionAlreadyExists;
}
}
loadMaterial();
}
@ -178,8 +204,28 @@ void MaterialAsset::onAssetRefresh()
{
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (mMatDefinitionName == StringTable->EmptyString())
{
mLoadedState = Failed;
return;
}
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
{
//Since we're refreshing, we can assume that the file we're executing WILL have an existing definition.
//But that definition, whatever it is, is the 'correct' one, so we enable the Replace Existing behavior
//when the engine encounters a named object conflict.
String redefineBehaviorPrev = Con::getVariable("$Con::redefineBehavior");
Con::setVariable("$Con::redefineBehavior", "replaceExisting");
if (Con::executeFile(mScriptPath, false, false))
mLoadedState = ScriptLoaded;
else
mLoadedState = Failed;
//And now that we've executed, switch back to the prior behavior
Con::setVariable("$Con::redefineBehavior", redefineBehaviorPrev.c_str());
}
loadMaterial();
}
@ -189,7 +235,6 @@ void MaterialAsset::setScriptFile(const char* pScriptFile)
// Sanity!
AssertFatal(pScriptFile != NULL, "Cannot use a NULL script file.");
// Fetch image file.
pScriptFile = StringTable->insert(pScriptFile, true);
// Update.
@ -204,9 +249,28 @@ void MaterialAsset::setScriptFile(const char* pScriptFile)
void MaterialAsset::loadMaterial()
{
if (mMaterialDefinition)
SAFE_DELETE(mMaterialDefinition);
{
mMaterialDefinition->safeDeleteObject();
}
if (mMatDefinitionName != StringTable->EmptyString())
if (mLoadedState == EmbeddedDefinition)
{
if (size() != 0)
{
for (U32 i = 0; i < size(); i++)
{
mMaterialDefinition = dynamic_cast<Material*>(getObject(i));
if (mMaterialDefinition)
{
mLoadedState = Ok;
mMaterialDefinition->setInternalName(getAssetId());
mMaterialDefinition->reload();
return;
}
}
}
}
else if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && mMatDefinitionName != StringTable->EmptyString())
{
Material* matDef;
if (!Sim::findObject(mMatDefinitionName, matDef))
@ -219,7 +283,7 @@ void MaterialAsset::loadMaterial()
mMaterialDefinition = matDef;
mLoadedState = Ok;
mMaterialDefinition->setInternalName(getAssetId());
mMaterialDefinition->reload();
return;
}
@ -255,11 +319,11 @@ U32 MaterialAsset::getAssetByMaterialName(StringTableEntry matName, AssetPtr<Mat
//handle noshape not being loaded itself
if ((*matAsset)->mLoadedState == BadFileReference)
{
Con::warnf("ShapeAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
Con::warnf("MaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
return AssetErrCode::BadFileReference;
}
Con::warnf("ShapeAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
Con::warnf("MaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
(*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
return AssetErrCode::UsingFallback;
@ -278,6 +342,12 @@ U32 MaterialAsset::getAssetByMaterialName(StringTableEntry matName, AssetPtr<Mat
AssetDatabase.releaseAsset(query.mAssetList[i]); //cleanup if that's not the one we needed
}
}
//Somehow we failed to bind an asset, so just use the fallback and mark the failure
matAsset->setAssetId(MaterialAsset::smNoMaterialAssetFallback);
(*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
return AssetErrCode::UsingFallback;
}
StringTableEntry MaterialAsset::getAssetIdByMaterialName(StringTableEntry matName)
@ -341,6 +411,17 @@ U32 MaterialAsset::getAssetById(StringTableEntry assetId, AssetPtr<MaterialAsset
}
}
SimObjectPtr<Material> MaterialAsset::findMaterialDefinitionByAssetId(StringTableEntry assetId)
{
SimSet* matSet = MATMGR->getMaterialSet();
if (matSet)
{
SimObjectPtr<Material> matDef = dynamic_cast<Material*>(matSet->findObjectByInternalName(assetId));
return matDef;
}
return nullptr;
}
#ifdef TORQUE_TOOLS
DefineEngineStaticMethod(MaterialAsset, getAssetIdByMaterialName, const char*, (const char* materialName), (""),
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
@ -349,9 +430,21 @@ DefineEngineStaticMethod(MaterialAsset, getAssetIdByMaterialName, const char*, (
return MaterialAsset::getAssetIdByMaterialName(StringTable->insert(materialName));
}
//MaterialAsset::findMaterialDefinitionByAssetId("Prototyping:Detail")
DefineEngineStaticMethod(MaterialAsset, findMaterialDefinitionByAssetId, S32, (const char* assetId), (""),
"Queries the MaterialSet to see if any MaterialDefinition exists that is associated to the provided assetId.\n"
"@return The MaterialDefinition Id associated to the assetId, if any")
{
SimObjectPtr<Material> matDef = MaterialAsset::findMaterialDefinitionByAssetId(StringTable->insert(assetId));
if (matDef.isNull())
return SimObjectId(0);
else
return matDef->getId();
}
DefineEngineMethod(MaterialAsset, getScriptPath, const char*, (), ,
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
"@return The AssetId of the associated asset, if any.")
"Gets the script file path for the asset.")
{
return object->getScriptPath();
}
@ -385,8 +478,8 @@ GuiControl* GuiInspectorTypeMaterialAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"MaterialAsset\", \"AssetBrowser.changeAsset\", %s, \"\");",
getIdString());
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"MaterialAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());

View file

@ -48,12 +48,15 @@
#include "sim/netConnection.h"
#endif
#ifndef _GUI_INSPECTOR_TYPES_H_
#include "gui/editor/guiInspectorTypes.h"
#endif
#include "materials/matTextureTarget.h"
#include "materials/materialDefinition.h"
#include "materials/customMaterialDefinition.h"
#include "materials/materialManager.h"
#include "assetMacroHelpers.h"
//-----------------------------------------------------------------------------
class MaterialAsset : public AssetBase
@ -70,6 +73,14 @@ class MaterialAsset : public AssetBase
public:
static StringTableEntry smNoMaterialAssetFallback;
enum MaterialAssetErrCode
{
ScriptLoaded = AssetErrCode::Extended,
DefinitionAlreadyExists,
EmbeddedDefinition,
Extended
};
public:
MaterialAsset();
virtual ~MaterialAsset();
@ -100,6 +111,7 @@ public:
/// <returns>AssetId of matching asset.</returns>
static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<MaterialAsset>* materialAsset);
static SimObjectPtr<Material> findMaterialDefinitionByAssetId(StringTableEntry assetId);
static U32 getAssetByMaterialName(StringTableEntry matName, AssetPtr<MaterialAsset>* matAsset);
/// Declare Console Object.
@ -231,7 +243,7 @@ public: \
Con::errorf("%s::_set%s() - material asset failure\"%s\" due to [%s]", macroText(className), macroText(name), _in, MaterialAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
return false; \
}\
else if (m##name)\
else if (!m##name)\
{\
Con::errorf("%s::_set%s() - Couldn't load material \"%s\"", macroText(className), macroText(name), _in);\
return false;\
@ -253,47 +265,8 @@ public: \
SimObjectPtr<Material> get##name##Resource() \
{\
return m##name;\
}
#define DECLARE_MATERIALASSET_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
return ret;\
}
#define DECLARE_MATERIALASSET_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
#define DEF_MATERIALASSET_BINDS(className,name)\
DefineEngineMethod(className, get##name, const char*, (), , "get name")\
{\
return object->get##name(); \
}\
DefineEngineMethod(className, get##name##Asset, const char*, (), , assetText(name, asset reference))\
{\
return object->m##name##AssetId; \
}\
DefineEngineMethod(className, set##name, bool, (const char* mat), , assetText(name,assignment. first tries asset then material name.))\
{\
return object->_set##name(StringTable->insert(mat));\
}
#define INIT_MATERIALASSET(name) \
m##name##Name = StringTable->EmptyString(); \
m##name##AssetId = StringTable->EmptyString(); \
m##name##Asset = NULL;\
m##name = NULL;
}\
bool is##name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
@ -309,11 +282,6 @@ DefineEngineMethod(className, set##name, bool, (const char* mat), , assetText(na
#endif // SHOW_LEGACY_FILE_FIELDS
#define CLONE_MATERIALASSET(name) \
m##name##Name = other.m##name##Name;\
m##name##AssetId = other.m##name##AssetId;\
m##name##Asset = other.m##name##Asset;
#define LOAD_MATERIALASSET(name)\
if (m##name##AssetId != StringTable->EmptyString())\
{\
@ -324,42 +292,6 @@ if (m##name##AssetId != StringTable->EmptyString())\
}\
else Con::warnf("Warning: %s::LOAD_MATERIALASSET(%s)-%s", mClassName, m##name##AssetId, MaterialAsset::getAssetErrstrn(assetState).c_str());\
}
#define PACKDATA_MATERIALASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
stream->writeString(m##name##Asset.getAssetId());\
}\
else\
stream->writeString(m##name##Name);
#define UNPACKDATA_MATERIALASSET(name)\
if (stream->readFlag())\
{\
m##name##AssetId = stream->readSTString();\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
#define PACK_MATERIALASSET(netconn, name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset.getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name);
#define UNPACK_MATERIALASSET(netconn, name)\
if (stream->readFlag())\
{\
m##name##AssetId = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
#pragma endregion
#endif // _ASSET_BASE_H_

View file

@ -151,7 +151,7 @@ GuiControl* GuiInspectorTypeParticleAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ParticleAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
mInspector->getComponentGroupTargetId(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
// Create "Open in ShapeEditor" button

View file

@ -206,3 +206,21 @@ void PostEffectAsset::setGLSLShaderFile(const char* pShaderFile)
// Refresh the asset.
refreshAsset();
}
DefineEngineMethod(PostEffectAsset, getScriptPath, const char*, (), ,
"Gets the script file path for the asset.")
{
return object->getScriptPath();
}
DefineEngineMethod(PostEffectAsset, getHLSLShaderPath, const char*, (), ,
"Gets the HLSL Shader file path for the asset.")
{
return object->getHLSLShaderPath();
}
DefineEngineMethod(PostEffectAsset, getGLSLShaderPath, const char*, (), ,
"Gets the GLSL Shader file path for the asset.")
{
return object->getGLSLShaderPath();
}

View file

@ -190,17 +190,12 @@ bool ScriptAsset::execScript()
if (handle)
return true;
return false;
if (Torque::FS::IsScriptFile(mScriptPath))
{
return Con::executeFile(mScriptPath, false, false);
}
else
{
Con::errorf("ScriptAsset:execScript() - Script asset must have a valid file to exec");
return false;
}
Con::errorf("ScriptAsset:execScript() - Script asset must have a valid file to exec");
return false;
}
DefineEngineMethod(ScriptAsset, execScript, bool, (), ,

View file

@ -151,7 +151,7 @@ void ShapeAnimationAsset::initializeAsset(void)
mSourceShape = ResourceManager::get().load(mFilePath);
if (!mSourceShape->addSequence("ambient", "", mAnimationName, mStartFrame, mEndFrame, mPadRotation, mPadTransforms))
if (!mSourceShape || !mSourceShape->addSequence("ambient", "", mAnimationName, mStartFrame, mEndFrame, mPadRotation, mPadTransforms))
{
Con::errorf("ShapeAnimationAsset::initializeAsset - Unable to do initial setup of the animation clip named %s for asset %s", mAnimationName, getAssetName());
return;
@ -204,3 +204,9 @@ DefineEngineMethod(ShapeAnimationAsset, getAnimationCount, S32, (), ,
{
return object->getAnimationCount();
}
DefineEngineMethod(ShapeAnimationAsset, getAnimationPath, const char*, (), ,
"Gets the Animation file path associated to this asset.")
{
return object->getAnimationPath();
}

View file

@ -49,6 +49,10 @@
#ifdef TORQUE_TOOLS
#include "ts/tsLastDetail.h"
#endif
#include "util/imposterCapture.h"
#include "ts/tsShapeInstance.h"
#include "gfx/bitmap/imageUtils.h"
StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL;
@ -128,6 +132,13 @@ ShapeAsset::ShapeAsset()
mConstructorFileName = StringTable->EmptyString();
mFilePath = StringTable->EmptyString();
mConstructorFilePath = StringTable->EmptyString();
mDiffuseImposterFileName = StringTable->EmptyString();
mDiffuseImposterPath = StringTable->EmptyString();
mNormalImposterFileName = StringTable->EmptyString();
mNormalImposterPath = StringTable->EmptyString();
mLoadedState = AssetErrCode::NotLoaded;
}
@ -161,6 +172,12 @@ void ShapeAsset::initPersistFields()
&setShapeFile, &getShapeFile, "Path to the shape file we want to render");
addProtectedField("constuctorFileName", TypeAssetLooseFilePath, Offset(mConstructorFileName, ShapeAsset),
&setShapeConstructorFile, &getShapeConstructorFile, "Path to the shape file we want to render");
addProtectedField("diffuseImposterFileName", TypeAssetLooseFilePath, Offset(mDiffuseImposterFileName, ShapeAsset),
&setDiffuseImposterFile, &getDiffuseImposterFile, "Path to the diffuse imposter file we want to render");
addProtectedField("normalImposterFileName", TypeAssetLooseFilePath, Offset(mNormalImposterFileName, ShapeAsset),
&setNormalImposterFile, &getNormalImposterFile, "Path to the normal imposter file we want to render");
}
void ShapeAsset::setDataField(StringTableEntry slotName, StringTableEntry array, StringTableEntry value)
@ -192,6 +209,20 @@ void ShapeAsset::initializeAsset()
mConstructorFilePath = getOwned() ? expandAssetFilePath(mConstructorFilePath) : mConstructorFilePath;
mDiffuseImposterPath = getOwned() ? expandAssetFilePath(mDiffuseImposterFileName) : mDiffuseImposterFileName;
if (mDiffuseImposterPath == StringTable->EmptyString())
{
String diffusePath = String(mFilePath) + "_imposter.dds";
mDiffuseImposterPath = StringTable->insert(diffusePath.c_str());
}
mNormalImposterPath = getOwned() ? expandAssetFilePath(mNormalImposterFileName) : mNormalImposterFileName;
if (mNormalImposterPath == StringTable->EmptyString())
{
String normalPath = String(mFilePath) + "_imposter_normals.dds";
mNormalImposterPath = StringTable->insert(normalPath.c_str());
}
loadShape();
}
@ -231,6 +262,42 @@ void ShapeAsset::setShapeConstructorFile(const char* pShapeConstructorFile)
refreshAsset();
}
void ShapeAsset::setDiffuseImposterFile(const char* pImageFile)
{
// Sanity!
AssertFatal(pImageFile != NULL, "Cannot use a NULL image file.");
// Fetch image file.
pImageFile = StringTable->insert(pImageFile, true);
// Ignore no change,
if (pImageFile == mDiffuseImposterFileName)
return;
mDiffuseImposterFileName = getOwned() ? expandAssetFilePath(pImageFile) : pImageFile;
// Refresh the asset.
refreshAsset();
}
void ShapeAsset::setNormalImposterFile(const char* pImageFile)
{
// Sanity!
AssertFatal(pImageFile != NULL, "Cannot use a NULL image file.");
// Fetch image file.
pImageFile = StringTable->insert(pImageFile, true);
// Ignore no change,
if (pImageFile == mNormalImposterFileName)
return;
mNormalImposterFileName = getOwned() ? expandAssetFilePath(pImageFile) : pImageFile;
// Refresh the asset.
refreshAsset();
}
void ShapeAsset::_onResourceChanged(const Torque::Path &path)
{
if (path != Torque::Path(mFilePath) )
@ -291,6 +358,10 @@ bool ShapeAsset::loadShape()
return false; //if it failed to load, bail out
}
mShape->setupBillboardDetails(mFilePath, mDiffuseImposterPath, mNormalImposterPath);
//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
@ -402,6 +473,10 @@ StringTableEntry ShapeAsset::getAssetIdByFilename(StringTableEntry fileName)
//acquire and bind the asset, and return it out
shapeAssetId = query.mAssetList[0];
}
else
{
AssetPtr<ShapeAsset> shapeAsset = shapeAssetId; //ensures the fallback is loaded
}
return shapeAssetId;
}
@ -492,25 +567,97 @@ ShapeAnimationAsset* ShapeAsset::getAnimation(S32 index)
}
#ifdef TORQUE_TOOLS
const char* ShapeAsset::generateCachedPreviewImage(S32 resolution)
const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overrideMaterial)
{
if (!mShape)
return "";
TSLastDetail* dt = new TSLastDetail(mShape,
mFilePath,
1,
0,
0,
false,
0,
resolution);
// We're gonna render... make sure we can.
bool sceneBegun = GFX->canCurrentlyRender();
if (!sceneBegun)
GFX->beginScene();
dt->update();
// We need to create our own instance to render with.
TSShapeInstance* shape = new TSShapeInstance(mShape, true);
delete dt;
if (overrideMaterial.isNotEmpty())
{
Material *tMat = dynamic_cast<Material*>(Sim::findObject(overrideMaterial));
if (tMat)
shape->reSkin(tMat->mMapTo, mShape->materialList->getMaterialName(0));
}
// Animate the shape once.
shape->animate(0);
return mFilePath;
// So we don't have to change it everywhere.
const GFXFormat format = GFXFormatR8G8B8A8;
GBitmap* imposter = NULL;
GBitmap* imposterNrml = NULL;
ImposterCapture* imposterCap = new ImposterCapture();
static const MatrixF topXfm(EulerF(-M_PI_F / 2.0f, 0, 0));
static const MatrixF bottomXfm(EulerF(M_PI_F / 2.0f, 0, 0));
MatrixF angMat;
S32 mip = 0;
PROFILE_START(ShapeAsset_generateCachedPreviewImage);
//dMemset(destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize(format));
F32 rotX = -(mDegToRad(60.0) - 0.5f * M_PI_F);
F32 rotZ = -(mDegToRad(45.0) - 0.5f * M_PI_F);
// We capture the images in a particular order which must
// match the order expected by the imposter renderer.
imposterCap->begin(shape, 0, resolution, mShape->mRadius, mShape->center);
angMat.mul(MatrixF(EulerF(rotX, 0, 0)),
MatrixF(EulerF(0, 0, rotZ)));
imposterCap->capture(angMat, &imposter, &imposterNrml);
imposterCap->end();
PROFILE_END(); // ShapeAsset_generateCachedPreviewImage
delete imposterCap;
delete shape;
String dumpPath = String(mFilePath) + "_Preview.dds";
char* returnBuffer = Con::getReturnBuffer(128);
dSprintf(returnBuffer, 128, "%s", dumpPath.c_str());
/*FileStream stream;
if (stream.open(dumpPath, Torque::FS::File::Write))
destBmp.writeBitmap("png", stream);
stream.close();*/
DDSFile* ddsDest = DDSFile::createDDSFileFromGBitmap(imposter);
ImageUtil::ddsCompress(ddsDest, GFXFormatBC2);
// Finally save the imposters to disk.
FileStream fs;
if (fs.open(returnBuffer, Torque::FS::File::Write))
{
ddsDest->write(fs);
fs.close();
}
delete ddsDest;
delete imposter;
delete imposterNrml;
// If we did a begin then end it now.
if (!sceneBegun)
GFX->endScene();
return returnBuffer;
}
#endif
@ -536,7 +683,7 @@ DefineEngineMethod(ShapeAsset, getAnimation, ShapeAnimationAsset*, (S32 index),
return object->getAnimation(index);
}
DefineEngineMethod(ShapeAsset, getShapeFile, const char*, (), ,
DefineEngineMethod(ShapeAsset, getShapePath, const char*, (), ,
"Gets the shape's file path\n"
"@return The filename of the shape file")
{
@ -557,9 +704,12 @@ DefineEngineMethod(ShapeAsset, getStatusString, String, (), , "get status string
#ifdef TORQUE_TOOLS
DefineEngineMethod(ShapeAsset, generateCachedPreviewImage, const char*, (S32 resolution), (256), "")
DefineEngineMethod(ShapeAsset, generateCachedPreviewImage, const char*, (S32 resolution, const char* overrideMaterialName), (256, ""),
"Generates a baked preview image of the given shapeAsset. Only really used for generating Asset Browser icons.\n"
"@param resolution Optional field for what resolution to bake the preview image at. Must be pow2\n"
"@param overrideMaterialName Optional field for overriding the material used when rendering the shape for the bake.")
{
return object->generateCachedPreviewImage(resolution);
return object->generateCachedPreviewImage(resolution, overrideMaterialName);
}
DefineEngineStaticMethod(ShapeAsset, getAssetIdByFilename, const char*, (const char* filePath), (""),
@ -599,12 +749,10 @@ GuiControl* GuiInspectorTypeShapeAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getInspectObject()->getIdString(), mCaption);
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
const char* id = mInspector->getInspectObject()->getIdString();
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
// Create "Open in ShapeEditor" button

View file

@ -60,6 +60,7 @@
#ifndef _BITSTREAM_H_
#include "core/stream/bitStream.h"
#endif
#include "assetMacroHelpers.h"
//-----------------------------------------------------------------------------
class ShapeAsset : public AssetBase
{
@ -72,6 +73,12 @@ protected:
StringTableEntry mConstructorFilePath;
Resource<TSShape> mShape;
StringTableEntry mDiffuseImposterFileName;
StringTableEntry mDiffuseImposterPath;
StringTableEntry mNormalImposterFileName;
StringTableEntry mNormalImposterPath;
//Material assets we're dependent on and use
Vector<StringTableEntry> mMaterialAssetIds;
Vector<AssetPtr<MaterialAsset>> mMaterialAssets;
@ -169,13 +176,22 @@ public:
inline StringTableEntry getShapeFilePath(void) const { return mFilePath; };
inline StringTableEntry getShapeConstructorFilePath(void) const { return mConstructorFilePath; };
//Imposter images
void setDiffuseImposterFile(const char* pImageFile);
inline StringTableEntry getDiffuseImposterFile(void) const { return mDiffuseImposterFileName; };
inline StringTableEntry getDiffuseImposterFilePath(void) const { return mDiffuseImposterPath; };
void setNormalImposterFile(const char* pImageFile);
inline StringTableEntry getNormalImposterFile(void) const { return mNormalImposterFileName; };
inline StringTableEntry getNormalImposterFilePath(void) const { return mNormalImposterPath; };
static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr<ShapeAsset>* shapeAsset);
static StringTableEntry getAssetIdByFilename(StringTableEntry fileName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* shapeAsset);
#ifdef TORQUE_TOOLS
const char* generateCachedPreviewImage(S32 resolution);
const char* generateCachedPreviewImage(S32 resolution, String overrideMaterial = "");
#endif
protected:
@ -187,6 +203,10 @@ protected:
static bool setShapeConstructorFile(void* obj, const char* index, const char* data) { static_cast<ShapeAsset*>(obj)->setShapeConstructorFile(data); return false; }
static const char* getShapeConstructorFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getShapeConstructorFile(); }
static bool setDiffuseImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast<ShapeAsset*>(obj)->setDiffuseImposterFile(data); return false; }
static const char* getDiffuseImposterFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getDiffuseImposterFile(); }
static bool setNormalImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast<ShapeAsset*>(obj)->setNormalImposterFile(data); return false; }
static const char* getNormalImposterFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getNormalImposterFile(); }
};
#ifdef TORQUE_TOOLS
@ -299,7 +319,7 @@ public: \
Con::errorf("%s(%s)::_set%s() - shape asset failure \"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ShapeAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
return false; \
}\
else if (m##name)\
else if (!m##name)\
{\
Con::errorf("%s(%s)::_set%s() - Couldn't load shape \"%s\"", macroText(className), getName(), macroText(name), _in);\
return false;\
@ -321,47 +341,8 @@ public: \
Resource<TSShape> get##name##Resource() \
{\
return m##name;\
}
#define DECLARE_SHAPEASSET_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
return ret;\
}
#define DECLARE_SHAPEASSET_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
#define DEF_SHAPEASSET_BINDS(className,name)\
DefineEngineMethod(className, get##name, String, (), , "get name")\
{\
return object->get##name(); \
}\
DefineEngineMethod(className, get##name##Asset, String, (), , assetText(name, asset reference))\
{\
return object->m##name##AssetId; \
}\
DefineEngineMethod(className, set##name, bool, (const char* shape), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(shape));\
}
#define INIT_SHAPEASSET(name) \
m##name##Name = StringTable->EmptyString(); \
m##name##AssetId = StringTable->EmptyString(); \
m##name##Asset = NULL; \
m##name = NULL;
}\
bool is##name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
@ -377,46 +358,6 @@ DefineEngineMethod(className, set##name, bool, (const char* shape), , assetText
#endif // SHOW_LEGACY_FILE_FIELDS
#define CLONE_SHAPEASSET(name) \
m##name##Name = other.m##name##Name;\
m##name##AssetId = other.m##name##AssetId;\
m##name##Asset = other.m##name##Asset;\
#define PACKDATA_SHAPEASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
stream->writeString(m##name##Asset.getAssetId());\
}\
else\
stream->writeString(m##name##Name);
#define UNPACKDATA_SHAPEASSET(name)\
if (stream->readFlag())\
{\
m##name##AssetId = stream->readSTString();\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
#define PACK_SHAPEASSET(netconn, name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset.getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name);
#define UNPACK_SHAPEASSET(netconn, name)\
if (stream->readFlag())\
{\
m##name##AssetId = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
#pragma endregion
#pragma region Arrayed Asset Macros
@ -495,7 +436,7 @@ public: \
Con::errorf("%s(%s)::_set%s(%i) - shape asset failure \"%s\" due to [%s]", macroText(className), getName(), macroText(name), index, _in, ShapeAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\
return false; \
}\
else if (bool(m##name[index]) == NULL)\
else if (!m##name[index])\
{\
Con::errorf("%s(%s)::_set%s(%i) - Couldn't load shape \"%s\"", macroText(className), getName(), macroText(name), index, _in);\
return false; \
@ -519,59 +460,8 @@ public: \
if(index >= sm##name##Count || index < 0)\
return ResourceManager::get().load( "" );\
return m##name[index];\
}
#define DECLARE_SHAPEASSET_ARRAY_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
if (!index) return false;\
U32 idx = dAtoi(index);\
if (idx >= sm##name##Count)\
return false;\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data), idx);\
return ret;\
}
#define DECLARE_SHAPEASSET_ARRAY_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
if (!index) return false;\
U32 idx = dAtoi(index);\
if (idx >= sm##name##Count)\
return false;\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data), idx);\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
#define DEF_SHAPEASSET_ARRAY_BINDS(className,name)\
DefineEngineMethod(className, get##name, String, (S32 index), , "get name")\
{\
return object->get##name(index); \
}\
DefineEngineMethod(className, get##name##Asset, String, (S32 index), , assetText(name, asset reference))\
{\
if(index >= className::sm##name##Count || index < 0)\
return "";\
return object->m##name##AssetId[index]; \
}\
DefineEngineMethod(className, set##name, bool, (const char* shape, S32 index), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(shape), index);\
}
#define INIT_SHAPEASSET_ARRAY(name, index) \
{\
m##name##Name[index] = StringTable->EmptyString(); \
m##name##AssetId[index] = StringTable->EmptyString(); \
m##name##Asset[index] = NULL; \
m##name[index] = NULL;\
}
}\
bool is##name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
@ -587,48 +477,6 @@ DefineEngineMethod(className, set##name, bool, (const char* shape, S32 index),
#endif // SHOW_LEGACY_FILE_FIELDS
#define CLONE_SHAPEASSET_ARRAY(name, index) \
{\
m##name##Name[index] = other.m##name##Name[index];\
m##name##AssetId[index] = other.m##name##AssetId[index];\
m##name##Asset[index] = other.m##name##Asset[index];\
}
#define PACKDATA_SHAPEASSET_ARRAY(name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
stream->writeString(m##name##Asset[index].getAssetId());\
}\
else\
stream->writeString(m##name##Name[index]);
#define UNPACKDATA_SHAPEASSET_ARRAY(name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
}\
else\
m##name##Name[index] = stream->readSTString();
#define PACK_SHAPEASSET_ARRAY(netconn, name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset[index].getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name[index]);
#define UNPACK_SHAPEASSET_ARRAY(netconn, name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId[index], index);\
}\
else\
m##name##Name[index] = stream->readSTString();
#pragma endregion
#endif

View file

@ -40,6 +40,10 @@
#include "assets/assetPtr.h"
#endif
#ifndef _SFXSOURCE_H_
#include "sfx/sfxSource.h"
#endif
// Debug Profiling.
#include "platform/profiler.h"
#include "sfx/sfxTypes.h"
@ -103,6 +107,7 @@ ConsoleSetType(TypeSoundAssetId)
//-----------------------------------------------------------------------------
SoundAsset::SoundAsset()
: AssetBase()
{
mSoundFile = StringTable->EmptyString();
mSoundPath = StringTable->EmptyString();
@ -159,7 +164,7 @@ void SoundAsset::initPersistFields()
addField("maxDistance", TypeF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), "Max distance for sound.");
addField("coneInsideAngle", TypeS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), "Cone inside angle.");
addField("coneOutsideAngle", TypeS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), "Cone outside angle.");
addField("coneOutsideVolume", TypeS32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), "Cone outside volume.");
addField("coneOutsideVolume", TypeF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), "Cone outside volume.");
addField("rolloffFactor", TypeF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), "Rolloff factor.");
addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound.");
addField("sourceGroup", TypeSFXSourceName, Offset(mProfileDesc.mSourceGroup, SoundAsset), "Group that sources playing with this description should be put into.");
@ -181,13 +186,7 @@ void SoundAsset::initializeAsset(void)
if (mSoundFile == StringTable->EmptyString())
return;
//ResourceManager::get().getChangedSignal.notify(this, &SoundAsset::_onResourceChanged);
//Ensure our path is expando'd if it isn't already
mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath;
mSoundPath = expandAssetFilePath(mSoundPath);
loadSound();
}
@ -208,7 +207,6 @@ void SoundAsset::onAssetRefresh(void)
//Update
mSoundPath = getOwned() ? expandAssetFilePath(mSoundFile) : mSoundPath;
loadSound();
}
@ -220,12 +218,15 @@ bool SoundAsset::loadSound()
{
Con::errorf("SoundAsset::initializeAsset: Attempted to load file %s but it was not valid!", mSoundFile);
mLoadedState = BadFileReference;
mSFXProfile.setDescription(NULL);
mSFXProfile.setSoundFileName(StringTable->insert(StringTable->EmptyString()));
mSFXProfile.setPreload(false);
return false;
}
else
{// = new SFXProfile(mProfileDesc, mSoundFile, mPreload);
mSFXProfile.setDescription(&mProfileDesc);
mSFXProfile.setSoundFileName(mSoundFile);
mSFXProfile.setSoundFileName(mSoundPath);
mSFXProfile.setPreload(mPreload);
}
@ -254,11 +255,106 @@ void SoundAsset::setSoundFile(const char* pSoundFile)
refreshAsset();
}
StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
{
if (fileName == StringTable->EmptyString())
return StringTable->EmptyString();
StringTableEntry soundAssetId = StringTable->EmptyString();
AssetQuery query;
U32 foundCount = AssetDatabase.findAssetType(&query, "SoundAsset");
if (foundCount != 0)
{
for (U32 i = 0; i < foundCount; i++)
{
SoundAsset* soundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
if (soundAsset && soundAsset->getSoundPath() == fileName)
{
soundAssetId = soundAsset->getAssetId();
AssetDatabase.releaseAsset(query.mAssetList[i]);
break;
}
AssetDatabase.releaseAsset(query.mAssetList[i]);
}
}
return soundAssetId;
}
U32 SoundAsset::getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* soundAsset)
{
(*soundAsset) = assetId;
if (soundAsset->notNull())
{
return (*soundAsset)->mLoadedState;
}
else
{
//Well that's bad, loading the fallback failed.
Con::warnf("SoundAsset::getAssetById - Finding of asset with id %s failed with no fallback asset", assetId);
return AssetErrCode::Failed;
}
}
U32 SoundAsset::getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsset>* soundAsset)
{
AssetQuery query;
U32 foundAssetcount = AssetDatabase.findAssetType(&query, "SoundAsset");
if (foundAssetcount == 0)
{
//Well that's bad, loading the fallback failed.
Con::warnf("MaterialAsset::getAssetByMaterialName - Finding of asset associated with filename %s failed with no fallback asset", fileName);
return AssetErrCode::Failed;
}
else
{
for (U32 i = 0; i < foundAssetcount; i++)
{
SoundAsset* tSoundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
if (tSoundAsset && tSoundAsset->getSoundPath() == fileName)
{
soundAsset->setAssetId(query.mAssetList[i]);
AssetDatabase.releaseAsset(query.mAssetList[i]);
return (*soundAsset)->mLoadedState;
}
AssetDatabase.releaseAsset(query.mAssetList[i]); //cleanup if that's not the one we needed
}
}
//No good match
return AssetErrCode::Failed;
}
DefineEngineMethod(SoundAsset, getSoundPath, const char*, (), , "")
{
return object->getSoundPath();
}
DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zero),
"Plays the sound for this asset.\n"
"@return (sound plays).\n")
{
if (object->getSfxProfile())
{
MatrixF transform;
transform.setPosition(position);
SFXSource* source = SFX->playOnce(object->getSfxProfile(), &transform, NULL, -1);
return source->getId();
}
else
return 0;
}
#ifdef TORQUE_TOOLS
DefineEngineStaticMethod(SoundAsset, getAssetIdByFilename, const char*, (const char* filePath), (""),
"Queries the Asset Database to see if any asset exists that is associated with the provided file path.\n"
"@return The AssetId of the associated asset, if any.")
{
return SoundAsset::getAssetIdByFileName(StringTable->insert(filePath));
}
#endif
IMPLEMENT_CONOBJECT(GuiInspectorTypeSoundAssetPtr);
ConsoleDocClass(GuiInspectorTypeSoundAssetPtr,
@ -276,12 +372,63 @@ void GuiInspectorTypeSoundAssetPtr::consoleInit()
GuiControl * GuiInspectorTypeSoundAssetPtr::constructEditControl()
{
return nullptr;
// Create base filename edit controls
GuiControl* retCtrl = Parent::constructEditControl();
if (retCtrl == NULL)
return retCtrl;
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"SoundAsset\", \"AssetBrowser.changeAsset\", %s, \"\");",
getIdString());
mBrowseButton->setField("Command", szBuffer);
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
// Create "Open in Editor" button
mEditButton = new GuiBitmapButtonCtrl();
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.editAsset(%d.getText());", retCtrl->getId());
mEditButton->setField("Command", szBuffer);
char bitmapName[512] = "ToolsModule:SFXEmitter_image";
mEditButton->setBitmap(StringTable->insert(bitmapName));
mEditButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
mEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
mEditButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
mEditButton->setDataField(StringTable->insert("tooltip"), NULL, "Test play this sound");
mEditButton->registerObject();
addObject(mEditButton);
return retCtrl;
}
bool GuiInspectorTypeSoundAssetPtr::updateRects()
{
return false;
S32 dividerPos, dividerMargin;
mInspector->getDivider(dividerPos, dividerMargin);
Point2I fieldExtent = getExtent();
Point2I fieldPos = getPosition();
mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
if (mBrowseButton != NULL)
{
mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
}
if (mEditButton != NULL)
{
RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
resized |= mEditButton->resize(shapeEdRect.point, shapeEdRect.extent);
}
return resized;
}
IMPLEMENT_CONOBJECT(GuiInspectorTypeSoundAssetId);

View file

@ -57,6 +57,7 @@
#include "sfx/sfxProfile.h"
#endif // !_SFXPROFILE_H_
#include "assetMacroHelpers.h"
class SFXResource;
//-----------------------------------------------------------------------------
@ -122,6 +123,9 @@ public:
bool isLoop() { return mProfileDesc.mIsLooping; }
bool is3D() { return mProfileDesc.mIs3D; }
static StringTableEntry getAssetIdByFileName(StringTableEntry fileName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* materialAsset);
static U32 getAssetByFileName(StringTableEntry fileName, AssetPtr<SoundAsset>* matAsset);
protected:
virtual void initializeAsset(void);
@ -143,7 +147,7 @@ class GuiInspectorTypeSoundAssetPtr : public GuiInspectorTypeFileName
typedef GuiInspectorTypeFileName Parent;
public:
GuiBitmapButtonCtrl* mSoundButton;
GuiBitmapButtonCtrl* mEditButton;
DECLARE_CONOBJECT(GuiInspectorTypeSoundAssetPtr);
static void consoleInit();
@ -168,14 +172,14 @@ public:
/// Declares a sound asset
/// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions
/// </Summary>
#define DECLARE_SOUNDASSET(className, name, profile) public: \
#define DECLARE_SOUNDASSET(className, name) public: \
Resource<SFXResource> m##name;\
StringTableEntry m##name##Name; \
StringTableEntry m##name##AssetId;\
AssetPtr<SoundAsset> m##name##Asset = NULL;\
SFXProfile* m##name##Profile = &profile;\
SFXProfile* m##name##Profile = NULL;\
public: \
const StringTableEntry get##name##File() const { return m##name##Name); }\
const StringTableEntry get##name##File() const { return m##name##Name; }\
void set##name##File(const FileName &_in) { m##name##Name = StringTable->insert(_in.c_str());}\
const AssetPtr<SoundAsset> & get##name##Asset() const { return m##name##Asset; }\
void set##name##Asset(const AssetPtr<SoundAsset> &_in) { m##name##Asset = _in;}\
@ -206,7 +210,7 @@ public: \
}\
else\
{\
StringTableEntry assetId = SoundAsset::getAssetIdByFilename(_in);\
StringTableEntry assetId = SoundAsset::getAssetIdByFileName(_in);\
if (assetId != StringTable->EmptyString())\
{\
m##name##AssetId = assetId;\
@ -231,13 +235,17 @@ public: \
{\
m##name = NULL;\
}\
if(get##name() == StringTable->EmptyString())\
return true;\
\
if (m##name##Asset.notNull() && m##name##Asset->getStatus() != ShapeAsset::Ok)\
if(get##name() == StringTable->EmptyString())\
return true;\
if (m##name##Asset.notNull() && m##name##Asset->getStatus() != SoundAsset::Ok)\
{\
Con::errorf("%s(%s)::_set%s() - sound asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, ShapeAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
Con::errorf("%s(%s)::_set%s() - sound asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name), _in, SoundAsset::getAssetErrstrn(m##name##Asset->getStatus()).c_str());\
return false; \
}\
else if (m##name)\
else if (!m##name)\
{\
Con::errorf("%s(%s)::_set%s() - Couldn't load sound \"%s\"", macroText(className), getName(), macroText(name), _in);\
return false;\
@ -259,47 +267,14 @@ public: \
Resource<SFXResource> get##name##Resource() \
{\
return m##name;\
}
#define DECLARE_SOUNDASSET_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
}\
SFXProfile* get##name##Profile()\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
return ret;\
}
#define DECLARE_SOUNDASSET_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
#define DEF_SOUNDASSET_BINDS(className,name)\
DefineEngineMethod(className, get##name, String, (), , "get name")\
{\
return object->get##name(); \
}\
DefineEngineMethod(className, get##name##Asset, String, (), , assetText(name, asset reference))\
{\
return object->m##name##AssetId; \
}\
DefineEngineMethod(className, set##name, bool, (const char* shape), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(shape));\
}
#define INIT_SOUNDASSET(name) \
m##name##Name = StringTable->EmptyString(); \
m##name##AssetId = StringTable->EmptyString(); \
m##name##Asset = NULL; \
m##name = NULL;\
if (get##name() != StringTable->EmptyString() && m##name##Asset.notNull())\
return m##name##Asset->getSfxProfile();\
return NULL;\
}\
bool is##name##Valid() { return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
@ -315,46 +290,164 @@ DefineEngineMethod(className, set##name, bool, (const char* shape), , assetText
#endif // TORQUE_SHOW_LEGACY_FILE_FIELDS
#define CLONE_SOUNDASSET(name) \
m##name##Name = other.m##name##Name;\
m##name##AssetId = other.m##name##AssetId;\
m##name##Asset = other.m##name##Asset;\
#pragma endregion
#define PACKDATA_SOUNDASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
#pragma region Arrayed Asset Macros
#define DECLARE_SOUNDASSET_ARRAY(className,name,max) public: \
static const U32 sm##name##Count = max;\
Resource<SFXResource> m##name[max];\
StringTableEntry m##name##Name[max]; \
StringTableEntry m##name##AssetId[max];\
AssetPtr<SoundAsset> m##name##Asset[max];\
SFXProfile* m##name##Profile[max];\
public: \
const StringTableEntry get##name##File(const U32& index) const { return m##name##Name[index]; }\
void set##name##File(const FileName &_in, const U32& index) { m##name##Name[index] = StringTable->insert(_in.c_str());}\
const AssetPtr<SoundAsset> & get##name##Asset(const U32& index) const { return m##name##Asset[index]; }\
void set##name##Asset(const AssetPtr<SoundAsset> &_in, const U32& index) { m##name##Asset[index] = _in;}\
\
bool _set##name(StringTableEntry _in, const U32& index)\
{\
stream->writeString(m##name##Asset.getAssetId());\
if(m##name##AssetId[index] != _in || m##name##Name[index] != _in)\
{\
if(index >= sm##name##Count || index < 0) \
return false;\
if (_in == NULL || _in == StringTable->EmptyString())\
{\
m##name##Name[index] = StringTable->EmptyString();\
m##name##AssetId[index] = StringTable->EmptyString();\
m##name##Asset[index] = NULL;\
m##name[index] = NULL;\
return true;\
}\
else if(_in[0] == '$' || _in[0] == '#')\
{\
m##name##Name[index] = _in;\
m##name##AssetId[index] = StringTable->EmptyString();\
m##name##Asset[index] = NULL;\
m##name[index] = NULL;\
return true;\
}\
\
if (AssetDatabase.isDeclaredAsset(_in))\
{\
m##name##AssetId[index] = _in;\
\
U32 assetState = SoundAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\
\
if (SoundAsset::Ok == assetState)\
{\
m##name##Name[index] = StringTable->EmptyString();\
}\
}\
else\
{\
StringTableEntry assetId = SoundAsset::getAssetIdByFileName(_in);\
if (assetId != StringTable->EmptyString())\
{\
m##name##AssetId[index] = assetId;\
if(SoundAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]) == SoundAsset::Ok)\
{\
m##name##Name[index] = StringTable->EmptyString();\
}\
}\
else\
{\
m##name##Name[index] = _in;\
m##name##AssetId[index] = StringTable->EmptyString();\
m##name##Asset[index] = NULL;\
}\
}\
}\
if (get##name(index) != StringTable->EmptyString() && m##name##Asset[index].notNull())\
{\
m##name[index] = m##name##Asset[index]->getSoundResource();\
}\
else\
{\
m##name[index] = NULL;\
}\
if(get##name(index) == StringTable->EmptyString())\
return true;\
\
if (m##name##Asset[index].notNull() && m##name##Asset[index]->getStatus() != SoundAsset::Ok)\
{\
Con::errorf("%s(%s)::_set%s(%i) - sound asset failure\"%s\" due to [%s]", macroText(className), getName(), macroText(name),index, _in, SoundAsset::getAssetErrstrn(m##name##Asset[index]->getStatus()).c_str());\
return false; \
}\
else if (!m##name[index])\
{\
Con::errorf("%s(%s)::_set%s(%i) - Couldn't load sound \"%s\"", macroText(className), getName(), macroText(name),index, _in);\
return false;\
}\
return true;\
}\
else\
stream->writeString(m##name##Name);
#define UNPACKDATA_SOUNDASSET(name)\
if (stream->readFlag())\
\
const StringTableEntry get##name(const U32& index) const\
{\
m##name##AssetId = stream->readSTString();\
_set##name(m##name##AssetId);\
if (m##name##Asset[index] && (m##name##Asset[index]->getSoundPath() != StringTable->EmptyString()))\
return m##name##Asset[index]->getSoundPath();\
else if (m##name##AssetId[index] != StringTable->EmptyString())\
return m##name##AssetId[index];\
else if (m##name##Name[index] != StringTable->EmptyString())\
return StringTable->insert(m##name##Name[index]);\
else\
return StringTable->EmptyString();\
}\
else\
m##name##Name = stream->readSTString();
#define PACK_SOUNDASSET(netconn, name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
Resource<SFXResource> get##name##Resource(const U32& id) \
{\
NetStringHandle assetIdStr = m##name##Asset.getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
if(id >= sm##name##Count || id < 0)\
return ResourceManager::get().load( "" );\
return m##name[id];\
}\
else\
stream->writeString(m##name##Name);
#define UNPACK_SOUNDASSET(netconn, name)\
if (stream->readFlag())\
SFXProfile* get##name##Profile(const U32& id)\
{\
m##name##AssetId = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId);\
if (get##name(id) != StringTable->EmptyString() && m##name##Asset[id].notNull())\
return m##name##Asset[id]->getSfxProfile();\
return NULL;\
}\
else\
m##name##Name = stream->readSTString();
bool is##name##Valid(const U32& id) {return (get##name(id) != StringTable->EmptyString() && m##name##Asset[id]->getStatus() == AssetBase::Ok); }
#ifdef TORQUE_SHOW_LEGACY_FILE_FIELDS
#define INITPERSISTFIELD_IMAGEASSET_ARRAY(name, arraySize, consoleClass, docs) \
addProtectedField(#name, TypeSoundFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs)); \
addProtectedField(assetText(name, Asset), TypeImageAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));
#else
#define INITPERSISTFIELD_SOUNDASSET_ARRAY(name, arraySize, consoleClass, docs) \
addProtectedField(#name, TypeSoundFilename, Offset(m##name##Name, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, docs), AbstractClassRep::FIELD_HideInInspectors); \
addProtectedField(assetText(name, Asset), TypeSoundAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));
#endif
#define LOAD_SOUNDASSET_ARRAY(name, index)\
if (m##name##AssetId[index] != StringTable->EmptyString())\
{\
S32 assetState = SoundAsset::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\
if (assetState == SoundAsset::Ok )\
{\
m##name##Name[index] = StringTable->EmptyString();\
}\
else Con::warnf("Warning: %s::LOAD_SOUNDASSET_ARRAY(%s[%i])-%s", mClassName, m##name##AssetId[index], index, ImageAsset::getAssetErrstrn(assetState).c_str());\
}
#define assetEnumNameConcat(x,suff)(new std::string( x + std::string(#suff)))->c_str()
#define INITPERSISTFIELD_SOUNDASSET_ENUMED(name, enumType, maxValue, consoleClass, docs) \
for (U32 i = 0; i < maxValue; i++)\
{\
const enumType itter = static_cast<enumType>(i);\
const char* enumString = castConsoleTypeToString(static_cast<enumType>(itter));\
if (enumString && enumString[0])\
{\
addField(assetEnumNameConcat(enumString, File), TypeSoundFilename, Offset(m##name##Name[0], consoleClass) + sizeof(m##name##Name[0])*i, assetText(name, docs), AbstractClassRep::FIELD_HideInInspectors); \
addField(assetEnumNameConcat(enumString, Asset), TypeSoundAssetId, Offset(m##name##AssetId[0], consoleClass) + sizeof(m##name##AssetId[0])*i, assetText(name, asset reference.));\
}\
}
#pragma endregion
#endif // _ASSET_BASE_H_

View file

@ -247,7 +247,7 @@ bool TerrainAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr<Terrai
{
//Didn't find any assets
//If possible, see if we can run an in-place import and the get the asset from that
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
Con::warnf("TerrainAsset::getAssetByFilename - Attempted to in-place import a terrainFile(%s) that had no associated asset", fileName);
#endif
@ -465,11 +465,9 @@ GuiControl* GuiInspectorTypeTerrainAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"TerrainAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getInspectObject()->getIdString(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
const char* id = mInspector->getInspectObject()->getIdString();
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
// Create "Open in ShapeEditor" button

View file

@ -40,6 +40,10 @@
#include "assets/assetPtr.h"
#endif
#include "T3D/assets/assetImporter.h"
StringTableEntry TerrainMaterialAsset::smNoTerrainMaterialAssetFallback = NULL;
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(TerrainMaterialAsset);
@ -85,6 +89,35 @@ ConsoleSetType(TypeTerrainMaterialAssetPtr)
Con::warnf("(TypeTerrainMaterialAssetPtr) - Cannot set multiple args to a single asset.");
}
ConsoleType(assetIdString, TypeTerrainMaterialAssetId, const char*, ASSET_ID_FIELD_PREFIX)
ConsoleGetType(TypeTerrainMaterialAssetId)
{
// Fetch asset Id.
return *((const char**)(dptr));
}
ConsoleSetType(TypeTerrainMaterialAssetId)
{
// Was a single argument specified?
if (argc == 1)
{
// Yes, so fetch field value.
const char* pFieldValue = argv[0];
// Fetch asset Id.
StringTableEntry* assetId = (StringTableEntry*)(dptr);
// Update asset value.
*assetId = StringTable->insert(pFieldValue);
return;
}
// Warn.
Con::warnf("(TypeTerrainMaterialAssetId) - Cannot set multiple args to a single asset.");
}
//-----------------------------------------------------------------------------
TerrainMaterialAsset::TerrainMaterialAsset()
@ -92,24 +125,41 @@ TerrainMaterialAsset::TerrainMaterialAsset()
mScriptFile = StringTable->EmptyString();
mScriptPath = StringTable->EmptyString();
mMatDefinitionName = StringTable->EmptyString();
mMaterialDefinition = nullptr;
mFXMaterialDefinition = nullptr;
}
//-----------------------------------------------------------------------------
TerrainMaterialAsset::~TerrainMaterialAsset()
{
if (mMaterialDefinition)
mMaterialDefinition->safeDeleteObject();
if (mFXMaterialDefinition)
mFXMaterialDefinition->safeDeleteObject();
}
//-----------------------------------------------------------------------------
void TerrainMaterialAsset::consoleInit()
{
Parent::consoleInit();
Con::addVariable("$Core::NoTerrainMaterialAssetFallback", TypeString, &smNoTerrainMaterialAssetFallback,
"The assetId of the material to display when the requested material asset is missing.\n"
"@ingroup GFX\n");
smNoTerrainMaterialAssetFallback = StringTable->insert(Con::getVariable("$Core::NoTerrainMaterialAssetFallback"));
}
void TerrainMaterialAsset::initPersistFields()
{
// Call parent.
Parent::initPersistFields();
//addField("shaderGraph", TypeRealString, Offset(mShaderGraphFile, TerrainMaterialAsset), "");
addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset),
&setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
//addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset),
// &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
addField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset), "");
addField("materialDefinitionName", TypeString, Offset(mMatDefinitionName, TerrainMaterialAsset), "Name of the material definition this asset is for.");
}
@ -121,28 +171,66 @@ void TerrainMaterialAsset::initializeAsset()
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
if (mMatDefinitionName == StringTable->EmptyString())
{
mLoadedState = Failed;
return;
}
if (size() != 0 && mScriptPath == StringTable->EmptyString())
{
mLoadedState = EmbeddedDefinition;
}
else if (Torque::FS::IsScriptFile(mScriptPath))
{
if (!Sim::findObject(mMatDefinitionName))
{
if (Con::executeFile(mScriptPath, false, false))
{
mLoadedState = ScriptLoaded;
}
else
{
mLoadedState = Failed;
}
}
else
{
mLoadedState = DefinitionAlreadyExists;
}
}
loadMaterial();
}
void TerrainMaterialAsset::onAssetRefresh()
{
mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
if (Torque::FS::IsScriptFile(mScriptPath))
Con::executeFile(mScriptPath, false, false);
if (mMatDefinitionName != StringTable->EmptyString())
if (mMatDefinitionName == StringTable->EmptyString())
{
TerrainMaterial* matDef;
if (!Sim::findObject(mMatDefinitionName, matDef))
{
Con::errorf("TerrainMaterialAsset: Unable to find the Material %s", mMatDefinitionName);
mLoadedState = Failed;
return;
}
//matDef->reload();
if (Torque::FS::IsScriptFile(mScriptPath))
{
//Since we're refreshing, we can assume that the file we're executing WILL have an existing definition.
//But that definition, whatever it is, is the 'correct' one, so we enable the Replace Existing behavior
//when the engine encounters a named object conflict.
String redefineBehaviorPrev = Con::getVariable("$Con::redefineBehavior");
Con::setVariable("$Con::redefineBehavior", "replaceExisting");
if (Con::executeFile(mScriptPath, false, false))
mLoadedState = ScriptLoaded;
else
mLoadedState = Failed;
//And now that we've executed, switch back to the prior behavior
Con::setVariable("$Con::redefineBehavior", redefineBehaviorPrev.c_str());
}
loadMaterial();
}
void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
@ -152,10 +240,6 @@ void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
pScriptFile = StringTable->insert(pScriptFile, true);
// Ignore no change,
if (pScriptFile == mScriptFile)
return;
// Update.
mScriptFile = getOwned() ? expandAssetFilePath(pScriptFile) : pScriptFile;
@ -165,41 +249,190 @@ void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
//------------------------------------------------------------------------------
void TerrainMaterialAsset::loadMaterial()
{
if (mMaterialDefinition)
mMaterialDefinition->safeDeleteObject();
if (mFXMaterialDefinition)
mFXMaterialDefinition->safeDeleteObject();
if (mLoadedState == EmbeddedDefinition)
{
if (size() != 0)
{
for (U32 i = 0; i < size(); i++)
{
TerrainMaterial* terrMat = dynamic_cast<TerrainMaterial*>(getObject(i));
if (terrMat)
{
mMaterialDefinition = terrMat;
mLoadedState = Ok;
mMaterialDefinition->setInternalName(getAssetId());
continue;
}
//Otherwise, check if it's our FX material
Material* fxMat = dynamic_cast<Material*>(getObject(i));
if (fxMat)
{
mFXMaterialDefinition = fxMat;
//mMaterialDefinition->setInternalName(getAssetId());
mFXMaterialDefinition->reload();
continue;
}
}
}
if(mLoadedState == Ok)
return;
}
else if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && mMatDefinitionName != StringTable->EmptyString())
{
TerrainMaterial* matDef;
if (!Sim::findObject(mMatDefinitionName, matDef))
{
Con::errorf("TerrainMaterialAsset: Unable to find the Material %s", mMatDefinitionName);
mLoadedState = BadFileReference;
return;
}
mMaterialDefinition = matDef;
mLoadedState = Ok;
mMaterialDefinition->setInternalName(getAssetId());
return;
}
mLoadedState = Failed;
}
//------------------------------------------------------------------------------
void TerrainMaterialAsset::copyTo(SimObject* object)
{
// Call to parent.
Parent::copyTo(object);
}
StringTableEntry TerrainMaterialAsset::getAssetIdByMaterialName(StringTableEntry matName)
//------------------------------------------------------------------------------
U32 TerrainMaterialAsset::getAssetByMaterialName(StringTableEntry matName, AssetPtr<TerrainMaterialAsset>* matAsset)
{
StringTableEntry materialAssetId = StringTable->EmptyString();
AssetQuery* query = new AssetQuery();
U32 foundCount = AssetDatabase.findAssetType(query, "TerrainMaterialAsset");
if (foundCount == 0)
AssetQuery query;
U32 foundAssetcount = AssetDatabase.findAssetType(&query, "TerrainMaterialAsset");
if (foundAssetcount == 0)
{
//Didn't work, so have us fall back to a placeholder asset
materialAssetId = StringTable->insert("Core_Rendering:noMaterial");
matAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
if (matAsset->isNull())
{
//Well that's bad, loading the fallback failed.
Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of asset associated with material name %s failed with no fallback asset", matName);
return AssetErrCode::Failed;
}
//handle noshape not being loaded itself
if ((*matAsset)->mLoadedState == BadFileReference)
{
Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
return AssetErrCode::BadFileReference;
}
Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
(*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
return AssetErrCode::UsingFallback;
}
else
{
for (U32 i = 0; i < foundAssetcount; i++)
{
TerrainMaterialAsset* tMatAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query.mAssetList[i]);
if (tMatAsset && tMatAsset->getMaterialDefinitionName() == matName)
{
matAsset->setAssetId(query.mAssetList[i]);
AssetDatabase.releaseAsset(query.mAssetList[i]);
return (*matAsset)->mLoadedState;
}
AssetDatabase.releaseAsset(query.mAssetList[i]); //cleanup if that's not the one we needed
}
}
//Somehow we failed to bind an asset, so just use the fallback and mark the failure
matAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
(*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
return AssetErrCode::UsingFallback;
}
StringTableEntry TerrainMaterialAsset::getAssetIdByMaterialName(StringTableEntry matName)
{
if (matName == StringTable->EmptyString())
return StringTable->EmptyString();
StringTableEntry materialAssetId = TerrainMaterialAsset::smNoTerrainMaterialAssetFallback;
AssetQuery query;
U32 foundCount = AssetDatabase.findAssetType(&query, "TerrainMaterialAsset");
if (foundCount != 0)
{
for (U32 i = 0; i < foundCount; i++)
{
TerrainMaterialAsset* matAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query->mAssetList[i]);
TerrainMaterialAsset* matAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query.mAssetList[i]);
if (matAsset && matAsset->getMaterialDefinitionName() == matName)
{
materialAssetId = matAsset->getAssetId();
AssetDatabase.releaseAsset(query->mAssetList[i]);
AssetDatabase.releaseAsset(query.mAssetList[i]);
break;
}
AssetDatabase.releaseAsset(query->mAssetList[i]);
AssetDatabase.releaseAsset(query.mAssetList[i]);
}
}
return materialAssetId;
}
U32 TerrainMaterialAsset::getAssetById(StringTableEntry assetId, AssetPtr<TerrainMaterialAsset>* materialAsset)
{
(*materialAsset) = assetId;
if (materialAsset->notNull())
{
return (*materialAsset)->mLoadedState;
}
else
{
//Didn't work, so have us fall back to a placeholder asset
materialAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
if (materialAsset->isNull())
{
//Well that's bad, loading the fallback failed.
Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed with no fallback asset", assetId);
return AssetErrCode::Failed;
}
//handle noshape not being loaded itself
if ((*materialAsset)->mLoadedState == BadFileReference)
{
Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed, and fallback asset reported error of Bad File Reference.", assetId);
return AssetErrCode::BadFileReference;
}
Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed, utilizing fallback asset", assetId);
(*materialAsset)->mLoadedState = AssetErrCode::UsingFallback;
return AssetErrCode::UsingFallback;
}
}
SimObjectPtr<TerrainMaterial> TerrainMaterialAsset::findMaterialDefinitionByAssetId(StringTableEntry assetId)
{
SimSet* terrainMatSet;
if (!Sim::findObject("TerrainMaterialSet", terrainMatSet))
{
return nullptr;
}
SimObjectPtr<TerrainMaterial> matDef = dynamic_cast<TerrainMaterial*>(terrainMatSet->findObjectByInternalName(assetId));
return matDef;
}
#ifdef TORQUE_TOOLS
DefineEngineStaticMethod(TerrainMaterialAsset, getAssetIdByMaterialName, const char*, (const char* materialName), (""),
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
@ -207,6 +440,48 @@ DefineEngineStaticMethod(TerrainMaterialAsset, getAssetIdByMaterialName, const c
{
return TerrainMaterialAsset::getAssetIdByMaterialName(StringTable->insert(materialName));
}
//MaterialAsset::findMaterialDefinitionByAssetId("Prototyping:Detail")
DefineEngineStaticMethod(TerrainMaterialAsset, findMaterialDefinitionByAssetId, S32, (const char* assetId), (""),
"Queries the MaterialSet to see if any MaterialDefinition exists that is associated to the provided assetId.\n"
"@return The MaterialDefinition Id associated to the assetId, if any")
{
SimObjectPtr<TerrainMaterial> matDef = TerrainMaterialAsset::findMaterialDefinitionByAssetId(StringTable->insert(assetId));
if (matDef.isNull())
return SimObjectId(0);
else
return matDef->getId();
}
DefineEngineMethod(TerrainMaterialAsset, getScriptPath, const char*, (), ,
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
"@return The AssetId of the associated asset, if any.")
{
return object->getScriptPath();
}
DefineEngineMethod(TerrainMaterialAsset, getMaterialDefinition, S32, (), ,
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
"@return The AssetId of the associated asset, if any.")
{
SimObjectPtr<TerrainMaterial> mat = object->getMaterialDefinition();
if (mat.isValid())
return mat->getId();
else
return 0;
}
DefineEngineMethod(TerrainMaterialAsset, getFXMaterialDefinition, S32, (), ,
"Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
"@return The AssetId of the associated asset, if any.")
{
SimObjectPtr<Material> mat = object->getFXMaterialDefinition();
if (mat.isValid())
return mat->getId();
else
return 0;
}
#endif
//-----------------------------------------------------------------------------
// GuiInspectorTypeAssetId
@ -230,68 +505,36 @@ void GuiInspectorTypeTerrainMaterialAssetPtr::consoleInit()
GuiControl* GuiInspectorTypeTerrainMaterialAssetPtr::constructEditControl()
{
// Create base filename edit controls
mUseHeightOverride = true;
mHeightOverride = 100;
mMatEdContainer = new GuiControl();
mMatEdContainer->registerObject();
addObject(mMatEdContainer);
// Create "Open in ShapeEditor" button
mMatPreviewButton = new GuiBitmapButtonCtrl();
const char* matAssetId = getData();
TerrainMaterialAsset* matAsset = AssetDatabase.acquireAsset< TerrainMaterialAsset>(matAssetId);
TerrainMaterial* materialDef = nullptr;
char bitmapName[512] = "ToolsModule:material_editor_n_image";
/*if (!Sim::findObject(matAsset->getMaterialDefinitionName(), materialDef))
{
Con::errorf("GuiInspectorTypeTerrainMaterialAssetPtr::constructEditControl() - unable to find material in asset");
}
else
{
mMatPreviewButton->setBitmap(materialDef->mDiffuseMapFilename[0]);
}*/
mMatPreviewButton->setPosition(0, 0);
mMatPreviewButton->setExtent(100,100);
GuiControl* retCtrl = Parent::constructEditControl();
if (retCtrl == NULL)
return retCtrl;
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"TerrainMaterialAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
mInspector->getComponentGroupTargetId(), mCaption);
mMatPreviewButton->setField("Command", szBuffer);
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"TerrainMaterialAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
mMatPreviewButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
mMatPreviewButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
mMatPreviewButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
StringBuilder strbld;
strbld.append(matAsset->getMaterialDefinitionName());
strbld.append("\n");
strbld.append("Open this asset in the Material Editor");
// Create "Open in Editor" button
mEditButton = new GuiBitmapButtonCtrl();
mMatPreviewButton->setDataField(StringTable->insert("tooltip"), NULL, strbld.data());
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.editAsset(%d.getText());", retCtrl->getId());
mEditButton->setField("Command", szBuffer);
_registerEditControl(mMatPreviewButton);
//mMatPreviewButton->registerObject();
mMatEdContainer->addObject(mMatPreviewButton);
char bitmapName[512] = "ToolsModule:material_editor_n_image";
mEditButton->setBitmap(StringTable->insert(bitmapName));
mMatAssetIdTxt = new GuiTextEditCtrl();
mMatAssetIdTxt->registerObject();
mMatAssetIdTxt->setActive(false);
mEditButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
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 Terrain Material Editor");
mMatAssetIdTxt->setText(matAssetId);
mEditButton->registerObject();
addObject(mEditButton);
mMatAssetIdTxt->setBounds(100, 0, 150, 18);
mMatEdContainer->addObject(mMatAssetIdTxt);
return mMatEdContainer;
return retCtrl;
}
bool GuiInspectorTypeTerrainMaterialAssetPtr::updateRects()
@ -305,41 +548,32 @@ bool GuiInspectorTypeTerrainMaterialAssetPtr::updateRects()
mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
if (mMatEdContainer != nullptr)
if (mBrowseButton != NULL)
{
mMatPreviewButton->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
}
if (mMatPreviewButton != nullptr)
if (mEditButton != NULL)
{
mMatPreviewButton->resize(Point2I::Zero, Point2I(100, 100));
}
if (mMatAssetIdTxt != nullptr)
{
mMatAssetIdTxt->resize(Point2I(100, 0), Point2I(mEditCtrlRect.extent.x - 100, 18));
RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
resized |= mEditButton->resize(shapeEdRect.point, shapeEdRect.extent);
}
return resized;
}
void GuiInspectorTypeTerrainMaterialAssetPtr::setMaterialAsset(String assetId)
IMPLEMENT_CONOBJECT(GuiInspectorTypeTerrainMaterialAssetId);
ConsoleDocClass(GuiInspectorTypeTerrainMaterialAssetId,
"@brief Inspector field type for Terrain Material Assets\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeTerrainMaterialAssetId::consoleInit()
{
mTargetObject->setDataField(mCaption, "", assetId);
Parent::consoleInit();
//force a refresh
SimObject* obj = mInspector->getInspectObject();
mInspector->inspectObject(obj);
}
DefineEngineMethod(GuiInspectorTypeTerrainMaterialAssetPtr, setMaterialAsset, void, (String assetId), (""),
"Gets a particular shape animation asset for this shape.\n"
"@param animation asset index.\n"
"@return Shape Animation Asset.\n")
{
if (assetId == String::EmptyString)
return;
return object->setMaterialAsset(assetId);
ConsoleBaseType::getType(TypeTerrainMaterialAssetId)->setInspectorFieldType("GuiInspectorTypeTerrainMaterialAssetId");
}

View file

@ -47,7 +47,13 @@
#include "gui/editor/guiInspectorTypes.h"
#endif
#ifndef _TERRMATERIAL_H_
#include "terrain/terrMaterial.h"
#endif
#ifndef _MATERIALDEFINITION_H_
#include "materials/materialDefinition.h"
#endif
//-----------------------------------------------------------------------------
class TerrainMaterialAsset : public AssetBase
@ -58,23 +64,55 @@ class TerrainMaterialAsset : public AssetBase
StringTableEntry mScriptPath;
StringTableEntry mMatDefinitionName;
SimObjectPtr<TerrainMaterial> mMaterialDefinition;
SimObjectPtr<Material> mFXMaterialDefinition;
public:
static StringTableEntry smNoTerrainMaterialAssetFallback;
enum TerrainMaterialAssetErrCode
{
ScriptLoaded = AssetErrCode::Extended,
DefinitionAlreadyExists,
EmbeddedDefinition,
Extended
};
public:
TerrainMaterialAsset();
virtual ~TerrainMaterialAsset();
/// Set up some global script interface stuff.
static void consoleInit();
/// Engine.
static void initPersistFields();
virtual void copyTo(SimObject* object);
static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
void loadMaterial();
StringTableEntry getMaterialDefinitionName() { return mMatDefinitionName; }
SimObjectPtr<TerrainMaterial> getMaterialDefinition() { return mMaterialDefinition; }
SimObjectPtr<Material> getFXMaterialDefinition() { return mFXMaterialDefinition; }
void setScriptFile(const char* pScriptFile);
inline StringTableEntry getScriptFile(void) const { return mScriptFile; };
inline StringTableEntry getScriptPath(void) const { return mScriptPath; };
/// <summary>
/// Looks for any assets that uses the provided Material Definition name.
/// If none are found, attempts to auto-import the material definition if the
/// material definition exists.
/// </summary>
/// <param name="matName">Material Definition name to look for</param>
/// <returns>AssetId of matching asset.</returns>
static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
static U32 getAssetById(StringTableEntry assetId, AssetPtr<TerrainMaterialAsset>* materialAsset);
static SimObjectPtr<TerrainMaterial> findMaterialDefinitionByAssetId(StringTableEntry assetId);
static U32 getAssetByMaterialName(StringTableEntry matName, AssetPtr<TerrainMaterialAsset>* matAsset);
/// Declare Console Object.
DECLARE_CONOBJECT(TerrainMaterialAsset);
@ -82,30 +120,40 @@ protected:
virtual void initializeAsset();
virtual void onAssetRefresh(void);
static bool setScriptFile(void *obj, const char *index, const char *data) { static_cast<TerrainMaterialAsset*>(obj)->setScriptFile(data); return false; }
static bool setScriptFile(void *obj, const char *index, const char *data)
{
static_cast<TerrainMaterialAsset*>(obj)->setScriptFile(data);
return false;
}
static const char* getScriptFile(void* obj, const char* data) { return static_cast<TerrainMaterialAsset*>(obj)->getScriptFile(); }
};
DefineConsoleType(TypeTerrainMaterialAssetPtr, TerrainMaterialAsset)
DefineConsoleType(TypeTerrainMaterialAssetId, String)
//-----------------------------------------------------------------------------
// TypeAssetId GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeTerrainMaterialAssetPtr : public GuiInspectorField
class GuiInspectorTypeTerrainMaterialAssetPtr : public GuiInspectorTypeFileName
{
typedef GuiInspectorField Parent;
typedef GuiInspectorTypeFileName Parent;
public:
GuiControl* mMatEdContainer;
GuiBitmapButtonCtrl *mMatPreviewButton;
GuiTextEditCtrl *mMatAssetIdTxt;
GuiBitmapButtonCtrl* mEditButton;
DECLARE_CONOBJECT(GuiInspectorTypeTerrainMaterialAssetPtr);
static void consoleInit();
virtual GuiControl* constructEditControl();
virtual bool updateRects();
void setMaterialAsset(String assetId);
};
class GuiInspectorTypeTerrainMaterialAssetId : public GuiInspectorTypeTerrainMaterialAssetPtr
{
typedef GuiInspectorTypeTerrainMaterialAssetPtr Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeTerrainMaterialAssetId);
static void consoleInit();
};
#endif // _ASSET_BASE_H_

File diff suppressed because it is too large Load diff

View file

@ -261,6 +261,16 @@ public:
/// </summary>
F32 animFPS;
/// <summary>
/// When importing a shape animation, this indicates if it should automatically add a standard suffix onto the name
/// </summary>
bool AlwaysAddShapeAnimationSuffix;
/// <summary>
/// If AlwaysAddShapeAnimationSuffix is on, this is the suffix to be added
/// </summary>
String AddedShapeAnimationSuffix;
//
//Collision
/// <summary>
@ -409,6 +419,15 @@ public:
/// </summary>
bool SoundsCompressed;
/// When importing an image, this indicates if it should automatically add a standard suffix onto the name
/// </summary>
bool AlwaysAddSoundSuffix;
/// <summary>
/// If AlwaysAddSoundSuffix is on, this is the suffix to be added
/// </summary>
String AddedSoundSuffix;
public:
AssetImportConfig();
virtual ~AssetImportConfig();
@ -492,15 +511,20 @@ public:
/// </summary>
bool dirty;
enum
{
NotProcessed=0,
Processed,
Skipped,
UseForDependencies,
Error,
Imported
};
/// <summary>
/// Is this asset item marked to be skipped. If it is, it's usually due to being marked as deleted
/// </summary>
bool skip;
/// <summary>
/// Has the asset item been processed
/// </summary>
bool processed;
U32 importStatus;
/// <summary>
/// Is this specific asset item generated as part of the import process of another item
@ -564,6 +588,10 @@ public:
{
return o.getId() == this->getId();
}
bool canImport() {
return (importStatus == AssetImportObject::Processed);
}
};
/// <summary>
@ -629,6 +657,8 @@ class AssetImporter : public SimObject
/// </summary>
String finalImportedAssetPath;
bool mDumpLogs;
public:
AssetImporter();
virtual ~AssetImporter();
@ -780,11 +810,17 @@ public:
void processMaterialAsset(AssetImportObject* assetItem);
/// <summary>
/// Process a specific AssetImportObject that is an ShapeAsset type to prepare it for importing
/// Process a specific AssetImportObject that is an ShapeAnimationAsset type to prepare it for importing
/// <para>@param assetItem, The AssetImportObject to process</para>
/// </summary>
void processShapeAsset(AssetImportObject* assetItem);
/// <summary>
/// Process a specific AssetImportObject that is an ShapeAsset type to prepare it for importing
/// <para>@param assetItem, The AssetImportObject to process</para>
/// </summary>
void processShapeAnimationAsset(AssetImportObject* assetItem);
/// <summary>
/// Process a specific ShapeAsset AssetImportObject with a material id in order to parse and handle the materials listed in the shape file
/// <para>@param assetItem, The AssetImportObject to process</para>
@ -878,6 +914,12 @@ public:
/// </summary>
Torque::Path importShapeAnimationAsset(AssetImportObject* assetItem);
/// <summary>
/// Iterates over all the items in the current session and acquires them, which jumpstarts the loading/init'ng process on them, making the available for use immediately
/// <para>@param assetItem, if null, will loop over and recurse the main import asset items, if a specific AssetImportObject is passed in, it will recurse it's children</para>
/// </summary>
void acquireAssets(AssetImportObject* assetItem = nullptr);
//
/// <summary>
/// Gets the currently active import configuration
@ -885,9 +927,15 @@ public:
/// </summary>
AssetImportConfig* getImportConfig() { return activeImportConfig; }
void setImportConfig(AssetImportConfig* importConfig) {
if(importConfig != nullptr)
void setImportConfig(AssetImportConfig* importConfig)
{
if (importConfig != nullptr)
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Loading import config: %s!", importConfig->getName());
activityLog.push_back(importLogBuffer);
activeImportConfig = importConfig;
}
}
/// <summary>
@ -922,16 +970,30 @@ public:
return imagePath;
}
static inline const char* makeFullPath(const String& path)
{
char qualifiedFilePath[2048];
Platform::makeFullPathName(path.c_str(), qualifiedFilePath, sizeof(qualifiedFilePath));
return qualifiedFilePath;
}
//
void setTargetModuleId(const String& moduleId) { targetModuleId = moduleId; }
const String& getTargetModuleId() { return targetModuleId; }
String getFolderPrefixedName(AssetImportObject* assetItem)
{
String renamedAssetName = assetItem->assetName;
S32 dirIndex = assetItem->filePath.getDirectoryCount() - 1;
while (dirIndex > -1)
{
renamedAssetName = assetItem->assetName;
String owningFolder = assetItem->filePath.getDirectory(dirIndex);
renamedAssetName = owningFolder + "_" + renamedAssetName;
if (AssetDatabase.isDeclaredAsset(renamedAssetName))
{
dirIndex--;
continue;
}
break;
}
return renamedAssetName;
}
};

View file

@ -6,113 +6,116 @@
//Console Functions
DefineEngineMethod(AssetImportConfig, loadImportConfig, void, (Settings* configSettings, String configName), (nullAsType<Settings*>(), ""),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Loads the provided import config to the importer.\n"
"@param configSettings A Settings object containing the import configs.\n"
"@param configName The specific name of the config to be used.")
{
return object->loadImportConfig(configSettings, configName);
}
DefineEngineMethod(AssetImporter, setTargetPath, void, (String path), (""),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Sets the target path the importing assets will be put into.\n"
"@param A string of the target path.")
{
return object->setTargetPath(path);
}
DefineEngineMethod(AssetImporter, resetImportSession, void, (bool forceResetSession), (false),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Resets the importer's import session. All existing import items, logs, etc will be cleared.")
{
return object->resetImportSession(forceResetSession);
}
DefineEngineMethod(AssetImporter, dumpActivityLog, void, (), ,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Dumps the import activity log. If the importer is set to, it will save to file, otherwise dump to console.")
{
return object->dumpActivityLog();
}
DefineEngineMethod(AssetImporter, getActivityLogLineCount, S32, (),,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Gets the number of lines in the import activity log.\n"
"@return The number of lines in the import activity log.")
{
return object->getActivityLogLineCount();
}
DefineEngineMethod(AssetImporter, getActivityLogLine, String, (S32 i), (0),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
DefineEngineMethod(AssetImporter, getActivityLogLine, String, (S32 index), (0),
"Gets a specific line in the import activity log.\n"
"@param index The index of the line to be returned.\n"
"@return The string of the requested line of the activity log")
{
return object->getActivityLogLine(0);
return object->getActivityLogLine(index);
}
DefineEngineMethod(AssetImporter, autoImportFile, String, (String path, String typeHint), ("", ""),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Run the full import process on a specific file.\n"
"@return If import is successful, the assetId of the new asset. If it failed, an empty string.")
{
return object->autoImportFile(path, typeHint);
}
DefineEngineMethod(AssetImporter, addImportingFile, AssetImportObject*, (String path), (""),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Adds a filepath to the current importing session.\n"
"@param path The path to the file to be imported.\n"
"@return The AssetImportObject from the import session.")
{
return object->addImportingFile(path);
}
DefineEngineMethod(AssetImporter, addImportingAssetItem, void, (AssetImportObject* assetItem, AssetImportObject* parentItem), (nullAsType< AssetImportObject*>(), nullAsType< AssetImportObject*>()),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Adds an existing AssetImportObject to the current improting session.\n"
"@param assetItem The AssetImportObject to be added to the import session.\n"
"@param parentItem An AssetImportObject that to act as the parent of the item being added.")
{
return object->addImportingAssetItem(assetItem, parentItem);
}
DefineEngineMethod(AssetImporter, processImportingAssets, void, (), ,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Processes the importing assets.")
{
return object->processImportAssets();
}
DefineEngineMethod(AssetImporter, validateImportingAssets, bool, (), ,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
DefineEngineMethod(AssetImporter, hasImportIssues, bool, (), ,
"Validates the status of the importing items.\n"
"@return False if there are no issues, true if there are importing issues")
{
return object->validateAssets();
}
DefineEngineMethod(AssetImporter, resolveAssetItemIssues, void, (AssetImportObject* assetItem), (nullAsType< AssetImportObject*>()),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Runs the issue resolver to attempt to correct any simple issues, such as utilizing the config's settings to resolve collisions.")
{
object->resolveAssetItemIssues(assetItem);
}
DefineEngineMethod(AssetImporter, importAssets, void, (),,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Runs the actual import action on the items.")
{
return object->importAssets();
object->importAssets();
object->acquireAssets();
}
DefineEngineMethod(AssetImporter, getAssetItemCount, S32, (),,
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Gets the number of importing asset items.\n"
"@return The number of importing asset items")
{
return object->getAssetItemCount();
}
DefineEngineMethod(AssetImporter, getAssetItem, AssetImportObject*, (S32 index), (0),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Gets a specific import asset item.\n"
"@param index The index of the AssetImportObject to be returned.\n"
"@return AssetImportObject")
{
return object->getAssetItem(index);
}
DefineEngineMethod(AssetImporter, getAssetItemChildCount, S32, (AssetImportObject* assetItem), (nullAsType< AssetImportObject*>()),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Gets number of child items for a given importing asset item.\n"
"@param assetItem The AssetImportObject to get the number of children of.\n"
"@return The number of child items")
{
if (assetItem == nullptr)
return 0;
@ -121,8 +124,10 @@ DefineEngineMethod(AssetImporter, getAssetItemChildCount, S32, (AssetImportObjec
}
DefineEngineMethod(AssetImporter, getAssetItemChild, AssetImportObject*, (AssetImportObject* assetItem, S32 index), (nullAsType< AssetImportObject*>(), 0),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Gets a specific child item of a given importing asset item.\n"
"@param assetItem The AssetImportObject to get the child from.\n"
"@param index The index of the child to get.\n"
"@return The child AssetImportObect")
{
if (assetItem == nullptr)
return nullptr;
@ -131,31 +136,15 @@ DefineEngineMethod(AssetImporter, getAssetItemChild, AssetImportObject*, (AssetI
}
DefineEngineMethod(AssetImporter, deleteImportingAsset, void, (AssetImportObject* assetItem), (nullAsType< AssetImportObject*>()),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Deletes an importing AssetImportObject from the import session.\n"
"@param assetItem The AssetImportObject to delete.")
{
return object->deleteImportingAsset(assetItem);
}
DefineEngineMethod(AssetImporter, setImportConfig, void, (AssetImportConfig* importConfig), (nullAsType< AssetImportConfig*>()),
"Creates a new script asset using the targetFilePath.\n"
"@return The bool result of calling exec")
"Sets the import config to be used via a AssetImportConfig object.\n"
"@param importConfig The AssetImportConfig object to use.")
{
return object->setImportConfig(importConfig);
}
/*DefineEngineFunction(enumColladaForImport, bool, (const char* shapePath, const char* ctrl, bool loadCachedDts), ("", "", true),
"(string shapePath, GuiTreeViewCtrl ctrl) Collect scene information from "
"a COLLADA file and store it in a GuiTreeView control. This function is "
"used by the COLLADA import gui to show a preview of the scene contents "
"prior to import, and is probably not much use for anything else.\n"
"@param shapePath COLLADA filename\n"
"@param ctrl GuiTreeView control to add elements to\n"
"@param loadCachedDts dictates if it should try and load the cached dts file if it exists"
"@return true if successful, false otherwise\n"
"@ingroup Editors\n"
"@internal")
{
return enumColladaForImport(shapePath, ctrl, loadCachedDts);
}*/

View file

@ -0,0 +1,298 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2013 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.
//-----------------------------------------------------------------------------
#pragma once
//general class-injection hooks for asset support. not all cases are needed for every class/usage.
//-----------------------------------------------------------------------------
/// INDIVIDUALIZED CLASS ENTRIES
//-----------------------------------------------------------------------------
//iniitalization
#define INIT_ASSET(name) \
m##name##Name = StringTable->EmptyString(); \
m##name##AssetId = StringTable->EmptyString(); \
m##name##Asset = NULL;\
m##name = NULL;
//load asset into memory by looking up the ID, spew a warning if anything goes wrong
#define LOAD_ASSET(name, assetClass)\
if (m##name##AssetId != StringTable->EmptyString())\
{\
S32 assetState = assetClass::getAssetById(m##name##AssetId, &m##name##Asset);\
if (assetState == assetClass::Ok )\
{\
m##name##Name = StringTable->EmptyString();\
}\
else Con::warnf("Warning: %s::LOAD_ASSET(%s)-%s", mClassName, m##name##AssetId, assetClass::getAssetErrstrn(assetState).c_str());\
}
// copy constructor
#define CLONE_ASSET(name) \
m##name##Name = other.m##name##Name;\
m##name##AssetId = other.m##name##AssetId;\
m##name##Asset = other.m##name##Asset;\
m##name = other.m##name
// addProtectedField acessors
#define DECLARE_ASSET_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
return ret;\
}
// addProtectedField acessors for networked objects (sets a flag)
#define DECLARE_ASSET_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data));\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
//network send - datablock
#define PACKDATA_ASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
stream->writeString(m##name##Asset.getAssetId());\
}\
else\
stream->writeString(m##name##Name);
//network recieve - datablock
#define UNPACKDATA_ASSET(name)\
if (stream->readFlag())\
{\
m##name##AssetId = stream->readSTString();\
_set##name(m##name##AssetId);\
}\
else\
{\
m##name##Name = stream->readSTString();\
_set##name(m##name##Name);\
}
//network send - object-instance
#define PACK_ASSET(netconn, name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset.getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name);
//network recieve - object-instance
#define UNPACK_ASSET(netconn, name)\
if (stream->readFlag())\
{\
m##name##AssetId = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId);\
}\
else\
m##name##Name = stream->readSTString();
//script methods for class.asset acces
//declare general get<entry>, get<entry>Asset and set<entry> methods
#define DEF_ASSET_BINDS(className,name)\
DefineEngineMethod(className, get##name, String, (), , "get name")\
{\
return object->get##name(); \
}\
DefineEngineMethod(className, get##name##Asset, String, (), , assetText(name, asset reference))\
{\
return object->m##name##AssetId; \
}\
DefineEngineMethod(className, set##name, bool, (const char* assetName), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(assetName));\
}
//-----------------------------------------------------------------------------
/// ARRAY CLASS ENTRIES
//-----------------------------------------------------------------------------
//iniitalization
#define INIT_ASSET_ARRAY(name, index) \
{\
m##name##Name[index] = StringTable->EmptyString(); \
m##name##AssetId[index] = StringTable->EmptyString(); \
m##name##Asset[index] = NULL;\
m##name[index] = NULL;\
}
//load asset into memory by looking up the ID, spew a warning if anything goes wrong
#define LOAD_ASSET_ARRAY(name, index, assetClass)\
if (m##name##AssetId[index] != StringTable->EmptyString())\
{\
S32 assetState = assetClass::getAssetById(m##name##AssetId[index], &m##name##Asset[index]);\
if (assetState == assetClass::Ok )\
{\
m##name##Name[index] = StringTable->EmptyString();\
}\
else Con::warnf("Warning: %s::LOAD_ASSET(%s[%d])-%s", mClassName, m##name##AssetId[index],index, assetClass::getAssetErrstrn(assetState).c_str());\
}
// copy constructor
#define CLONE_ASSET_ARRAY(name, index) \
{\
m##name##Name[index] = other.m##name##Name[index];\
m##name##AssetId[index] = other.m##name##AssetId[index];\
m##name##Asset[index] = other.m##name##Asset[index];\
m##name[index] = other.m##name[index];\
}
// addProtectedField acessors
#define DECLARE_ASSET_ARRAY_SETGET(className, name)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
if(!index) return false;\
U32 idx = dAtoi(index);\
if (idx >= sm##name##Count)\
return false;\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data), idx);\
return ret;\
}
// addProtectedField acessors for networked objects (sets a flag)
#define DECLARE_ASSET_ARRAY_NET_SETGET(className, name, bitmask)\
static bool _set##name##Data(void* obj, const char* index, const char* data)\
{\
if (!index) return false;\
U32 idx = dAtoi(index);\
if (idx >= sm##name##Count)\
return false;\
bool ret = false;\
className* object = static_cast<className*>(obj);\
ret = object->_set##name(StringTable->insert(data), idx);\
if(ret)\
object->setMaskBits(bitmask);\
return ret;\
}
//network send - datablock
#define PACKDATA_ASSET_ARRAY(name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
stream->writeString(m##name##Asset[index].getAssetId());\
}\
else\
stream->writeString(m##name##Name[index]);
//network recieve - datablock
#define UNPACKDATA_ASSET_ARRAY(name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
}\
else\
{\
m##name##Name[index] = stream->readSTString();\
_set##name(m##name##Name[index], index);\
}
//network send - object-instance
#define PACK_ASSET_ARRAY(netconn, name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
NetStringHandle assetIdStr = m##name##Asset[index].getAssetId();\
netconn->packNetStringHandleU(stream, assetIdStr);\
}\
else\
stream->writeString(m##name##Name[index]);
//network recieve - object-instance
#define UNPACK_ASSET_ARRAY(netconn, name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = StringTable->insert(netconn->unpackNetStringHandleU(stream).getString());\
_set##name(m##name##AssetId[index], index);\
}\
else\
{\
m##name##Name[index] = stream->readSTString();\
_set##name(m##name##Name[index], index);\
}
//script methods for class.asset acces
//declare general get<entry>, get<entry>Asset and set<entry> methods
//signatures are:
//using DiffuseMap as an example
//material.getDiffuseMap(%layer); //returns the raw file referenced
//material.getDiffuseMapAsset(%layer); //returns the asset id
//material.setDiffuseMap(%texture, %layer); //tries to set the asset and failing that attempts a flat file reference
#define DEF_ASSET_ARRAY_BINDS(className,name)\
DefineEngineMethod(className, get##name, const char*, (S32 index), , "get name")\
{\
return object->get##name(index); \
}\
DefineEngineMethod(className, get##name##Asset, const char*, (S32 index), , assetText(name, asset reference))\
{\
if(index >= className::sm##name##Count || index < 0)\
return "";\
return object->m##name##AssetId[index]; \
}\
DefineEngineMethod(className, set##name, bool, (const char* assetName, S32 index), , assetText(name,assignment. first tries asset then flat file.))\
{\
return object->_set##name(StringTable->insert(assetName), index);\
}
//-----------------------------------------------------------------------------
/// ARRAYS REFERENCED VIA ENUM CLASS ENTRIES
//-----------------------------------------------------------------------------
//
// substite these in to see the enum strings and assigned values
//network send - object-instance
#define PACKDATA_ASSET_ARRAY_ENUMED(name, enumType, index )\
{\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
stream->writeString(m##name##Asset[index].getAssetId());\
const char* enumString = castConsoleTypeToString(static_cast<enumType>(index));\
Con::printf("pack: %s = %s",enumString, m##name##AssetId[index]);\
}\
else\
stream->writeString(m##name##Name[index]);\
}
//network recieve - object-instance
#define UNPACKDATA_ASSET_ARRAY_ENUMED(name, enumType, index )\
{\
if (stream->readFlag())\
{\
m##name##AssetId[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
const char* enumString = castConsoleTypeToString(static_cast<enumType>(index));\
Con::printf("unpack: %s = %s",enumString, m##name##AssetId[index]);\
}\
else\
{\
m##name##Name[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
}\
}

View file

@ -185,7 +185,7 @@ GuiControl* GuiInspectorTypeStateMachineAssetPtr::constructEditControl()
// Change filespec
char szBuffer[512];
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"StateMachineAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
mInspector->getComponentGroupTargetId(), mCaption);
mInspector->getIdString(), mCaption);
mBrowseButton->setField("Command", szBuffer);
// Create "Open in ShapeEditor" button

View file

@ -222,7 +222,6 @@ bool ConvexShape::protectedSetSurface( void *object, const char *index, const ch
*/
String t = data;
S32 len = t.length();
dSscanf( data, "%g %g %g %g %g %g %g %i %g %g %g %g %f", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z,
&matID, &offset.x, &offset.y, &scale.x, &scale.y, &rot);
@ -290,7 +289,7 @@ ConvexShape::ConvexShape()
mSurfaceUVs.clear();
mSurfaceTextures.clear();
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
}
ConvexShape::~ConvexShape()
@ -318,10 +317,10 @@ void ConvexShape::initPersistFields()
addGroup( "Internal" );
addProtectedField( "surface", TypeRealString, NULL, &protectedSetSurface, &defaultProtectedGetFn,
addProtectedField( "surface", TypeRealString, 0, &protectedSetSurface, &defaultProtectedGetFn,
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
addProtectedField( "surfaceTexture", TypeRealString, NULL, &protectedSetSurfaceTexture, &defaultProtectedGetFn,
addProtectedField( "surfaceTexture", TypeRealString, 0, &protectedSetSurfaceTexture, &defaultProtectedGetFn,
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
endGroup( "Internal" );
@ -528,7 +527,7 @@ U32 ConvexShape::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
if ( stream->writeFlag( mask & UpdateMask ) )
{
PACK_MATERIALASSET(conn, Material);
PACK_ASSET(conn, Material);
U32 surfCount = mSurfaces.size();
stream->writeInt( surfCount, 32 );
@ -584,7 +583,7 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
if ( stream->readFlag() ) // UpdateMask
{
UNPACK_MATERIALASSET(conn, Material);
UNPACK_ASSET(conn, Material);
mSurfaces.clear();
mSurfaceUVs.clear();
@ -961,17 +960,6 @@ bool ConvexShape::castRay( const Point3F &start, const Point3F &end, RayInfo *in
VectorF rayDir( end - start );
rayDir.normalizeSafe();
if ( false )
{
PlaneF plane( Point3F(0,0,0), Point3F(0,0,1) );
Point3F sp( 0,0,-1 );
Point3F ep( 0,0,1 );
F32 t = plane.intersect( sp, ep );
Point3F hitPnt;
hitPnt.interpolate( sp, ep, t );
}
for ( S32 i = 0; i < planeCount; i++ )
{
// Don't hit the back-side of planes.
@ -1376,8 +1364,6 @@ void ConvexShape::_updateGeometry( bool updateCollision )
{
U32 count = faceList[i].triangles.size();
S32 matID = mSurfaceUVs[i].matID;
mSurfaceBuffers[mSurfaceUVs[i].matID].mPrimCount += count;
mSurfaceBuffers[mSurfaceUVs[i].matID].mVertCount += count * 3;
}
@ -1429,9 +1415,6 @@ void ConvexShape::_updateGeometry( bool updateCollision )
{
if (mSurfaceBuffers[i].mVertCount > 0)
{
U32 primCount = mSurfaceBuffers[i].mPrimCount;
U32 vertCount = mSurfaceBuffers[i].mVertCount;
mSurfaceBuffers[i].mVertexBuffer.set(GFX, mSurfaceBuffers[i].mVertCount, GFXBufferTypeStatic);
VertexType *pVert = mSurfaceBuffers[i].mVertexBuffer.lock();
@ -2171,4 +2154,4 @@ void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vecto
}
}
DEF_MATERIALASSET_BINDS(ConvexShape, Material);
DEF_ASSET_BINDS(ConvexShape, Material);

View file

@ -138,14 +138,14 @@ public:
// The name of the Material we will use for rendering
DECLARE_MATERIALASSET(surfaceMaterial, Material);
DECLARE_MATERIALASSET_SETGET(surfaceMaterial, Material);
DECLARE_ASSET_SETGET(surfaceMaterial, Material);
// The actual Material instance
BaseMatInstance* materialInst;
surfaceMaterial()
{
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
materialInst = NULL;
}
@ -264,7 +264,7 @@ protected:
protected:
DECLARE_MATERIALASSET(ConvexShape, Material);
DECLARE_MATERIALASSET_SETGET(ConvexShape, Material);
DECLARE_ASSET_SETGET(ConvexShape, Material);
// The actual Material instance
BaseMatInstance* mMaterialInst;

View file

@ -116,7 +116,7 @@ DebrisData::DebrisData()
terminalVelocity = 0.0f;
ignoreWater = true;
INIT_SHAPEASSET(Shape);
INIT_ASSET(Shape);
}
//#define TRACK_DEBRIS_DATA_CLONES
@ -152,7 +152,7 @@ DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(
terminalVelocity = other.terminalVelocity;
ignoreWater = other.ignoreWater;
CLONE_SHAPEASSET(Shape);
CLONE_ASSET(Shape);
textureName = other.textureName;
explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
@ -382,7 +382,7 @@ void DebrisData::packData(BitStream* stream)
stream->writeString( textureName );
PACKDATA_SHAPEASSET(Shape);
PACKDATA_ASSET(Shape);
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{
@ -426,7 +426,7 @@ void DebrisData::unpackData(BitStream* stream)
textureName = stream->readSTString();
UNPACKDATA_SHAPEASSET(Shape);
UNPACKDATA_ASSET(Shape);
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{

View file

@ -84,7 +84,7 @@ struct DebrisData : public GameBaseData
bool ignoreWater;
DECLARE_SHAPEASSET(DebrisData, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(DebrisData, Shape);
DECLARE_ASSET_SETGET(DebrisData, Shape);
StringTableEntry textureName;

View file

@ -76,7 +76,7 @@ ConsoleDocClass( DecalData,
DecalData::DecalData()
{
size = 5;
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
lifeSpan = 5000;
fadeTime = 1000;
@ -258,7 +258,7 @@ void DecalData::packData( BitStream *stream )
stream->write( lookupName );
stream->write( size );
PACKDATA_MATERIALASSET(Material);
PACKDATA_ASSET(Material);
stream->write( lifeSpan );
stream->write( fadeTime );
@ -287,7 +287,7 @@ void DecalData::unpackData( BitStream *stream )
assignName(lookupName);
stream->read( &size );
UNPACKDATA_MATERIALASSET(Material);
UNPACKDATA_ASSET(Material);
_updateMaterial();
stream->read( &lifeSpan );

View file

@ -78,7 +78,7 @@ class DecalData : public SimDataBlock
F32 fadeEndPixelSize;
DECLARE_MATERIALASSET(DecalData, Material);
DECLARE_MATERIALASSET_SETGET(DecalData, Material);
DECLARE_ASSET_SETGET(DecalData, Material);
/// Material instance for decal.
BaseMatInstance *matInst;
@ -139,4 +139,4 @@ inline SimSet* DecalData::getSet()
return set;
}
#endif // _DECALDATA_H_
#endif // _DECALDATA_H_

View file

@ -59,7 +59,8 @@ RenderMeshExample::RenderMeshExample()
// Set it as a "static" object that casts shadows
mTypeMask |= StaticObjectType | StaticShapeObjectType;
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
mMaterialInst = NULL;
}
RenderMeshExample::~RenderMeshExample()
@ -143,7 +144,7 @@ U32 RenderMeshExample::packUpdate( NetConnection *conn, U32 mask, BitStream *str
// Write out any of the updated editable properties
if (stream->writeFlag(mask & UpdateMask))
{
PACK_MATERIALASSET(conn, Material);
PACK_ASSET(conn, Material);
}
return retMask;
@ -164,7 +165,7 @@ void RenderMeshExample::unpackUpdate(NetConnection *conn, BitStream *stream)
if ( stream->readFlag() ) // UpdateMask
{
UNPACK_MATERIALASSET(conn, Material);
UNPACK_ASSET(conn, Material);
if ( isProperlyAdded() )
updateMaterial();

View file

@ -74,7 +74,7 @@ class RenderMeshExample : public SceneObject
BaseMatInstance* mMaterialInst;
DECLARE_MATERIALASSET(RenderMeshExample, Material);
DECLARE_MATERIALASSET_NET_SETGET(RenderMeshExample, Material, UpdateMask);
DECLARE_ASSET_NET_SETGET(RenderMeshExample, Material, UpdateMask);
// The GFX vertex and primitive buffers
GFXVertexBufferHandle< VertexType > mVertexBuffer;

View file

@ -59,6 +59,7 @@ RenderShapeExample::RenderShapeExample()
mTypeMask |= StaticObjectType | StaticShapeObjectType;
// Make sure to initialize our TSShapeInstance to NULL
INIT_ASSET(Shape);
mShapeInstance = NULL;
}
@ -145,7 +146,7 @@ U32 RenderShapeExample::packUpdate( NetConnection *conn, U32 mask, BitStream *st
// Write out any of the updated editable properties
if ( stream->writeFlag( mask & UpdateMask ) )
{
PACK_SHAPEASSET(conn, Shape);
PACK_ASSET(conn, Shape);
// Allow the server object a chance to handle a new shape
createShape();
@ -169,7 +170,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream)
if ( stream->readFlag() ) // UpdateMask
{
UNPACK_SHAPEASSET(conn, Shape);
UNPACK_ASSET(conn, Shape);
if ( isProperlyAdded() )
createShape();
@ -258,4 +259,4 @@ void RenderShapeExample::prepRenderImage( SceneRenderState *state )
// Allow the shape to submit the RenderInst(s) for itself
mShapeInstance->render( rdata );
}
}

View file

@ -62,7 +62,7 @@ class RenderShapeExample : public SceneObject
// Rendering variables
//--------------------------------------------------------------------------
DECLARE_SHAPEASSET(RenderShapeExample, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(RenderShapeExample, Shape);
DECLARE_ASSET_SETGET(RenderShapeExample, Shape);
// The actual shape instance
TSShapeInstance* mShapeInstance;

View file

@ -230,14 +230,16 @@ ExplosionData::ExplosionData()
faceViewer = false;
soundProfile = NULL;
INIT_ASSET(Sound);
//soundProfile = NULL;
particleEmitter = NULL;
particleEmitterId = 0;
explosionScale.set(1.0f, 1.0f, 1.0f);
playSpeed = 1.0f;
INIT_SHAPEASSET(ExplosionShape);
INIT_ASSET(ExplosionShape);
explosionAnimation = -1;
@ -308,12 +310,12 @@ ExplosionData::ExplosionData(const ExplosionData& other, bool temp_clone) : Game
faceViewer = other.faceViewer;
particleDensity = other.particleDensity;
particleRadius = other.particleRadius;
soundProfile = other.soundProfile;
CLONE_ASSET(Sound);
particleEmitter = other.particleEmitter;
particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr
explosionScale = other.explosionScale;
playSpeed = other.playSpeed;
CLONE_SHAPEASSET(ExplosionShape);
CLONE_ASSET(ExplosionShape);
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
@ -358,12 +360,6 @@ ExplosionData::~ExplosionData()
if (!isTempClone())
return;
if (soundProfile && soundProfile->isTempClone())
{
delete soundProfile;
soundProfile = 0;
}
// particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves
#ifdef TRACK_EXPLOSION_DATA_CLONES
@ -399,8 +395,9 @@ void ExplosionData::initPersistFields()
"of the explosion." );
addField( "playSpeed", TypeF32, Offset(playSpeed, ExplosionData),
"Time scale at which to play the explosionShape <i>ambient</i> sequence." );
addField( "soundProfile", TYPEID< SFXTrack >(), Offset(soundProfile, ExplosionData),
"Non-looping sound effect that will be played at the start of the explosion." );
INITPERSISTFIELD_SOUNDASSET(Sound, ExplosionData, "Sound to play when this explosion explodes.");
addField( "faceViewer", TypeBool, Offset(faceViewer, ExplosionData),
"Controls whether the visual effects of the explosion always face the camera." );
@ -523,7 +520,6 @@ void ExplosionData::initPersistFields()
onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK
onlyKeepClearSubstitutions("emitter");
onlyKeepClearSubstitutions("particleEmitter");
onlyKeepClearSubstitutions("soundProfile");
onlyKeepClearSubstitutions("subExplosion");
Parent::initPersistFields();
}
@ -654,9 +650,10 @@ void ExplosionData::packData(BitStream* stream)
{
Parent::packData(stream);
PACKDATA_SHAPEASSET(ExplosionShape);
PACKDATA_ASSET(ExplosionShape);
PACKDATA_ASSET(Sound);
sfxWrite( stream, soundProfile );
if (stream->writeFlag(particleEmitter))
stream->writeRangedU32(particleEmitter->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
@ -757,9 +754,9 @@ void ExplosionData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
UNPACKDATA_SHAPEASSET(ExplosionShape);
UNPACKDATA_ASSET(ExplosionShape);
sfxRead( stream, &soundProfile );
UNPACKDATA_ASSET(Sound);
if (stream->readFlag())
particleEmitterId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
@ -861,15 +858,27 @@ bool ExplosionData::preload(bool server, String &errorStr)
{
if (Parent::preload(server, errorStr) == false)
return false;
if( !server )
{
String sfxErrorStr;
if( !sfxResolve( &soundProfile, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", sfxErrorStr.c_str());
if (getSound() != StringTable->EmptyString())
{
_setSound(getSound());
if (!getSoundProfile())
{
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
return false;
}
}
if (!particleEmitter && particleEmitterId != 0)
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
{
Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock");
return false;
}
}
if (mExplosionShapeAsset.notNull()) {
@ -1384,7 +1393,7 @@ bool Explosion::explode()
resetWorldBox();
}
SFXProfile* sound_prof = dynamic_cast<SFXProfile*>(mDataBlock->soundProfile);
SFXProfile* sound_prof = mDataBlock->getSoundProfile();
if (sound_prof)
{
soundProfile_clone = sound_prof->cloneAndPerformSubstitutions(ss_object, ss_index);

View file

@ -42,6 +42,7 @@
#endif
#include "T3D/assets/ShapeAsset.h"
#include "T3D/assets/SoundAsset.h"
class ParticleEmitter;
class ParticleEmitterData;
@ -69,7 +70,9 @@ class ExplosionData : public GameBaseData {
S32 particleDensity;
F32 particleRadius;
SFXTrack* soundProfile;
DECLARE_SOUNDASSET(ExplosionData, Sound);
DECLARE_ASSET_SETGET(ExplosionData, Sound);
ParticleEmitterData* particleEmitter;
S32 particleEmitterId;
@ -77,7 +80,7 @@ class ExplosionData : public GameBaseData {
F32 playSpeed;
DECLARE_SHAPEASSET(ExplosionData, ExplosionShape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(ExplosionData, ExplosionShape);
DECLARE_ASSET_SETGET(ExplosionData, ExplosionShape);
S32 explosionAnimation;

View file

@ -50,6 +50,7 @@
#include "renderInstance/renderDeferredMgr.h"
#include "console/engineAPI.h"
#include "T3D/assets/MaterialAsset.h"
#include "T3D/assets/TerrainMaterialAsset.h"
/// This is used for rendering ground cover billboards.
GFXImplementVertexFormat( GCVertex )
@ -459,7 +460,7 @@ GroundCover::GroundCover()
mRandomSeed = 1;
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
mMaterialInst = NULL;
mMatParams = NULL;
@ -520,7 +521,7 @@ GroundCover::GroundCover()
mBillboardRects[i].point.set( 0.0f, 0.0f );
mBillboardRects[i].extent.set( 1.0f, 1.0f );
INIT_SHAPEASSET_ARRAY(Shape, i);
INIT_ASSET_ARRAY(Shape, i);
mShapeInstances[i] = NULL;
@ -564,7 +565,7 @@ void GroundCover::initPersistFields()
addField("shapeFilename", TypeFilename, Offset(mShapeName, GroundCover), MAX_COVERTYPES, "The cover shape filename. [Optional]", AbstractClassRep::FIELD_HideInInspectors);
INITPERSISTFIELD_SHAPEASSET_ARRAY(Shape, MAX_COVERTYPES, GroundCover, "The cover shape. [Optional]");
addField( "layer", TypeTerrainMaterialName, Offset( mLayer, GroundCover ), MAX_COVERTYPES, "Terrain material name to limit coverage to, or blank to not limit." );
addField( "layer", TypeTerrainMaterialAssetId, Offset( mLayer, GroundCover ), MAX_COVERTYPES, "Terrain material assetId to limit coverage to, or blank to not limit." );
addField( "invertLayer", TypeBool, Offset( mInvertLayer, GroundCover ), MAX_COVERTYPES, "Indicates that the terrain material index given in 'layer' is an exclusion mask." );
@ -713,7 +714,7 @@ U32 GroundCover::packUpdate( NetConnection *connection, U32 mask, BitStream *str
// TODO: We could probably optimize a few of these
// based on reasonable units at some point.
PACK_MATERIALASSET(connection, Material);
PACK_ASSET(connection, Material);
stream->write( mRadius );
stream->write( mZOffset );
@ -766,7 +767,7 @@ U32 GroundCover::packUpdate( NetConnection *connection, U32 mask, BitStream *str
stream->write( mBillboardRects[i].extent.x );
stream->write( mBillboardRects[i].extent.y );
PACK_SHAPEASSET_ARRAY(connection, Shape, i);
PACK_ASSET_ARRAY(connection, Shape, i);
}
stream->writeFlag( mDebugRenderCells );
@ -784,7 +785,7 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream )
if (stream->readFlag())
{
UNPACK_MATERIALASSET(connection, Material);
UNPACK_ASSET(connection, Material);
stream->read( &mRadius );
stream->read( &mZOffset );
@ -837,7 +838,7 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream )
stream->read( &mBillboardRects[i].extent.x );
stream->read( &mBillboardRects[i].extent.y );
UNPACK_SHAPEASSET_ARRAY(connection, Shape, i);
UNPACK_ASSET_ARRAY(connection, Shape, i);
}
mDebugRenderCells = stream->readFlag();
@ -1178,6 +1179,7 @@ GroundCoverCell* GroundCover::_generateCell( const Point2I& index,
const bool typeIsShape = mShapeInstances[ type ] != NULL;
const Box3F typeShapeBounds = typeIsShape ? mShapeInstances[ type ]->getShape()->mBounds : Box3F();
const F32 typeWindScale = mWindScale[type];
StringTableEntry typeLayer = mLayer[type];
const bool typeInvertLayer = mInvertLayer[type];

View file

@ -269,7 +269,7 @@ protected:
BaseMatInstance* mMaterialInst;
DECLARE_MATERIALASSET(GroundCover, Material);
DECLARE_MATERIALASSET_NET_SETGET(GroundCover, Material, InitialUpdateMask);
DECLARE_ASSET_NET_SETGET(GroundCover, Material, InitialUpdateMask);
GroundCoverShaderConstData mShaderConstData;
@ -312,7 +312,7 @@ protected:
/// The maximum world space elevation for placement.
F32 mMaxElevation[MAX_COVERTYPES];
/// Terrain material name to limit coverage to, or
/// Terrain material assetId to limit coverage to, or
/// left empty to cover entire terrain.
StringTableEntry mLayer[MAX_COVERTYPES];
@ -341,7 +341,7 @@ protected:
/// The cover shape filenames.
DECLARE_SHAPEASSET_ARRAY(GroundCover, Shape, MAX_COVERTYPES);
DECLARE_SHAPEASSET_ARRAY_NET_SETGET(GroundCover, Shape, -1);
DECLARE_ASSET_ARRAY_NET_SETGET(GroundCover, Shape, -1);
/// The cover shape instances.
TSShapeInstance* mShapeInstances[MAX_COVERTYPES];

View file

@ -238,10 +238,12 @@ void LightningStrikeEvent::process(NetConnection*)
//
LightningData::LightningData()
{
strikeSound = NULL;
INIT_ASSET(StrikeSound);
for (S32 i = 0; i < MaxThunders; i++)
thunderSounds[i] = NULL;
{
INIT_ASSET_ARRAY(ThunderSound, i);
}
for (S32 i = 0; i < MaxTextures; i++)
{
@ -260,12 +262,11 @@ LightningData::~LightningData()
//--------------------------------------------------------------------------
void LightningData::initPersistFields()
{
addField( "strikeSound", TYPEID< SFXTrack >(), Offset(strikeSound, LightningData),
"Sound profile to play when a lightning strike occurs." );
addField( "thunderSounds", TYPEID< SFXTrack >(), Offset(thunderSounds, LightningData), MaxThunders,
"@brief List of thunder sound effects to play.\n\n"
"A random one of these sounds will be played shortly after each strike "
"occurs." );
INITPERSISTFIELD_SOUNDASSET(StrikeSound, LightningData, "Sound to play when lightning STRIKES!");
INITPERSISTFIELD_SOUNDASSET_ARRAY(ThunderSound, MaxThunders, LightningData, "Sounds for thunder.");
addField( "strikeTextures", TypeString, Offset(strikeTextureNames, LightningData), MaxTextures,
"List of textures to use to render lightning strikes." );
@ -290,27 +291,32 @@ bool LightningData::preload(bool server, String &errorStr)
//dQsort(thunderSounds, MaxThunders, sizeof(SFXTrack*), cmpSounds);
for (S32 i = 0; i < MaxThunders; i++) {
if (thunderSounds[i]!= NULL) numThunders++;
}
if (server == false)
{
String sfxErrorStr;
for (U32 i = 0; i < MaxThunders; i++) {
if( !sfxResolve( &thunderSounds[ i ], sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
for (S32 i = 0; i < MaxThunders; i++)
{
_setThunderSound(getThunderSound(i), i);
if (isThunderSoundValid(i) && !getThunderSoundProfile(i))
{
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Cant get an sfxProfile for thunder.");
}
}
if( !sfxResolve( &strikeSound, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
_setStrikeSound(getStrikeSound());
if (isStrikeSoundValid() && !getStrikeSoundProfile())
{
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: can't get sfxProfile from strike sound.");
}
mNumStrikeTextures = 0;
for (U32 i = 0; i < MaxTextures; i++)
for (U32 k = 0; k < MaxTextures; k++)
{
if (strikeTextureNames[i][0])
if (strikeTextureNames[k][0])
{
strikeTextures[i] = GFXTexHandle(strikeTextureNames[i], &GFXStaticTextureProfile, avar("%s() - strikeTextures[%d] (line %d)", __FUNCTION__, i, __LINE__));
strikeTextures[k] = GFXTexHandle(strikeTextureNames[k], &GFXStaticTextureProfile, avar("%s() - strikeTextures[%d] (line %d)", __FUNCTION__, k, __LINE__));
mNumStrikeTextures++;
}
}
@ -329,8 +335,7 @@ void LightningData::packData(BitStream* stream)
U32 i;
for (i = 0; i < MaxThunders; i++)
{
if (stream->writeFlag(thunderSounds[i]))
sfxWrite(stream, thunderSounds[i]);
PACKDATA_ASSET_ARRAY(ThunderSound, i);
}
stream->writeInt(mNumStrikeTextures, 4);
@ -338,7 +343,7 @@ void LightningData::packData(BitStream* stream)
for (i = 0; i < MaxTextures; i++)
stream->writeString(strikeTextureNames[i]);
sfxWrite( stream, strikeSound );
PACKDATA_ASSET(StrikeSound);
}
void LightningData::unpackData(BitStream* stream)
@ -348,10 +353,7 @@ void LightningData::unpackData(BitStream* stream)
U32 i;
for (i = 0; i < MaxThunders; i++)
{
if (stream->readFlag())
sfxRead(stream, &thunderSounds[i]);
else
thunderSounds[i] = NULL;
UNPACKDATA_ASSET_ARRAY(ThunderSound, i);
}
mNumStrikeTextures = stream->readInt(4);
@ -359,7 +361,7 @@ void LightningData::unpackData(BitStream* stream)
for (i = 0; i < MaxTextures; i++)
strikeTextureNames[i] = stream->readSTString();
sfxRead( stream, &strikeSound );
UNPACKDATA_ASSET(StrikeSound);
}
@ -584,7 +586,7 @@ void Lightning::scheduleThunder(Strike* newStrike)
if (t <= 0.03f) {
// If it's really close, just play it...
U32 thunder = sgLightningRand.randI(0, mDataBlock->numThunders - 1);
SFX->playOnce(mDataBlock->thunderSounds[thunder]);
SFX->playOnce(mDataBlock->getThunderSoundProfile(thunder));
} else {
Thunder* pThunder = new Thunder;
pThunder->tRemaining = t;
@ -651,7 +653,7 @@ void Lightning::advanceTime(F32 dt)
// Play the sound...
U32 thunder = sgLightningRand.randI(0, mDataBlock->numThunders - 1);
SFX->playOnce(mDataBlock->thunderSounds[thunder]);
SFX->playOnce(mDataBlock->getThunderSoundProfile(thunder));
} else {
pThunderWalker = &((*pThunderWalker)->next);
}
@ -735,9 +737,9 @@ void Lightning::processEvent(LightningStrikeEvent* pEvent)
MatrixF trans(true);
trans.setPosition( strikePoint );
if (mDataBlock->strikeSound)
if (mDataBlock->getStrikeSoundProfile())
{
SFX->playOnce(mDataBlock->strikeSound, &trans );
SFX->playOnce(mDataBlock->getStrikeSoundProfile(), &trans );
}
}
@ -1337,4 +1339,4 @@ void LightningBolt::update( F32 dt )
isFading = false;
elapsedTime = 0.0f;
}
}
}

View file

@ -41,7 +41,8 @@
#include "gfx/gfxTextureHandle.h"
#include "T3D/assets/ImageAsset.h"
#include "T3D/assets/SoundAsset.h"
class ShapeBase;
class LightningStrikeEvent;
@ -62,8 +63,13 @@ class LightningData : public GameBaseData
//-------------------------------------- Console set variables
public:
SFXTrack* thunderSounds[MaxThunders];
SFXTrack* strikeSound;
DECLARE_SOUNDASSET_ARRAY(LightningData, ThunderSound, MaxThunders);
DECLARE_ASSET_ARRAY_SETGET(LightningData, ThunderSound);
DECLARE_SOUNDASSET(LightningData, StrikeSound);
DECLARE_ASSET_SETGET(LightningData, StrikeSound);
StringTableEntry strikeTextureNames[MaxTextures];
//-------------------------------------- load set variables

View file

@ -122,8 +122,8 @@ ParticleData::ParticleData()
animTexFramesString = NULL; // string of animation frame indices
animTexUVs = NULL; // array of tile vertex UVs
INIT_IMAGEASSET(Texture);
INIT_IMAGEASSET(TextureExt);
INIT_ASSET(Texture);
INIT_ASSET(TextureExt);
constrain_pos = false;
start_angle = 0.0f;
@ -293,7 +293,7 @@ void ParticleData::packData(BitStream* stream)
stream->writeFloat( times[i], 8);
}
//PACKDATA_IMAGEASSET(Texture);
//PACKDATA_ASSET(Texture);
for (i = 0; i < 4; i++)
mathWrite(*stream, texCoords[i]);
@ -307,7 +307,7 @@ void ParticleData::packData(BitStream* stream)
stream->writeInt(framesPerSec, 8);
}
//PACKDATA_IMAGEASSET(TextureExt);
//PACKDATA_ASSET(TextureExt);
stream->writeFlag(constrain_pos);
stream->writeFloat(start_angle/360.0f, 11);
@ -378,7 +378,7 @@ void ParticleData::unpackData(BitStream* stream)
times[i] = stream->readFloat(8);
}
//UNPACKDATA_IMAGEASSET(Texture);
//UNPACKDATA_ASSET(Texture);
for (i = 0; i < 4; i++)
mathRead(*stream, &texCoords[i]);
@ -391,7 +391,7 @@ void ParticleData::unpackData(BitStream* stream)
framesPerSec = stream->readInt(8);
}
//UNPACKDATA_IMAGEASSET(Texture);
//UNPACKDATA_ASSET(Texture);
constrain_pos = stream->readFlag();
start_angle = 360.0f*stream->readFloat(11);
@ -763,12 +763,12 @@ ParticleData::ParticleData(const ParticleData& other, bool temp_clone) : SimData
animTexFramesString = other.animTexFramesString;
animTexFrames = other.animTexFrames; // -- parsed from animTexFramesString
CLONE_IMAGEASSET(Texture);
CLONE_ASSET(Texture);
spinBias = other.spinBias;
randomizeSpinDir = other.randomizeSpinDir;
CLONE_IMAGEASSET(TextureExt);
CLONE_ASSET(TextureExt);
constrain_pos = other.constrain_pos;
start_angle = other.start_angle;
@ -804,4 +804,4 @@ void ParticleData::onPerformSubstitutions()
reload(errorBuffer);
}
DEF_IMAGEASSET_BINDS(ParticleData, Texture);
DEF_ASSET_BINDS(ParticleData, Texture);

View file

@ -87,7 +87,7 @@ class ParticleData : public SimDataBlock
Vector<U8> animTexFrames;
DECLARE_IMAGEASSET(ParticleData, Texture, onImageChanged, GFXStaticTextureSRGBProfile);
DECLARE_IMAGEASSET_SETGET(ParticleData, Texture);
DECLARE_ASSET_SETGET(ParticleData, Texture);
static bool protectedSetSizes(void* object, const char* index, const char* data);
static bool protectedSetTimes(void* object, const char* index, const char* data);
@ -118,7 +118,7 @@ public:
bool randomizeSpinDir;
public:
DECLARE_IMAGEASSET(ParticleData, TextureExt, onImageChanged, GFXStaticTextureSRGBProfile);
DECLARE_IMAGEASSET_SETGET(ParticleData, TextureExt);
DECLARE_ASSET_SETGET(ParticleData, TextureExt);
bool constrain_pos;
F32 start_angle;

View file

@ -1551,13 +1551,10 @@ void ParticleEmitter::updateBBox()
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
{
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
{
Point3F particleSize(part->size * 0.5f);
F32 motion = getMax((part->vel.len() * part->totalLifetime / 1000.0f), 1.0f);
minPt.setMin(part->pos - particleSize - Point3F(motion));
maxPt.setMax(part->pos + particleSize + Point3F(motion));
}
Point3F particleSize(part->size * 0.5f);
F32 motion = getMax((part->vel.len() * part->totalLifetime / 1000.0f), 1.0f);
minPt.setMin(part->pos - particleSize - Point3F(motion));
maxPt.setMax(part->pos + particleSize + Point3F(motion));
}
mObjBox = Box3F(minPt, maxPt);
@ -1675,8 +1672,8 @@ void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const
}
else
{
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
}
updateKeyData( pNew );
@ -1911,42 +1908,21 @@ void ParticleEmitter::copyToVB( const Point3F &camPos, const LinearColorF &ambie
if (mDataBlock->reverseOrder)
{
buffPtr += 4 * (n_parts - 1);
// do sorted-oriented particles
if (mDataBlock->sortParticles)
{
SortParticle* partPtr = orderedVector.address();
for (U32 i = 0; i < n_parts - 1; i++, partPtr++, buffPtr -= 4)
setupRibbon(partPtr->p, partPtr++->p, partPtr--->p, camPos, ambientColor, buffPtr);
}
// do unsorted-oriented particles
else
{
Particle* oldPtr = NULL;
for (Particle* partPtr = part_list_head.next; partPtr != NULL; partPtr = partPtr->next, buffPtr -= 4) {
for (Particle* partPtr = part_list_head.next; partPtr != NULL; partPtr = partPtr->next, buffPtr -= 4)
{
setupRibbon(partPtr, partPtr->next, oldPtr, camPos, ambientColor, buffPtr);
oldPtr = partPtr;
}
}
}
else
{
// do sorted-oriented particles
if (mDataBlock->sortParticles)
{
SortParticle* partPtr = orderedVector.address();
for (U32 i = 0; i < n_parts - 1; i++, partPtr++, buffPtr += 4)
setupRibbon(partPtr->p, partPtr++->p, partPtr--->p, camPos, ambientColor, buffPtr);
}
// do unsorted-oriented particles
else
{
Particle* oldPtr = NULL;
for (Particle* partPtr = part_list_head.next; partPtr != NULL; partPtr = partPtr->next, buffPtr += 4) {
for (Particle* partPtr = part_list_head.next; partPtr != NULL; partPtr = partPtr->next, buffPtr += 4)
{
setupRibbon(partPtr, partPtr->next, oldPtr, camPos, ambientColor, buffPtr);
oldPtr = partPtr;
}
}
}
PROFILE_END();
}
@ -2220,7 +2196,7 @@ void ParticleEmitter::setupOriented( Particle *part,
LinearColorF partCol = mLerp( part->color, ( part->color * ambientColor ), ambientLerp );
const ColorI color = partCol.toColorI();
// Here we deal with UVs for animated particle (oriented)
if (part->dataBlock->animateTexture)
if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty())
{
// Let particle compute the UV indices for current frame
S32 fm = (S32)(part->currentAge*(1.0f/1000.0f)*part->dataBlock->framesPerSec);
@ -2331,7 +2307,7 @@ void ParticleEmitter::setupAligned( const Particle *part,
LinearColorF partCol = mLerp( part->color, ( part->color * ambientColor ), ambientLerp );
const ColorI color = partCol.toColorI();
// Here we deal with UVs for animated particle
if (part->dataBlock->animateTexture)
if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty())
{
// Let particle compute the UV indices for current frame
S32 fm = (S32)(part->currentAge*(1.0f/1000.0f)*part->dataBlock->framesPerSec);
@ -2520,7 +2496,7 @@ void ParticleEmitter::setupRibbon(Particle *part,
ColorI pCol = partCol.toColorI();
// Here we deal with UVs for animated particle (oriented)
if (part->dataBlock->animateTexture)
if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty())
{
// Let particle compute the UV indices for current frame
S32 fm = (S32)(part->currentAge*(1.0f / 1000.0f)*part->dataBlock->framesPerSec);

View file

@ -127,13 +127,13 @@ ConsoleDocClass( PrecipitationData,
//----------------------------------------------------------
PrecipitationData::PrecipitationData()
{
soundProfile = NULL;
INIT_ASSET(Sound);
INIT_IMAGEASSET(Drop);
INIT_ASSET(Drop);
mDropShaderName = StringTable->EmptyString();
INIT_IMAGEASSET(Splash);
INIT_ASSET(Splash);
mSplashShaderName = StringTable->EmptyString();
@ -143,8 +143,7 @@ PrecipitationData::PrecipitationData()
void PrecipitationData::initPersistFields()
{
addField( "soundProfile", TYPEID< SFXTrack >(), Offset(soundProfile, PrecipitationData),
"Looping SFXProfile effect to play while Precipitation is active." );
INITPERSISTFIELD_SOUNDASSET(Sound, PrecipitationData, "Looping SFXProfile effect to play while Precipitation is active.");
addProtectedField( "dropTexture", TypeFilename, Offset(mDropName, PrecipitationData), &_setDropData, &defaultProtectedGetFn,
"@brief Texture filename for drop particles.\n\n"
@ -189,9 +188,16 @@ bool PrecipitationData::preload( bool server, String &errorStr )
{
if( Parent::preload( server, errorStr) == false)
return false;
if (!server)
{
if (getSound() != StringTable->EmptyString())
{
_setSound(getSound());
if( !server && !sfxResolve( &soundProfile, errorStr ) )
return false;
if (!getSoundProfile())
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
}
}
return true;
}
@ -200,13 +206,13 @@ void PrecipitationData::packData(BitStream* stream)
{
Parent::packData(stream);
sfxWrite( stream, soundProfile );
PACKDATA_ASSET(Sound);
PACKDATA_IMAGEASSET(Drop);
PACKDATA_ASSET(Drop);
stream->writeString(mDropShaderName);
PACKDATA_IMAGEASSET(Splash);
PACKDATA_ASSET(Splash);
stream->writeString(mSplashShaderName);
stream->write(mDropsPerSide);
@ -217,13 +223,13 @@ void PrecipitationData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
sfxRead( stream, &soundProfile );
UNPACKDATA_ASSET(Sound);
UNPACKDATA_IMAGEASSET(Drop);
UNPACKDATA_ASSET(Drop);
mDropShaderName = stream->readSTString();
UNPACKDATA_IMAGEASSET(Splash);
UNPACKDATA_ASSET(Splash);
mSplashShaderName = stream->readSTString();
stream->read(&mDropsPerSide);
@ -598,9 +604,9 @@ bool Precipitation::onNewDataBlock( GameBaseData *dptr, bool reload )
{
SFX_DELETE( mAmbientSound );
if ( mDataBlock->soundProfile )
if ( mDataBlock->getSoundProfile())
{
mAmbientSound = SFX->createSource( mDataBlock->soundProfile, &getTransform() );
mAmbientSound = SFX->createSource(mDataBlock->getSoundProfile(), &getTransform() );
if ( mAmbientSound )
mAmbientSound->play();
}
@ -997,7 +1003,7 @@ void Precipitation::initRenderObjects()
// entire or a partially filled vb.
mRainIB.set(GFX, mMaxVBDrops * 6, 0, GFXBufferTypeStatic);
U16 *idxBuff;
mRainIB.lock(&idxBuff, NULL, NULL, NULL);
mRainIB.lock(&idxBuff, NULL, 0, 0);
for( U32 i=0; i < mMaxVBDrops; i++ )
{
//

View file

@ -34,8 +34,9 @@
#endif
#include "T3D/assets/ImageAsset.h"
#include "T3D/assets/SoundAsset.h"
class SFXTrack;
//class SFXTrack;
class SFXSource;
//--------------------------------------------------------------------------
@ -45,30 +46,31 @@ class PrecipitationData : public GameBaseData
typedef GameBaseData Parent;
public:
SFXTrack* soundProfile;
DECLARE_SOUNDASSET(PrecipitationData, Sound);
DECLARE_ASSET_SETGET(PrecipitationData, Sound);
DECLARE_IMAGEASSET(PrecipitationData, Drop, onDropChanged, GFXStaticTextureSRGBProfile); ///< Texture for drop particles
DECLARE_IMAGEASSET_SETGET(PrecipitationData, Drop);
DECLARE_IMAGEASSET(PrecipitationData, Drop, onDropChanged, GFXStaticTextureSRGBProfile); ///< Texture for drop particles
DECLARE_ASSET_SETGET(PrecipitationData, Drop);
StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops
StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops
DECLARE_IMAGEASSET(PrecipitationData, Splash, onSplashChanged, GFXStaticTextureSRGBProfile); ///< Texture for splash particles
DECLARE_IMAGEASSET_SETGET(PrecipitationData, Splash);
DECLARE_IMAGEASSET(PrecipitationData, Splash, onSplashChanged, GFXStaticTextureSRGBProfile); ///< Texture for splash particles
DECLARE_ASSET_SETGET(PrecipitationData, Splash);
StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops
StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops
S32 mDropsPerSide; ///< How many drops are on a side of the raindrop texture.
S32 mSplashesPerSide; ///< How many splash are on a side of the splash texture.
S32 mDropsPerSide; ///< How many drops are on a side of the raindrop texture.
S32 mSplashesPerSide; ///< How many splash are on a side of the splash texture.
PrecipitationData();
DECLARE_CONOBJECT(PrecipitationData);
bool preload( bool server, String& errorStr );
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
PrecipitationData();
DECLARE_CONOBJECT(PrecipitationData);
bool preload( bool server, String& errorStr );
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
void onDropChanged() {}
void onSplashChanged() {}
void onDropChanged() {}
void onSplashChanged() {}
};
struct Raindrop

View file

@ -67,8 +67,10 @@ ConsoleDocClass( Splash,
//--------------------------------------------------------------------------
SplashData::SplashData()
{
soundProfile = NULL;
soundProfileId = 0;
//soundProfile = NULL;
//soundProfileId = 0;
INIT_ASSET(Sound);
scale.set(1, 1, 1);
@ -95,7 +97,9 @@ SplashData::SplashData()
U32 i;
for (i = 0; i < NUM_TEX; i++)
INIT_IMAGEASSET_ARRAY(Texture, i);
{
INIT_IMAGEASSET_ARRAY(Texture, GFXStaticTextureSRGBProfile, i);
}
for( i=0; i<NUM_TIME_KEYS; i++ )
times[i] = 1.0;
@ -112,7 +116,8 @@ SplashData::SplashData()
//--------------------------------------------------------------------------
void SplashData::initPersistFields()
{
addField("soundProfile", TYPEID< SFXProfile >(), Offset(soundProfile, SplashData), "SFXProfile effect to play.\n");
INITPERSISTFIELD_SOUNDASSET(Sound, SplashData, "Sound to play when splash, splashes.");
addField("scale", TypePoint3F, Offset(scale, SplashData), "The scale of this splashing effect, defined as the F32 points X, Y, Z.\n");
addField("emitter", TYPEID< ParticleEmitterData >(), Offset(emitterList, SplashData), NUM_EMITTERS, "List of particle emitters to create at the point of this Splash effect.\n");
addField("delayMS", TypeS32, Offset(delayMS, SplashData), "Time to delay, in milliseconds, before actually starting this effect.\n");
@ -158,6 +163,8 @@ void SplashData::packData(BitStream* stream)
{
Parent::packData(stream);
PACKDATA_ASSET(Sound);
mathWrite(*stream, scale);
stream->write(delayMS);
stream->write(delayVariance);
@ -201,7 +208,7 @@ void SplashData::packData(BitStream* stream)
for( i=0; i<NUM_TEX; i++ )
{
PACKDATA_IMAGEASSET_ARRAY(Texture, i);
PACKDATA_ASSET_ARRAY(Texture, i);
}
}
@ -212,6 +219,8 @@ void SplashData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
UNPACKDATA_ASSET(Sound);
mathRead(*stream, &scale);
stream->read(&delayMS);
stream->read(&delayVariance);
@ -255,7 +264,7 @@ void SplashData::unpackData(BitStream* stream)
for( i=0; i<NUM_TEX; i++ )
{
UNPACKDATA_IMAGEASSET_ARRAY(Texture, i);
UNPACKDATA_ASSET_ARRAY(Texture, i);
}
}
@ -269,6 +278,15 @@ bool SplashData::preload(bool server, String &errorStr)
if (!server)
{
if (getSound() != StringTable->EmptyString())
{
_setSound(getSound());
if(!getSoundProfile())
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
}
S32 i;
for( i=0; i<NUM_EMITTERS; i++ )
{
@ -667,6 +685,14 @@ void Splash::spawnExplosion()
{
if( !mDataBlock->explosion ) return;
/// could just play the explosion one, but explosion could be weapon specific,
/// splash sound could be liquid specific. food for thought.
SFXProfile* sound_prof = mDataBlock->getSoundProfile();
if (sound_prof)
{
SFX->playOnce(sound_prof, &getTransform());
}
Explosion* pExplosion = new Explosion;
pExplosion->onNewDataBlock(mDataBlock->explosion, false);

View file

@ -34,6 +34,7 @@
#include "gfx/gfxTextureHandle.h"
#include "T3D/assets/ImageAsset.h"
#include "T3D/assets/SoundAsset.h"
class ParticleEmitter;
class ParticleEmitterData;
@ -91,8 +92,11 @@ class SplashData : public GameBaseData
};
public:
AudioProfile* soundProfile;
S32 soundProfileId;
//AudioProfile* soundProfile;
//S32 soundProfileId;
DECLARE_SOUNDASSET(SplashData, Sound);
DECLARE_ASSET_SETGET(SplashData, Sound);
ParticleEmitterData* emitterList[NUM_EMITTERS];
S32 emitterIDList[NUM_EMITTERS];
@ -118,7 +122,7 @@ public:
F32 times[ NUM_TIME_KEYS ];
LinearColorF colors[ NUM_TIME_KEYS ];
DECLARE_IMAGEASSET_ARRAY(SplashData, Texture, GFXStaticTextureSRGBProfile, NUM_TEX);
DECLARE_IMAGEASSET_ARRAY(SplashData, Texture, NUM_TEX);
DECLARE_IMAGEASSET_ARRAY_SETGET(SplashData, Texture)
ExplosionData* explosion;

View file

@ -331,7 +331,7 @@ DefineEngineStringlyVariadicMethod(GameConnection, setConnectArgs, void, 3, 17,
"@see GameConnection::onConnect()\n\n")
{
StringStackWrapper args(argc - 2, argv + 2);
ConsoleValueToStringArrayWrapper args(argc - 2, argv + 2);
object->setConnectArgs(args.count(), args);
}
@ -373,7 +373,7 @@ void GameConnection::onConnectionEstablished(bool isInitiator)
mMoveList->init();
const char *argv[MaxConnectArgs + 2];
argv[0] = "onConnect";
argv[1] = NULL; // Filled in later
argv[1] = getIdString();
for(U32 i = 0; i < mConnectArgc; i++)
argv[i + 2] = mConnectArgv[i];
// NOTE: Need to fallback to Con::execute() as IMPLEMENT_CALLBACK does not
@ -493,33 +493,32 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
*errorString = "CR_INVALID_ARGS";
return false;
}
ConsoleValueRef connectArgv[MaxConnectArgs + 3];
ConsoleValue connectArgvValue[MaxConnectArgs + 3];
for(U32 i = 0; i < mConnectArgc+3; i++)
{
connectArgv[i].value = &connectArgvValue[i];
connectArgvValue[i].init();
}
char buffer[256];
Net::addressToString(getNetAddress(), buffer);
ConsoleValue connectArgv[MaxConnectArgs + 3];
for(U32 i = 0; i < mConnectArgc; i++)
{
char argString[256];
stream->readString(argString);
mConnectArgv[i] = dStrdup(argString);
connectArgv[i + 3] = mConnectArgv[i];
connectArgv[i + 3].setString(argString);
}
connectArgvValue[0].setStackStringValue("onConnectRequest");
connectArgvValue[1].setIntValue(0);
char buffer[256];
Net::addressToString(getNetAddress(), buffer);
connectArgvValue[2].setStackStringValue(buffer);
connectArgv[0].setStringTableEntry("onConnectRequest");
connectArgv[1].setInt(0);
connectArgv[2].setString(buffer);
// NOTE: Cannot convert over to IMPLEMENT_CALLBACK as it has variable args.
const char *ret = Con::execute(this, mConnectArgc + 3, connectArgv);
if(ret[0])
ConsoleValue returnValue = Con::execute(this, mConnectArgc + 3, connectArgv);
StringTableEntry returnStr = StringTable->insert(returnValue.getString());
if(returnStr[0])
{
*errorString = ret;
*errorString = returnStr;
return false;
}
return true;
@ -808,7 +807,7 @@ bool GameConnection::isValidControlCameraFov(F32 fov)
return cObj->isValidCameraFov(fov);
}
return NULL;
return false;
}
bool GameConnection::setControlCameraFov(F32 fov)
@ -1088,7 +1087,7 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
void GameConnection::demoPlaybackComplete()
{
static const char* demoPlaybackArgv[1] = { "demoPlaybackComplete" };
static StringStackConsoleWrapper demoPlaybackCmd(1, demoPlaybackArgv);
static StringArrayToConsoleValueWrapper demoPlaybackCmd(1, demoPlaybackArgv);
Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(demoPlaybackCmd.argc, demoPlaybackCmd.argv, false));
Parent::demoPlaybackComplete();
@ -1563,33 +1562,50 @@ void GameConnection::packetDropped(PacketNotify *note)
//----------------------------------------------------------------------------
void GameConnection::play2D(SFXProfile* profile)
void GameConnection::play2D(StringTableEntry assetId)
{
postNetEvent(new Sim2DAudioEvent(profile));
if (AssetDatabase.isDeclaredAsset(assetId))
{
AssetPtr<SoundAsset> tempSoundAsset;
tempSoundAsset = assetId;
postNetEvent(new SimSoundAssetEvent(tempSoundAsset));
}
}
void GameConnection::play3D(SFXProfile* profile, const MatrixF *transform)
void GameConnection::play3D(StringTableEntry assetId, const MatrixF *transform)
{
if ( !transform )
play2D(profile);
play2D(assetId);
else if ( !mControlObject )
postNetEvent(new Sim3DAudioEvent(profile,transform));
else
if (AssetDatabase.isDeclaredAsset(assetId))
{
// TODO: Maybe improve this to account for the duration
// of the sound effect and if the control object can get
// into hearing range within time?
// Only post the event if it's within audible range
// of the control object.
Point3F ear,pos;
transform->getColumn(3,&pos);
mControlObject->getTransform().getColumn(3,&ear);
if ((ear - pos).len() < profile->getDescription()->mMaxDistance)
postNetEvent(new Sim3DAudioEvent(profile,transform));
}
AssetPtr<SoundAsset> tempSoundAsset;
tempSoundAsset = assetId;
if (!mControlObject)
postNetEvent(new SimSoundAssetEvent(tempSoundAsset, transform));
else
{
// TODO: Maybe improve this to account for the duration
// of the sound effect and if the control object can get
// into hearing range within time?
// Only post the event if it's within audible range
// of the control object.
tempSoundAsset->getSfxDescription();
Point3F ear, pos;
transform->getColumn(3, &pos);
mControlObject->getTransform().getColumn(3, &ear);
if ((ear - pos).len() < tempSoundAsset->getSfxDescription()->mMaxDistance)
postNetEvent(new SimSoundAssetEvent(tempSoundAsset, transform));
}
}
}
void GameConnection::doneScopingScene()
@ -2011,49 +2027,49 @@ DefineEngineMethod( GameConnection, isControlObjectRotDampedCamera, bool, (),,
return object->isControlObjectRotDampedCamera();
}
DefineEngineMethod( GameConnection, play2D, bool, (SFXProfile* profile),,
DefineEngineMethod( GameConnection, play2D, bool, (StringTableEntry assetId),,
"@brief Used on the server to play a 2D sound that is not attached to any object.\n\n"
"@param profile The SFXProfile that defines the sound to play.\n\n"
"@param assetID The SoundAsset ID that defines the sound to play.\n"
"@tsexample\n"
"function ServerPlay2D(%profile)\n"
"function ServerPlay2D(%assetId)\n"
"{\n"
" // Play the given sound profile on every client.\n"
" // Play the given sound asset on every client.\n"
" // The sounds will be transmitted as an event, not attached to any object.\n"
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
" ClientGroup.getObject(%idx).play2D(%profile);\n"
" ClientGroup.getObject(%idx).play2D(%assetId);\n"
"}\n"
"@endtsexample\n\n")
{
if(!profile)
if(assetId == StringTable->EmptyString())
return false;
object->play2D(profile);
object->play2D(assetId);
return true;
}
DefineEngineMethod( GameConnection, play3D, bool, (SFXProfile* profile, TransformF location),,
DefineEngineMethod( GameConnection, play3D, bool, (StringTableEntry assetId, TransformF location),,
"@brief Used on the server to play a 3D sound that is not attached to any object.\n\n"
"@param profile The SFXProfile that defines the sound to play.\n"
"@param assetID The SoundAsset ID that defines the sound to play.\n"
"@param location The position and orientation of the 3D sound given in the form of \"x y z ax ay az aa\".\n\n"
"@tsexample\n"
"function ServerPlay3D(%profile,%transform)\n"
"function ServerPlay3D(%assetId,%transform)\n"
"{\n"
" // Play the given sound profile at the given position on every client\n"
" // Play the given sound asset at the given position on every client\n"
" // The sound will be transmitted as an event, not attached to any object.\n"
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
" ClientGroup.getObject(%idx).play3D(%profile,%transform);\n"
" ClientGroup.getObject(%idx).play3D(%assetID,%transform);\n"
"}\n"
"@endtsexample\n\n")
{
if(!profile)
if(assetId == StringTable->EmptyString())
return false;
MatrixF mat = location.getMatrix();
object->play3D(profile,&mat);
object->play3D(assetId,&mat);
return true;
}

View file

@ -352,8 +352,8 @@ public:
/// @name Sound
/// @{
void play2D(SFXProfile *profile);
void play3D(SFXProfile *profile, const MatrixF *transform);
void play2D(StringTableEntry assetId);
void play3D(StringTableEntry assetId, const MatrixF *transform);
/// @}
/// @name Misc.

View file

@ -47,6 +47,7 @@
//--------------------------------------------------------------------------
IMPLEMENT_CO_CLIENTEVENT_V1(SimDataBlockEvent);
IMPLEMENT_CO_CLIENTEVENT_V1(SimSoundAssetEvent);
IMPLEMENT_CO_CLIENTEVENT_V1(Sim2DAudioEvent);
IMPLEMENT_CO_CLIENTEVENT_V1(Sim3DAudioEvent);
IMPLEMENT_CO_CLIENTEVENT_V1(SetMissionCRCEvent);
@ -293,6 +294,104 @@ void SimDataBlockEvent::process(NetConnection *cptr)
//----------------------------------------------------------------------------
static F32 SoundPosAccuracy = 0.5;
static S32 SoundRotBits = 8;
SimSoundAssetEvent::SimSoundAssetEvent(AssetPtr<SoundAsset> asset, const MatrixF* mat)
{
// cant get here unless the asset is declared.
mAsset = asset;
if (mat)
mTransform = *mat;
}
void SimSoundAssetEvent::pack(NetConnection* con, BitStream* stream)
{
NetStringHandle assetIdStr = mAsset->getAssetId();
con->packNetStringHandleU(stream, assetIdStr);
// only stream if this is a 3d sound asset.
if (mAsset->is3D())
{
SFXDescription* ad = mAsset->getSfxDescription();
if (stream->writeFlag(ad->mConeInsideAngle || ad->mConeOutsideAngle))
{
QuatF q(mTransform);
q.normalize();
// LH - we can get a valid quat that's very slightly over 1 in and so
// this fails (barely) check against zero. So use some error-
AssertFatal((1.0 - ((q.x * q.x) + (q.y * q.y) + (q.z * q.z))) >= (0.0 - 0.001),
"QuatF::normalize() is broken in Sim3DAudioEvent");
stream->writeSignedFloat(q.x, SoundRotBits);
stream->writeSignedFloat(q.y, SoundRotBits);
stream->writeSignedFloat(q.z, SoundRotBits);
stream->writeFlag(q.w < 0.0);
}
Point3F pos;
mTransform.getColumn(3, &pos);
stream->writeCompressedPoint(pos, SoundPosAccuracy);
}
}
void SimSoundAssetEvent::write(NetConnection* con, BitStream* stream)
{
// Just do the normal pack...
pack(con, stream);
}
void SimSoundAssetEvent::unpack(NetConnection* con, BitStream* stream)
{
StringTableEntry temp = StringTable->insert(con->unpackNetStringHandleU(stream).getString());
if (AssetDatabase.isDeclaredAsset(temp))
{
AssetPtr<SoundAsset> tempSoundAsset;
tempSoundAsset = temp;
mAsset = temp;
}
if (mAsset->is3D())
{
if (stream->readFlag()) {
QuatF q;
q.x = stream->readSignedFloat(SoundRotBits);
q.y = stream->readSignedFloat(SoundRotBits);
q.z = stream->readSignedFloat(SoundRotBits);
F32 value = ((q.x * q.x) + (q.y * q.y) + (q.z * q.z));
// #ifdef __linux
// Hmm, this should never happen, but it does...
if (value > 1.f)
value = 1.f;
// #endif
q.w = mSqrt(1.f - value);
if (stream->readFlag())
q.w = -q.w;
q.setMatrix(&mTransform);
}
else
mTransform.identity();
Point3F pos;
stream->readCompressedPoint(&pos, SoundPosAccuracy);
mTransform.setColumn(3, pos);
}
}
void SimSoundAssetEvent::process(NetConnection* con)
{
if (mAsset->is3D())
SFX->playOnce(mAsset->getSfxProfile(), &mTransform);
else
SFX->playOnce(mAsset->getSfxProfile());
}
Sim2DAudioEvent::Sim2DAudioEvent(SFXProfile *profile)
{
@ -321,11 +420,6 @@ void Sim2DAudioEvent::process(NetConnection *)
SFX->playOnce( mProfile );
}
//----------------------------------------------------------------------------
static F32 SoundPosAccuracy = 0.5;
static S32 SoundRotBits = 8;
Sim3DAudioEvent::Sim3DAudioEvent(SFXProfile *profile,const MatrixF* mat)
{
mProfile = profile;

View file

@ -39,6 +39,9 @@
#include "core/stream/bitStream.h"
#endif
#include "T3D/assets/SoundAsset.h"
class QuitEvent : public SimEvent
{
@ -102,6 +105,23 @@ class SimDataBlockEvent : public NetEvent
DECLARE_CATEGORY( "Game Networking" );
};
class SimSoundAssetEvent : public NetEvent
{
private:
AssetPtr<SoundAsset> mAsset;
MatrixF mTransform;
public:
typedef NetEvent Parent;
SimSoundAssetEvent(AssetPtr<SoundAsset> asset = NULL, const MatrixF* mat = NULL);
void pack(NetConnection*, BitStream* bstream);
void write(NetConnection*, BitStream* bstream);
void unpack(NetConnection*, BitStream* bstream);
void process(NetConnection*);
DECLARE_CONOBJECT(SimSoundAssetEvent);
};
class Sim2DAudioEvent: public NetEvent
{
private:

View file

@ -46,7 +46,7 @@ MODULE_BEGIN( 3D )
MODULE_SHUTDOWN_BEFORE( Process )
MODULE_SHUTDOWN_BEFORE( Sim )
MODULE_SHUTDOWN_AFTER( Scene )
MODULE_SHUTDOWN_BEFORE( Scene )
MODULE_INIT
{
@ -668,6 +668,7 @@ static void RegisterGameFunctions()
// PATHSHAPE
Con::setIntVariable("$TypeMasks::PathShapeObjectType", PathShapeObjectType);
// PATHSHAPE END
Con::setIntVariable("$TypeMasks::TurretObjectType", TurretObjectType);
Con::addVariable("Ease::InOut", TypeS32, &gEaseInOut,
"InOut ease for curve movement.\n"

View file

@ -87,7 +87,7 @@ GroundPlane::GroundPlane()
mConvexList = new Convex;
mTypeMask |= TerrainLikeObjectType;
INIT_MATERIALASSET(Material);
INIT_ASSET(Material);
}
GroundPlane::~GroundPlane()
@ -199,7 +199,7 @@ U32 GroundPlane::packUpdate( NetConnection* connection, U32 mask, BitStream* str
stream->write( mScaleU );
stream->write( mScaleV );
PACK_MATERIALASSET(connection, Material);
PACK_ASSET(connection, Material);
return retMask;
}
@ -212,7 +212,7 @@ void GroundPlane::unpackUpdate( NetConnection* connection, BitStream* stream )
stream->read( &mScaleU );
stream->read( &mScaleV );
UNPACK_MATERIALASSET(connection, Material);
UNPACK_ASSET(connection, Material);
// If we're added then something possibly changed in
// the editor... do an update of the material and the

View file

@ -108,7 +108,7 @@ private:
BaseMatInstance* mMaterialInst;
DECLARE_MATERIALASSET(GroundPlane, Material);
DECLARE_MATERIALASSET_NET_SETGET(GroundPlane, Material, -1);
DECLARE_ASSET_NET_SETGET(GroundPlane, Material, -1);
PhysicsBody *mPhysicsRep;

View file

@ -73,7 +73,7 @@ extern F32 gDecalBias;
extern GFXTexHandle gLevelAccuMap;
/// Default SFXAmbience used to reset the global soundscape.
static SFXAmbience sDefaultAmbience;
extern SFXAmbience* sDefaultAmbience;
//-----------------------------------------------------------------------------
@ -99,7 +99,7 @@ LevelInfo::LevelInfo()
mAdvancedLightmapSupport = true;
INIT_IMAGEASSET(AccuTexture);
INIT_ASSET(AccuTexture);
// Register with the light manager activation signal, and we need to do it first
// so the advanced light bin manager can be instructed about MRT lightmaps
@ -215,7 +215,7 @@ U32 LevelInfo::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
sfxWrite( stream, mSoundAmbience );
stream->writeInt( mSoundDistanceModel, 1 );
PACK_IMAGEASSET(conn, AccuTexture);
PACK_ASSET(conn, AccuTexture);
return retMask;
}
@ -256,13 +256,13 @@ void LevelInfo::unpackUpdate(NetConnection *conn, BitStream *stream)
if( mSoundAmbience )
mSoundscape->setAmbience( mSoundAmbience );
else
mSoundscape->setAmbience( &sDefaultAmbience );
mSoundscape->setAmbience( sDefaultAmbience );
}
SFX->setDistanceModel( mSoundDistanceModel );
}
UNPACK_IMAGEASSET(conn, AccuTexture);
UNPACK_ASSET(conn, AccuTexture);
setLevelAccuTexture(getAccuTexture());
}
@ -302,7 +302,7 @@ bool LevelInfo::onAdd()
void LevelInfo::onRemove()
{
if( mSoundscape )
mSoundscape->setAmbience( &sDefaultAmbience );
mSoundscape->setAmbience( sDefaultAmbience );
Parent::onRemove();
}

View file

@ -105,7 +105,7 @@ class LevelInfo : public NetObject
protected:
DECLARE_IMAGEASSET(LevelInfo, AccuTexture, onAccuTextureChanged, GFXStaticTextureSRGBProfile);
DECLARE_IMAGEASSET_SETGET(LevelInfo, AccuTexture);
DECLARE_ASSET_SETGET(LevelInfo, AccuTexture);
void onAccuTextureChanged() {}

View file

@ -133,7 +133,7 @@ LightFlareData::LightFlareData()
for ( U32 i = 0; i < MAX_ELEMENTS; i++ )
mElementDist[i] = -1.0f;
INIT_IMAGEASSET(FlareTexture);
INIT_ASSET(FlareTexture);
}
LightFlareData::~LightFlareData()
@ -219,7 +219,7 @@ void LightFlareData::packData( BitStream *stream )
stream->writeFlag( mFlareEnabled );
PACKDATA_IMAGEASSET(FlareTexture);
PACKDATA_ASSET(FlareTexture);
stream->write( mScale );
stream->write( mOcclusionRadius );
@ -244,7 +244,7 @@ void LightFlareData::unpackData( BitStream *stream )
mFlareEnabled = stream->readFlag();
UNPACKDATA_IMAGEASSET(FlareTexture);
UNPACKDATA_ASSET(FlareTexture);
stream->read( &mScale );
stream->read( &mOcclusionRadius );

View file

@ -121,7 +121,7 @@ protected:
bool mFlareEnabled;
DECLARE_IMAGEASSET(LightFlareData, FlareTexture, onImageChanged, GFXStaticTextureSRGBProfile);
DECLARE_IMAGEASSET_SETGET(LightFlareData, FlareTexture);
DECLARE_ASSET_SETGET(LightFlareData, FlareTexture);
F32 mOcclusionRadius;
bool mRenderReflectPass;

View file

@ -46,7 +46,6 @@ namespace IBLUtilities
}
GFXShaderConstBufferRef irrConsts = irrShader->allocConstBuffer();
GFXShaderConstHandle* irrEnvMapSC = irrShader->getShaderConstHandle("$environmentMap");
GFXShaderConstHandle* irrFaceSC = irrShader->getShaderConstHandle("$face");
GFXStateBlockDesc desc;
@ -132,7 +131,6 @@ namespace IBLUtilities
}
GFXShaderConstBufferRef prefilterConsts = prefilterShader->allocConstBuffer();
GFXShaderConstHandle* prefilterEnvMapSC = prefilterShader->getShaderConstHandle("$environmentMap");
GFXShaderConstHandle* prefilterFaceSC = prefilterShader->getShaderConstHandle("$face");
GFXShaderConstHandle* prefilterRoughnessSC = prefilterShader->getShaderConstHandle("$roughness");
GFXShaderConstHandle* prefilterMipSizeSC = prefilterShader->getShaderConstHandle("$mipSize");

View file

@ -77,7 +77,7 @@ ConsoleDocClass(BoxEnvironmentProbe,
BoxEnvironmentProbe::BoxEnvironmentProbe() : ReflectionProbe()
{
mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK;
mProbeShapeType = ProbeRenderInst::Box;
mProbeShapeType = ProbeInfo::Box;
mAtten = 0.0;
}
@ -158,7 +158,7 @@ void BoxEnvironmentProbe::unpackUpdate(NetConnection *conn, BitStream *stream)
void BoxEnvironmentProbe::updateProbeParams()
{
mProbeShapeType = ProbeRenderInst::Box;
mProbeShapeType = ProbeInfo::Box;
mProbeInfo.mAtten = mAtten;
Parent::updateProbeParams();

View file

@ -73,8 +73,8 @@ ConsoleDocClass(ReflectionProbe,
ImplementEnumType(ReflectProbeType,
"Type of mesh data available in a shape.\n"
"@ingroup gameObjects")
{ ProbeRenderInst::Sphere, "Sphere", "Sphere shaped" },
{ ProbeRenderInst::Box, "Box", "Box shape" }
{ ReflectionProbe::ProbeInfo::Sphere, "Sphere", "Sphere shaped" },
{ ReflectionProbe::ProbeInfo::Box, "Box", "Box shape" }
EndImplementEnumType;
ImplementEnumType(ReflectionModeEnum,
@ -97,7 +97,7 @@ ReflectionProbe::ReflectionProbe()
mTypeMask = LightObjectType | MarkerObjectType;
mProbeShapeType = ProbeRenderInst::Box;
mProbeShapeType = ProbeInfo::Box;
mReflectionModeType = BakedCubemap;
@ -121,8 +121,6 @@ ReflectionProbe::ReflectionProbe()
mRefreshRateMS = 200;
mDynamicLastBakeMS = 0;
mMaxDrawDistance = 75;
mResourcesCreated = false;
mPrefilterSize = 64;
mPrefilterMipLevels = mLog2(F32(mPrefilterSize));
@ -239,7 +237,7 @@ bool ReflectionProbe::_setRadius(void *object, const char *index, const char *da
{
ReflectionProbe* probe = reinterpret_cast<ReflectionProbe*>(object);
if (probe->mProbeShapeType != ProbeRenderInst::Sphere)
if (probe->mProbeShapeType != ProbeInfo::Sphere)
return false;
probe->mObjScale = Point3F(probe->mRadius, probe->mRadius, probe->mRadius);
@ -291,7 +289,7 @@ bool ReflectionProbe::onAdd()
if (!mPersistentId)
mPersistentId = getOrCreatePersistentId();
mProbeUniqueID = String::ToString(mPersistentId->getUUID().getHash());
mProbeUniqueID = mPersistentId->getUUID().toString();
}
// Refresh this object's material (if any)
@ -312,7 +310,7 @@ void ReflectionProbe::onRemove()
{
if (isClientObject())
{
PROBEMGR->unregisterProbe(mProbeInfo.mProbeIdx);
PROBEMGR->unregisterProbe(&mProbeInfo);
}
// Remove this object from the scene
@ -461,10 +459,10 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream)
if (stream->readFlag()) // StaticDataMask
{
U32 shapeType = ProbeRenderInst::Sphere;
U32 shapeType = ProbeInfo::Sphere;
stream->read(&shapeType);
mProbeShapeType = (ProbeRenderInst::ProbeShapeType)shapeType;
mProbeShapeType = (ProbeInfo::ProbeShapeType)shapeType;
stream->read(&mRadius);
@ -497,6 +495,8 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream)
//-----------------------------------------------------------------------------
void ReflectionProbe::updateProbeParams()
{
mProbeInfo.mObject = this;
if (!mResourcesCreated)
{
if (!createClientResources())
@ -507,12 +507,12 @@ void ReflectionProbe::updateProbeParams()
mProbeInfo.mProbeShapeType = mProbeShapeType;
if (mProbeShapeType == ProbeRenderInst::Sphere)
if (mProbeShapeType == ProbeInfo::Sphere)
mObjScale.set(mRadius, mRadius, mRadius);
Box3F bounds;
if (mProbeShapeType == ProbeRenderInst::Skylight)
if (mProbeShapeType == ProbeInfo::Skylight)
{
mProbeInfo.mPosition = Point3F::Zero;
mProbeInfo.mTransform = MatrixF::Identity;
@ -564,8 +564,6 @@ void ReflectionProbe::updateProbeParams()
else
processDynamicCubemap();
}
PROBEMGR->updateProbes();
}
void ReflectionProbe::processDynamicCubemap()
@ -575,7 +573,7 @@ void ReflectionProbe::processDynamicCubemap()
void ReflectionProbe::processBakedCubemap()
{
mProbeInfo.mIsEnabled = false;
//mProbeInfo.mIsEnabled = false;
if ((mReflectionModeType != BakedCubemap) || mProbeUniqueID.isEmpty())
return;
@ -611,7 +609,7 @@ void ReflectionProbe::processBakedCubemap()
if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
{
mProbeInfo.mIsEnabled = true;
//mProbeInfo.mIsEnabled = true;
mCubemapDirty = false;
@ -622,6 +620,11 @@ void ReflectionProbe::processBakedCubemap()
mProbeInfo.mPrefilterCubemap.free();
mProbeInfo.mIrradianceCubemap.free();
}
else
{
//if we failed, disable
mProbeInfo.mIsEnabled = false;
}
}
void ReflectionProbe::processStaticCubemap()
@ -798,7 +801,7 @@ void ReflectionProbe::createEditorResources()
mEditorShape = NULL;
String shapeFile = "tools/resources/ReflectProbeSphere.dae";
String shapeFile = "tools/resources/previewSphereShape.dae";
// Attempt to get the resource from the ResourceManager
mEditorShape = ResourceManager::get().load(shapeFile);
@ -811,16 +814,16 @@ void ReflectionProbe::createEditorResources()
void ReflectionProbe::prepRenderImage(SceneRenderState *state)
{
if (!mEnabled || !RenderProbeMgr::smRenderReflectionProbes)
if (!mEnabled || (!RenderProbeMgr::smRenderReflectionProbes && Con::getVariable("$Probes::Capturing", "0") == "0"))
return;
Point3F distVec = getRenderPosition() - state->getCameraPosition();
F32 dist = distVec.len();
//Culling distance. Can be adjusted for performance options considerations via the scalar
if (dist > mMaxDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0))
if (dist > RenderProbeMgr::smMaxProbeDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0))
{
mProbeInfo.mScore = mMaxDrawDistance;
mProbeInfo.mScore = RenderProbeMgr::smMaxProbeDrawDistance;
return;
}
@ -842,7 +845,7 @@ void ReflectionProbe::prepRenderImage(SceneRenderState *state)
//mProbeInfo.mScore *= mMax(mAbs(mDot(vect, state->getCameraTransform().getForwardVector())),0.001f);
PROBEMGR->submitProbe(mProbeInfo);
PROBEMGR->submitProbe(&mProbeInfo);
#ifdef TORQUE_TOOLS
if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mPrefilterMap != nullptr)
@ -938,7 +941,7 @@ void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri,
ColorI color = ColorI(255, 0, 255, 63);
const MatrixF worldToObjectXfm = mObjToWorld;
if (mProbeShapeType == ProbeRenderInst::Sphere)
if (mProbeShapeType == ProbeInfo::Sphere)
{
draw->drawSphere(desc, mRadius, getPosition(), color);
}

View file

@ -41,10 +41,6 @@
#include "renderInstance/renderPassManager.h"
#endif
#ifndef RENDER_PROBE_MGR_H
#include "renderInstance/renderProbeMgr.h"
#endif
class BaseMatInstance;
//-----------------------------------------------------------------------------
@ -74,6 +70,67 @@ public:
DynamicCubemap = 5,
};
/// <summary>
/// This contains all the important data the Probe uses for rendering.
/// </summary>
struct ProbeInfo
{
bool mIsEnabled;
MatrixF mTransform;
ReflectionProbe* mObject;
F32 mRadius;
bool mDirty;
Box3F mBounds;
Point3F mExtents;
Point3F mPosition;
Point3F mProbeRefOffset;
Point3F mProbeRefScale;
F32 mAtten;
F32 mScore;
GFXCubemapHandle mPrefilterCubemap;
GFXCubemapHandle mIrradianceCubemap;
/// The priority of this light used for
/// light and shadow scoring.
F32 mPriority;
enum ProbeShapeType
{
Box = 0,
Sphere = 1,
Skylight = 2
};
ProbeShapeType mProbeShapeType;
public:
ProbeInfo() : mScore(0) {}
~ProbeInfo() {}
// Copies data passed in from light
void set(const ProbeInfo* probeInfo);
// Accessors
const MatrixF& getTransform() const { return mTransform; }
void setTransform(const MatrixF& xfm) { mTransform = xfm; }
Point3F getPosition() const { return mPosition; }
void setPosition(const Point3F& pos) { mPosition = pos; }
void setPriority(F32 priority) { mPriority = priority; }
F32 getPriority() const { return mPriority; }
void clear();
};
protected:
// Networking masks
@ -124,7 +181,7 @@ protected:
/// <summary>
/// The shape of the probe
/// </summary>
ProbeRenderInst::ProbeShapeType mProbeShapeType;
ProbeInfo::ProbeShapeType mProbeShapeType;
/// <summary>
/// This is effectively a packed cache of the probe data actually utilized for rendering.
@ -132,7 +189,7 @@ protected:
/// When the manager goes to render it has the compacted data to read over more efficiently for setting up what probes should
/// Actually render in that frame
/// </summary>
ProbeRenderInst mProbeInfo;
ProbeInfo mProbeInfo;
/// <summary>
/// Used to dictate what sort of cubemap the probes use when using IBL
@ -166,14 +223,13 @@ protected:
CubemapData *mStaticCubemap;
GFXCubemapHandle mDynamicCubemap;
String cubeDescName;
U32 cubeDescId;
ReflectorDesc *reflectorDesc;
//String cubeDescName;
//U32 cubeDescId;
//ReflectorDesc *reflectorDesc;
//Utilized in dynamic reflections
//CubeReflector mCubeReflector;
///Prevents us from saving out the cubemaps(for now) but allows us the full HDR range on the in-memory cubemap captures
bool mUseHDRCaptures;
//irridiance resources
@ -196,7 +252,6 @@ protected:
U32 mDynamicLastBakeMS;
U32 mRefreshRateMS;
F32 mMaxDrawDistance;
bool mResourcesCreated;
U32 mCaptureMask;
@ -313,7 +368,7 @@ public:
void bake();
};
typedef ProbeRenderInst::ProbeShapeType ReflectProbeType;
typedef ReflectionProbe::ProbeInfo::ProbeShapeType ReflectProbeType;
DefineEnumType(ReflectProbeType);
typedef ReflectionProbe::ReflectionModeType ReflectionModeEnum;

View file

@ -148,7 +148,7 @@ void Skylight::unpackUpdate(NetConnection *conn, BitStream *stream)
void Skylight::updateProbeParams()
{
mProbeShapeType = ProbeRenderInst::Skylight;
mProbeShapeType = ProbeInfo::Skylight;
Parent::updateProbeParams();
}
@ -167,7 +167,7 @@ void Skylight::prepRenderImage(SceneRenderState *state)
// Get a handy pointer to our RenderPassmanager
//RenderPassManager *renderPass = state->getRenderPass();
PROBEMGR->submitProbe(mProbeInfo);
PROBEMGR->submitProbe(&mProbeInfo);
#ifdef TORQUE_TOOLS
if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr)

View file

@ -77,7 +77,7 @@ ConsoleDocClass(SphereEnvironmentProbe,
SphereEnvironmentProbe::SphereEnvironmentProbe() : ReflectionProbe()
{
mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK;
mProbeShapeType = ProbeRenderInst::Sphere;
mProbeShapeType = ProbeInfo::Sphere;
}
SphereEnvironmentProbe::~SphereEnvironmentProbe()
@ -144,83 +144,10 @@ void SphereEnvironmentProbe::unpackUpdate(NetConnection *conn, BitStream *stream
void SphereEnvironmentProbe::updateProbeParams()
{
mProbeShapeType = ProbeRenderInst::Sphere;
mProbeShapeType = ProbeInfo::Sphere;
Parent::updateProbeParams();
}
void SphereEnvironmentProbe::prepRenderImage(SceneRenderState *state)
{
if (!mEnabled || !ReflectionProbe::smRenderPreviewProbes)
return;
#ifdef TORQUE_TOOLS
if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr)
{
GFXTransformSaver saver;
// 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));
mEditorShapeInst->setDetailFromDistance(state, dist * invScale);
// Make sure we have a valid level of detail
if (mEditorShapeInst->getCurrentDetail() < 0)
return;
BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0);
setPreviewMatParameters(state, probePrevMat);
// 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
// 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(Point3F(1, 1, 1));
GFX->setWorldMatrix(mat);
// Animate the the shape
mEditorShapeInst->animate();
// Allow the shape to submit the RenderInst(s) for itself
mEditorShapeInst->render(rdata);
saver.restore();
}
// If the light is selected or light visualization
// is enabled then register the callback.
const bool isSelectedInEditor = (gEditingMission && isSelected());
if (isSelectedInEditor)
{
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind(this, &ReflectionProbe::_onRenderViz);
ri->type = RenderPassManager::RIT_Editor;
state->getRenderPass()->addInst(ri);
}
#endif
}
void SphereEnvironmentProbe::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat)
{
Parent::setPreviewMatParameters(renderState, mat);

View file

@ -98,10 +98,6 @@ public:
// use the same Materials.
//--------------------------------------------------------------------------
virtual void updateProbeParams();
// This is the function that allows this object to submit itself for rendering
void prepRenderImage(SceneRenderState *state);
void setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat);
};

View file

@ -433,7 +433,23 @@ void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream)
mSpawnTransform = stream->readFlag();
stream->read(&mSpawnClass);
String oldSDB = mSpawnDataBlock;
stream->read(&mSpawnDataBlock);
if (oldSDB != mSpawnDataBlock)
{
delete mShapeInstance;
ShapeBaseData *spawnedDatablock = dynamic_cast<ShapeBaseData *>(Sim::findObject(mSpawnDataBlock.c_str()));
if (spawnedDatablock && spawnedDatablock->mShape)
{
mShapeInstance = new TSShapeInstance(spawnedDatablock->mShape);
}
else if (mDataBlock)
{
if (mDataBlock->mShape)
mShapeInstance = new TSShapeInstance(mDataBlock->mShape);
}
}
stream->read(&mSpawnName);
stream->read(&mSpawnProperties);
stream->read(&mSpawnScript);

View file

@ -167,6 +167,10 @@ enum SceneObjectTypes
PathShapeObjectType = BIT( 28 ),
// PATHSHAPE END
/// A turret object.
/// @see TurretShape
TurretObjectType = BIT(29),
/// @}
};
@ -225,7 +229,7 @@ enum SceneObjectTypeMasks : U32
EnvironmentObjectType ),
SKYLIGHT_CAPTURE_TYPEMASK = (EnvironmentObjectType),
REFLECTION_PROBE_CAPTURE_TYPEMASK = (StaticObjectType | StaticShapeObjectType)
REFLECTION_PROBE_CAPTURE_TYPEMASK = (StaticObjectType | StaticShapeObjectType | LightObjectType)
};
#endif

View file

@ -114,6 +114,13 @@ PhysicalZone::PhysicalZone()
force_mag = 0.0f;
orient_force = false;
fade_amt = 1.0f;
//Default up a basic square
Point3F vecs[3] = { Point3F(1.0, 0.0, 0.0),
Point3F(0.0, -1.0, 0.0),
Point3F(0.0, 0.0, 1.0) };
mPolyhedron = Polyhedron(Point3F(-0.5, 0.5, 0.0), vecs);
}
PhysicalZone::~PhysicalZone()

View file

@ -74,7 +74,7 @@ PhysicsDebrisData::PhysicsDebrisData()
lifetime = 5.0f;
lifetimeVariance = 0.0f;
INIT_SHAPEASSET(Shape);
INIT_ASSET(Shape);
}
bool PhysicsDebrisData::onAdd()
@ -215,7 +215,7 @@ void PhysicsDebrisData::packData(BitStream* stream)
stream->write( waterDampingScale );
stream->write( buoyancyDensity );
PACKDATA_SHAPEASSET(Shape);
PACKDATA_ASSET(Shape);
}
void PhysicsDebrisData::unpackData(BitStream* stream)
@ -236,7 +236,7 @@ void PhysicsDebrisData::unpackData(BitStream* stream)
stream->read( &waterDampingScale );
stream->read( &buoyancyDensity );
UNPACKDATA_SHAPEASSET(Shape);
UNPACKDATA_ASSET(Shape);
}
DefineEngineMethod( PhysicsDebrisData, preload, void, (), ,

View file

@ -87,7 +87,7 @@ public:
bool castShadows;
DECLARE_SHAPEASSET(PhysicsDebrisData, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(PhysicsDebrisData, Shape);
DECLARE_ASSET_SETGET(PhysicsDebrisData, Shape);
PhysicsDebrisData();

View file

@ -78,7 +78,7 @@ PhysicsShapeData::PhysicsShapeData()
buoyancyDensity( 0.0f ),
simType( SimType_ClientServer )
{
INIT_SHAPEASSET(Shape);
INIT_ASSET(Shape);
}
PhysicsShapeData::~PhysicsShapeData()
@ -180,7 +180,7 @@ void PhysicsShapeData::packData( BitStream *stream )
{
Parent::packData( stream );
PACKDATA_SHAPEASSET(Shape);
PACKDATA_ASSET(Shape);
stream->write( mass );
stream->write( dynamicFriction );
@ -204,7 +204,7 @@ void PhysicsShapeData::unpackData( BitStream *stream )
{
Parent::unpackData(stream);
UNPACKDATA_SHAPEASSET(Shape);
UNPACKDATA_ASSET(Shape);
stream->read( &mass );
stream->read( &dynamicFriction );

View file

@ -75,7 +75,7 @@ public:
public:
DECLARE_SHAPEASSET(PhysicsShapeData, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(PhysicsShapeData, Shape);
DECLARE_ASSET_SETGET(PhysicsShapeData, Shape);
/// The shared unscaled collision shape.
PhysicsCollisionRef colShape;

View file

@ -187,6 +187,32 @@ PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAni
//----------------------------------------------------------------------------
typedef PlayerData::Sounds playerSoundsEnum;
DefineEnumType(playerSoundsEnum);
ImplementEnumType(playerSoundsEnum, "enum types.\n"
"@ingroup PlayerData\n\n")
{ playerSoundsEnum::FootSoft, "FootSoft", "..." },
{ playerSoundsEnum::FootHard, "FootHard","..." },
{ playerSoundsEnum::FootMetal, "FootMetal","..." },
{ playerSoundsEnum::FootSnow, "FootSnow","..." },
{ playerSoundsEnum::FootShallowSplash, "FootShallowSplash","..." },
{ playerSoundsEnum::FootWading, "FootWading","..." },
{ playerSoundsEnum::FootUnderWater, "FootUnderWater","..." },
{ playerSoundsEnum::FootBubbles, "FootBubbles","..." },
{ playerSoundsEnum::MoveBubbles, "MoveBubbles","..." },
{ playerSoundsEnum::WaterBreath, "WaterBreath","..." },
{ playerSoundsEnum::ImpactSoft, "ImpactSoft","..." },
{ playerSoundsEnum::ImpactHard, "ImpactHard","..." },
{ playerSoundsEnum::ImpactMetal, "ImpactMetal","..." },
{ playerSoundsEnum::ImpactSnow, "ImpactSnow","..." },
{ playerSoundsEnum::ImpactWaterEasy, "ImpactWaterEasy","..." },
{ playerSoundsEnum::ImpactWaterMedium, "ImpactWaterMedium","..." },
{ playerSoundsEnum::ImpactWaterHard, "ImpactWaterHard","..." },
{ playerSoundsEnum::ExitWater, "ExitWater","..." },
EndImplementEnumType;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
@ -272,7 +298,7 @@ PlayerData::PlayerData()
imageAnimPrefixFP = StringTable->EmptyString();
for (U32 i=0; i<ShapeBase::MaxMountedImages; ++i)
{
INIT_SHAPEASSET_ARRAY(ShapeFP, i);
INIT_ASSET_ARRAY(ShapeFP, i);
mCRCFP[i] = 0;
mValidShapeFP[i] = false;
}
@ -397,7 +423,7 @@ PlayerData::PlayerData()
boxHeadFrontPercentage = 1;
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = NULL;
INIT_ASSET_ARRAY(PlayerSound, i);
footPuffEmitter = NULL;
footPuffID = 0;
@ -444,14 +470,13 @@ bool PlayerData::preload(bool server, String &errorStr)
if(!Parent::preload(server, errorStr))
return false;
// Resolve objects transmitted from server
if( !server )
for (U32 i = 0; i < MaxSounds; ++i)
{
for( U32 i = 0; i < MaxSounds; ++ i )
_setPlayerSound(getPlayerSound(i), i);
if (getPlayerSound(i) != StringTable->EmptyString())
{
String sfxErrorStr;
if( !sfxResolve( &sound[ i ], sfxErrorStr ) )
Con::errorf( "PlayerData::preload: %s", sfxErrorStr.c_str() );
if (!getPlayerSoundProfile(i))
Con::errorf("PlayerData::Preload() - unable to find sfxProfile for asset %d %s", i, mPlayerSoundAssetId[i]);
}
}
@ -1021,65 +1046,7 @@ void PlayerData::initPersistFields()
endGroup( "Interaction: Footsteps" );
addGroup( "Interaction: Sounds" );
addField( "FootSoftSound", TypeSFXTrackName, Offset(sound[FootSoft], PlayerData),
"@brief Sound to play when walking on a surface with Material footstepSoundId 0.\n\n" );
addField( "FootHardSound", TypeSFXTrackName, Offset(sound[FootHard], PlayerData),
"@brief Sound to play when walking on a surface with Material footstepSoundId 1.\n\n" );
addField( "FootMetalSound", TypeSFXTrackName, Offset(sound[FootMetal], PlayerData),
"@brief Sound to play when walking on a surface with Material footstepSoundId 2.\n\n" );
addField( "FootSnowSound", TypeSFXTrackName, Offset(sound[FootSnow], PlayerData),
"@brief Sound to play when walking on a surface with Material footstepSoundId 3.\n\n" );
addField( "FootShallowSound", TypeSFXTrackName, Offset(sound[FootShallowSplash], PlayerData),
"@brief Sound to play when walking in water and coverage is less than "
"footSplashHeight.\n\n"
"@see footSplashHeight\n" );
addField( "FootWadingSound", TypeSFXTrackName, Offset(sound[FootWading], PlayerData),
"@brief Sound to play when walking in water and coverage is less than 1, "
"but > footSplashHeight.\n\n"
"@see footSplashHeight\n" );
addField( "FootUnderwaterSound", TypeSFXTrackName, Offset(sound[FootUnderWater], PlayerData),
"@brief Sound to play when walking in water and coverage equals 1.0 "
"(fully underwater).\n\n" );
addField( "FootBubblesSound", TypeSFXTrackName, Offset(sound[FootBubbles], PlayerData),
"@brief Sound to play when walking in water and coverage equals 1.0 "
"(fully underwater).\n\n" );
addField( "movingBubblesSound", TypeSFXTrackName, Offset(sound[MoveBubbles], PlayerData),
"@brief Sound to play when in water and coverage equals 1.0 (fully underwater).\n\n"
"Note that unlike FootUnderwaterSound, this sound plays even if the "
"player is not moving around in the water.\n" );
addField( "waterBreathSound", TypeSFXTrackName, Offset(sound[WaterBreath], PlayerData),
"@brief Sound to play when in water and coverage equals 1.0 (fully underwater).\n\n"
"Note that unlike FootUnderwaterSound, this sound plays even if the "
"player is not moving around in the water.\n" );
addField( "impactSoftSound", TypeSFXTrackName, Offset(sound[ImpactSoft], PlayerData),
"@brief Sound to play after falling on a surface with Material footstepSoundId 0.\n\n" );
addField( "impactHardSound", TypeSFXTrackName, Offset(sound[ImpactHard], PlayerData),
"@brief Sound to play after falling on a surface with Material footstepSoundId 1.\n\n" );
addField( "impactMetalSound", TypeSFXTrackName, Offset(sound[ImpactMetal], PlayerData),
"@brief Sound to play after falling on a surface with Material footstepSoundId 2.\n\n" );
addField( "impactSnowSound", TypeSFXTrackName, Offset(sound[ImpactSnow], PlayerData),
"@brief Sound to play after falling on a surface with Material footstepSoundId 3.\n\n" );
addField( "impactWaterEasy", TypeSFXTrackName, Offset(sound[ImpactWaterEasy], PlayerData),
"@brief Sound to play when entering the water with velocity < "
"mediumSplashSoundVelocity.\n\n"
"@see mediumSplashSoundVelocity\n");
addField( "impactWaterMedium", TypeSFXTrackName, Offset(sound[ImpactWaterMedium], PlayerData),
"@brief Sound to play when entering the water with velocity >= "
"mediumSplashSoundVelocity and < hardSplashSoundVelocity.\n\n"
"@see mediumSplashSoundVelocity\n"
"@see hardSplashSoundVelocity\n");
addField( "impactWaterHard", TypeSFXTrackName, Offset(sound[ImpactWaterHard], PlayerData),
"@brief Sound to play when entering the water with velocity >= "
"hardSplashSoundVelocity.\n\n"
"@see hardSplashSoundVelocity\n");
addField( "exitingWater", TypeSFXTrackName, Offset(sound[ExitWater], PlayerData),
"@brief Sound to play when exiting the water with velocity >= exitSplashSoundVelocity.\n\n"
"@see exitSplashSoundVelocity\n");
INITPERSISTFIELD_SOUNDASSET_ENUMED(PlayerSound, playerSoundsEnum, PlayerData::Sounds::MaxSounds, PlayerData, "Sounds related to player interaction.");
endGroup( "Interaction: Sounds" );
addGroup( "Interaction: Splashes" );
@ -1303,8 +1270,8 @@ void PlayerData::packData(BitStream* stream)
stream->write(minImpactSpeed);
stream->write(minLateralImpactSpeed);
for( U32 i = 0; i < MaxSounds; i++)
sfxWrite( stream, sound[ i ] );
for (U32 i = 0; i < MaxSounds; i++)
PACKDATA_ASSET_ARRAY(PlayerSound, i);
mathWrite(*stream, boxSize);
mathWrite(*stream, crouchBoxSize);
@ -1372,7 +1339,7 @@ void PlayerData::packData(BitStream* stream)
stream->writeString(imageAnimPrefixFP);
for (U32 i=0; i<ShapeBase::MaxMountedImages; ++i)
{
PACKDATA_SHAPEASSET_ARRAY(ShapeFP, i);
PACKDATA_ASSET_ARRAY(ShapeFP, i);
// computeCRC is handled in ShapeBaseData
if (computeCRC)
@ -1484,8 +1451,8 @@ void PlayerData::unpackData(BitStream* stream)
stream->read(&minImpactSpeed);
stream->read(&minLateralImpactSpeed);
for( U32 i = 0; i < MaxSounds; i++)
sfxRead( stream, &sound[ i ] );
for (U32 i = 0; i < MaxSounds; i++)
UNPACKDATA_ASSET_ARRAY(PlayerSound, i);
mathRead(*stream, &boxSize);
mathRead(*stream, &crouchBoxSize);
@ -1552,7 +1519,7 @@ void PlayerData::unpackData(BitStream* stream)
imageAnimPrefixFP = stream->readSTString();
for (U32 i=0; i<ShapeBase::MaxMountedImages; ++i)
{
UNPACKDATA_SHAPEASSET_ARRAY(ShapeFP, i);
UNPACKDATA_ASSET_ARRAY(ShapeFP, i);
// computeCRC is handled in ShapeBaseData
if (computeCRC)
@ -1932,11 +1899,11 @@ bool Player::onNewDataBlock( GameBaseData *dptr, bool reload )
SFX_DELETE( mMoveBubbleSound );
SFX_DELETE( mWaterBreathSound );
if ( mDataBlock->sound[PlayerData::MoveBubbles] )
mMoveBubbleSound = SFX->createSource( mDataBlock->sound[PlayerData::MoveBubbles] );
if ( mDataBlock->getPlayerSound(PlayerData::MoveBubbles) )
mMoveBubbleSound = SFX->createSource( mDataBlock->getPlayerSoundProfile(PlayerData::MoveBubbles) );
if ( mDataBlock->sound[PlayerData::WaterBreath] )
mWaterBreathSound = SFX->createSource( mDataBlock->sound[PlayerData::WaterBreath] );
if ( mDataBlock->getPlayerSound(PlayerData::WaterBreath) )
mWaterBreathSound = SFX->createSource( mDataBlock->getPlayerSoundProfile(PlayerData::WaterBreath) );
}
mObjBox.maxExtents.x = mDataBlock->boxSize.x * 0.5f;
@ -3300,7 +3267,7 @@ void Player::updateMove(const Move* move)
{
// exit-water splash sound happens for client only
if ( getSpeed() >= mDataBlock->exitSplashSoundVel && !isMounted() )
SFX->playOnce( mDataBlock->sound[PlayerData::ExitWater], &getTransform() );
SFX->playOnce( mDataBlock->getPlayerSoundProfile(PlayerData::ExitWater), &getTransform() );
}
}
@ -7060,39 +7027,39 @@ void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, S
// Treading water.
if ( mWaterCoverage < mDataBlock->footSplashHeight )
SFX->playOnce( mDataBlock->sound[ PlayerData::FootShallowSplash ], &footMat );
SFX->playOnce( mDataBlock->getPlayerSoundProfile( PlayerData::FootShallowSplash ), &footMat );
else
{
if ( mWaterCoverage < 1.0 )
SFX->playOnce( mDataBlock->sound[ PlayerData::FootWading ], &footMat );
SFX->playOnce( mDataBlock->getPlayerSoundProfile( PlayerData::FootWading ), &footMat );
else
{
if ( triggeredLeft )
{
SFX->playOnce( mDataBlock->sound[ PlayerData::FootUnderWater ], &footMat );
SFX->playOnce( mDataBlock->sound[ PlayerData::FootBubbles ], &footMat );
SFX->playOnce( mDataBlock->getPlayerSoundProfile( PlayerData::FootUnderWater ), &footMat );
SFX->playOnce( mDataBlock->getPlayerSoundProfile( PlayerData::FootBubbles ), &footMat );
}
}
}
}
else if( contactMaterial && contactMaterial->mFootstepSoundCustom )
else if( contactMaterial && contactMaterial->getCustomFootstepSoundProfile())
{
// Footstep sound defined on material.
SFX->playOnce( contactMaterial->mFootstepSoundCustom, &footMat );
SFX->playOnce( contactMaterial->getCustomFootstepSoundProfile(), &footMat );
}
else
{
// Play default sound.
S32 sound = -1;
if (contactMaterial && (contactMaterial->mFootstepSoundId>-1 && contactMaterial->mFootstepSoundId<PlayerData::MaxSoundOffsets))
if (contactMaterial && (contactMaterial->mFootstepSoundId > -1 && contactMaterial->mFootstepSoundId < PlayerData::WaterStart))
sound = contactMaterial->mFootstepSoundId;
else if( contactObject && contactObject->getTypeMask() & VehicleObjectType )
sound = 2;
if (sound>=0)
SFX->playOnce(mDataBlock->sound[sound], &footMat);
SFX->playOnce(mDataBlock->getPlayerSoundProfile(sound), &footMat);
}
}
@ -7112,18 +7079,18 @@ void Player:: playImpactSound()
{
Material* material = ( rInfo.material ? dynamic_cast< Material* >( rInfo.material->getMaterial() ) : 0 );
if( material && material->mImpactSoundCustom )
SFX->playOnce( material->mImpactSoundCustom, &getTransform() );
if( material && material->getCustomImpactSoundProfile() )
SFX->playOnce( material->getCustomImpactSoundProfile(), &getTransform() );
else
{
S32 sound = -1;
if (material && (material->mImpactSoundId>-1 && material->mImpactSoundId<PlayerData::MaxSoundOffsets))
if (material && (material->mImpactSoundId > -1 && material->mImpactSoundId < PlayerData::WaterStart))
sound = material->mImpactSoundId;
else if( rInfo.object->getTypeMask() & VehicleObjectType )
sound = 2; // Play metal;
if (sound >= 0)
SFX->playOnce(mDataBlock->sound[PlayerData::ImpactStart + sound], &getTransform());
SFX->playOnce(mDataBlock->getPlayerSoundProfile(PlayerData::ImpactSoft + sound), &getTransform());
}
}
}
@ -7277,11 +7244,11 @@ bool Player::collidingWithWater( Point3F &waterHeight )
void Player::createSplash( Point3F &pos, F32 speed )
{
if ( speed >= mDataBlock->hardSplashSoundVel )
SFX->playOnce( mDataBlock->sound[PlayerData::ImpactWaterHard], &getTransform() );
SFX->playOnce( mDataBlock->getPlayerSoundProfile(PlayerData::ImpactWaterHard), &getTransform() );
else if ( speed >= mDataBlock->medSplashSoundVel )
SFX->playOnce( mDataBlock->sound[PlayerData::ImpactWaterMedium], &getTransform() );
SFX->playOnce( mDataBlock->getPlayerSoundProfile(PlayerData::ImpactWaterMedium), &getTransform() );
else
SFX->playOnce( mDataBlock->sound[PlayerData::ImpactWaterEasy], &getTransform() );
SFX->playOnce( mDataBlock->getPlayerSoundProfile(PlayerData::ImpactWaterEasy), &getTransform() );
if( mDataBlock->splash )
{

View file

@ -35,6 +35,7 @@
#include "collision/boxConvex.h"
#endif
#include "T3D/assets/SoundAsset.h"
#include "T3D/gameBase/gameProcess.h"
class Material;
@ -76,7 +77,7 @@ struct PlayerData: public ShapeBaseData {
/// need to.
DECLARE_SHAPEASSET_ARRAY(PlayerData, ShapeFP, ShapeBase::MaxMountedImages); ///< Used to render with mounted images in first person [optional]
DECLARE_SHAPEASSET_ARRAY_SETGET(PlayerData, ShapeFP);
DECLARE_ASSET_ARRAY_SETGET(PlayerData, ShapeFP);
StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify
/// animation sequences played in first person. [optional]
@ -200,7 +201,7 @@ struct PlayerData: public ShapeBaseData {
FootHard,
FootMetal,
FootSnow,
MaxSoundOffsets,
WaterStart,
FootShallowSplash,
FootWading,
FootUnderWater,
@ -208,7 +209,7 @@ struct PlayerData: public ShapeBaseData {
MoveBubbles,
WaterBreath,
ImpactStart,
ImpactSoft = ImpactStart,
ImpactSoft,
ImpactHard,
ImpactMetal,
ImpactSnow,
@ -218,7 +219,8 @@ struct PlayerData: public ShapeBaseData {
ExitWater,
MaxSounds
};
SFXTrack* sound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(PlayerData, PlayerSound, Sounds::MaxSounds);
Point3F boxSize; ///< Width, depth, height
Point3F crouchBoxSize;
@ -877,5 +879,4 @@ public:
typedef Player::Pose PlayerPose;
DefineEnumType( PlayerPose );
#endif

View file

@ -242,7 +242,7 @@ bool Prefab::protectedSetFile( void *object, const char *index, const char *data
return false;
}
void Prefab::setFile( String file )
void Prefab::setFile( StringTableEntry file )
{
AssertFatal( isServerObject(), "Prefab-bad" );
@ -257,7 +257,7 @@ void Prefab::setFile( String file )
// be called for the client-side prefab but maybe the user did so accidentally.
if ( isClientObject() )
{
Con::errorf( "Prefab::setFile( %s ) - Should not be called on a client-side Prefab.", file.c_str() );
Con::errorf( "Prefab::setFile( %s ) - Should not be called on a client-side Prefab.", file );
return;
}
@ -616,3 +616,9 @@ void ExplodePrefabUndoAction::redo()
name = Sim::getUniqueName( name );
mGroup->assignName( name );
}
DefineEngineMethod(Prefab, getChildGroup, S32, (),,
"")
{
return object->getChildGroup();
}

View file

@ -90,7 +90,7 @@ public:
void render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
///
void setFile( String file );
void setFile(StringTableEntry file );
/// Removes all children from this Prefab and puts them into a SimGroup
/// which is added to the Scene and returned to the caller.
@ -102,6 +102,13 @@ public:
virtual void getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList);
S32 getChildGroup() {
if (mChildGroup.isValid())
return mChildGroup->getId();
return 0;
}
protected:
void _closeFile( bool removeFileNotify );

View file

@ -144,9 +144,9 @@ U32 Projectile::smProjectileWarpTicks = 5;
//
ProjectileData::ProjectileData()
{
INIT_SHAPEASSET(ProjectileShape);
INIT_ASSET(ProjectileShape);
sound = NULL;
INIT_ASSET(ProjectileSound);
explosion = NULL;
explosionId = 0;
@ -217,10 +217,10 @@ ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : G
splashId = other.splashId; // -- for pack/unpack of splash ptr
decal = other.decal;
decalId = other.decalId; // -- for pack/unpack of decal ptr
sound = other.sound;
CLONE_ASSET(ProjectileSound);
lightDesc = other.lightDesc;
lightDescId = other.lightDescId; // -- for pack/unpack of lightDesc ptr
CLONE_SHAPEASSET(ProjectileShape);// -- TSShape loads using mProjectileShapeName
CLONE_ASSET(ProjectileShape);// -- TSShape loads using mProjectileShapeName
activateSeq = other.activateSeq; // -- from projectileShape sequence "activate"
maintainSeq = other.maintainSeq; // -- from projectileShape sequence "maintain"
particleEmitter = other.particleEmitter;
@ -252,8 +252,7 @@ void ProjectileData::initPersistFields()
"@brief Scale to apply to the projectile's size.\n\n"
"@note This is applied after SceneObject::scale\n");
addField("sound", TypeSFXTrackName, Offset(sound, ProjectileData),
"@brief SFXTrack datablock used to play sounds while in flight.\n\n");
INITPERSISTFIELD_SOUNDASSET(ProjectileSound, ProjectileData, "The sound for the projectile.");
addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData),
"@brief Explosion datablock used when the projectile explodes outside of water.\n\n");
@ -368,9 +367,12 @@ bool ProjectileData::preload(bool server, String &errorStr)
if (Sim::findObject(decalId, decal) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(decal): %d", decalId);
String sfxErrorStr;
if( !sfxResolve( &sound, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet: %s", sfxErrorStr.c_str());
_setProjectileSound(getProjectileSound());
if (getProjectileSound() != StringTable->EmptyString())
{
if (!getProjectileSoundProfile())
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Cant get an sfxProfile for splash.");
}
if (!lightDesc && lightDescId != 0)
if (Sim::findObject(lightDescId, lightDesc) == false)
@ -403,7 +405,7 @@ void ProjectileData::packData(BitStream* stream)
{
Parent::packData(stream);
PACKDATA_SHAPEASSET(ProjectileShape);
PACKDATA_ASSET(ProjectileShape);
stream->writeFlag(faceViewer);
if(stream->writeFlag(scale.x != 1 || scale.y != 1 || scale.z != 1))
@ -436,8 +438,7 @@ void ProjectileData::packData(BitStream* stream)
if (stream->writeFlag(decal != NULL))
stream->writeRangedU32(decal->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
sfxWrite( stream, sound );
PACKDATA_ASSET(ProjectileSound);
if ( stream->writeFlag(lightDesc != NULL))
stream->writeRangedU32(lightDesc->getId(), DataBlockObjectIdFirst,
@ -468,7 +469,7 @@ void ProjectileData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
UNPACKDATA_SHAPEASSET(ProjectileShape);
UNPACKDATA_ASSET(ProjectileShape);
faceViewer = stream->readFlag();
if(stream->readFlag())
@ -497,8 +498,8 @@ void ProjectileData::unpackData(BitStream* stream)
if (stream->readFlag())
decalId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
sfxRead( stream, &sound );
UNPACKDATA_ASSET(ProjectileSound);
if (stream->readFlag())
lightDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
@ -786,6 +787,8 @@ bool Projectile::onAdd()
// If we're on the server, we need to inherit some of our parent's velocity
//
mCurrTick = 0;
scriptOnAdd();
}
else
{
@ -882,8 +885,8 @@ bool Projectile::onNewDataBlock( GameBaseData *dptr, bool reload )
SFX_DELETE( mSound );
if ( mDataBlock->sound )
mSound = SFX->createSource( mDataBlock->sound );
if ( mDataBlock->getProjectileSound() )
mSound = SFX->createSource( mDataBlock->getProjectileSoundProfile() );
}
return true;
@ -1097,7 +1100,7 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
void Projectile::updateSound()
{
if (!mDataBlock->sound)
if (!mDataBlock->isProjectileSoundValid())
return;
if ( mSound )

View file

@ -44,6 +44,7 @@
#include "lighting/lightInfo.h"
#endif
#include "T3D/assets/SoundAsset.h"
#include "T3D/assets/ShapeAsset.h"
class ExplosionData;
@ -71,7 +72,7 @@ protected:
public:
DECLARE_SHAPEASSET(ProjectileData, ProjectileShape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(ProjectileData, ProjectileShape);
DECLARE_ASSET_SETGET(ProjectileData, ProjectileShape);
/// Set to true if it is a billboard and want it to always face the viewer, false otherwise
bool faceViewer;
@ -115,7 +116,8 @@ public:
DecalData *decal; // (impact) Decal Datablock
S32 decalId; // (impact) Decal ID
SFXTrack* sound; // Projectile Sound
DECLARE_SOUNDASSET(ProjectileData, ProjectileSound);
DECLARE_ASSET_SETGET(ProjectileData, ProjectileSound);
LightDescription *lightDesc;
S32 lightDescId;

View file

@ -74,16 +74,16 @@ IMPLEMENT_CALLBACK( ProximityMineData, onExplode, void, ( ProximityMine* obj, Po
ProximityMineData::ProximityMineData()
: armingDelay( 0 ),
armingSequence( -1 ),
armingSound( NULL ),
triggerRadius( 5.0f ),
triggerSpeed( 1.0f ),
autoTriggerDelay( 0 ),
triggerOnOwner( false ),
triggerDelay( 0 ),
triggerSequence( -1 ),
triggerSound( NULL ),
explosionOffset( 0.05f )
{
INIT_ASSET(ArmSound);
INIT_ASSET(TriggerSound);
}
void ProximityMineData::initPersistFields()
@ -91,9 +91,9 @@ void ProximityMineData::initPersistFields()
addGroup( "Arming" );
addField( "armingDelay", TypeF32, Offset(armingDelay, ProximityMineData),
"Delay (in seconds) from when the mine is placed to when it becomes active." );
addField( "armingSound", TypeSFXTrackName, Offset(armingSound, ProximityMineData),
"Sound to play when the mine is armed (starts at the same time as "
"the <i>armed</i> sequence if defined)." );
INITPERSISTFIELD_SOUNDASSET(ArmSound, ProximityMineData, "Arming sound for this proximity mine.");
endGroup( "Arming" );
addGroup( "Triggering" );
@ -111,9 +111,9 @@ void ProximityMineData::initPersistFields()
"Speed above which moving objects within the trigger radius will trigger the mine" );
addField( "triggerDelay", TypeF32, Offset(triggerDelay, ProximityMineData),
"Delay (in seconds) from when the mine is triggered until it explodes." );
addField( "triggerSound", TypeSFXTrackName, Offset(triggerSound, ProximityMineData),
"Sound to play when the mine is triggered (starts at the same time as "
"the <i>triggered</i> sequence if defined)." );
INITPERSISTFIELD_SOUNDASSET(TriggerSound, ProximityMineData, "Arming sound for this proximity mine.");
endGroup( "Triggering" );
addGroup( "Explosion" );
@ -135,12 +135,10 @@ bool ProximityMineData::preload( bool server, String& errorStr )
if ( !server )
{
// Resolve sounds
String sfxErrorStr;
if( !sfxResolve( &armingSound, sfxErrorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
if( !sfxResolve( &triggerSound, sfxErrorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
if( !getArmSound() )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid arming sound." );
if( !getTriggerSound() )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid trigger sound." );
}
if ( mShape )
@ -158,14 +156,14 @@ void ProximityMineData::packData( BitStream* stream )
Parent::packData( stream );
stream->write( armingDelay );
sfxWrite( stream, armingSound );
PACKDATA_ASSET(ArmSound);
stream->write( autoTriggerDelay );
stream->writeFlag( triggerOnOwner );
stream->write( triggerRadius );
stream->write( triggerSpeed );
stream->write( triggerDelay );
sfxWrite( stream, triggerSound );
PACKDATA_ASSET(TriggerSound);
}
void ProximityMineData::unpackData( BitStream* stream )
@ -173,14 +171,14 @@ void ProximityMineData::unpackData( BitStream* stream )
Parent::unpackData(stream);
stream->read( &armingDelay );
sfxRead( stream, &armingSound );
UNPACKDATA_ASSET(ArmSound);
stream->read( &autoTriggerDelay );
triggerOnOwner = stream->readFlag();
stream->read( &triggerRadius );
stream->read( &triggerSpeed );
stream->read( &triggerDelay );
sfxRead( stream, &triggerSound );
UNPACKDATA_ASSET(TriggerSound);
}
//----------------------------------------------------------------------------
@ -428,8 +426,8 @@ void ProximityMine::processTick( const Move* move )
mAnimThread = mShapeInstance->addThread();
mShapeInstance->setSequence( mAnimThread, mDataBlock->armingSequence, 0.0f );
}
if ( mDataBlock->armingSound )
SFX->playOnce( mDataBlock->armingSound, &getRenderTransform() );
if ( mDataBlock->getArmSoundProfile() )
SFX->playOnce( mDataBlock->getArmSoundProfile(), &getRenderTransform() );
}
break;
@ -469,8 +467,8 @@ void ProximityMine::processTick( const Move* move )
mAnimThread = mShapeInstance->addThread();
mShapeInstance->setSequence( mAnimThread, mDataBlock->triggerSequence, 0.0f );
}
if ( mDataBlock->triggerSound )
SFX->playOnce( mDataBlock->triggerSound, &getRenderTransform() );
if ( mDataBlock->getTriggerSoundProfile() )
SFX->playOnce( mDataBlock->getTriggerSoundProfile(), &getRenderTransform() );
if ( isServerObject() )
mDataBlock->onTriggered_callback( this, sql.mList[0] );

View file

@ -27,6 +27,8 @@
#include "T3D/item.h"
#endif
#include "T3D/assets/SoundAsset.h"
class ExplosionData;
class SFXTrack;
class ProximityMine;
@ -43,7 +45,8 @@ struct ProximityMineData: public ItemData
public:
F32 armingDelay;
S32 armingSequence;
SFXTrack* armingSound;
DECLARE_SOUNDASSET(ProximityMineData, ArmSound);
DECLARE_ASSET_SETGET(ProximityMineData, ArmSound);
F32 autoTriggerDelay;
bool triggerOnOwner;
@ -51,7 +54,8 @@ public:
F32 triggerSpeed;
F32 triggerDelay;
S32 triggerSequence;
SFXTrack* triggerSound;
DECLARE_SOUNDASSET(ProximityMineData, TriggerSound);
DECLARE_ASSET_SETGET(ProximityMineData, TriggerSound);
F32 explosionOffset;

View file

@ -238,7 +238,7 @@ RigidShapeData::RigidShapeData()
density = 4;
for (S32 i = 0; i < Body::MaxSounds; i++)
body.sound[i] = 0;
INIT_ASSET_ARRAY(BodySounds, i);
dustEmitter = NULL;
dustID = 0;
@ -256,13 +256,15 @@ RigidShapeData::RigidShapeData()
hardSplashSoundVel = 3.0;
enablePhysicsRep = true;
dMemset(waterSound, 0, sizeof(waterSound));
for (S32 i = 0; i < Sounds::MaxSounds; i++)
INIT_ASSET_ARRAY(WaterSounds, i);
dragForce = 0;
vertFactor = 0.25;
dustTrailEmitter = NULL;
dustTrailID = 0;
_setShape(ShapeAsset::smNoShapeAssetFallback);
}
RigidShapeData::~RigidShapeData()
@ -298,7 +300,21 @@ bool RigidShapeData::preload(bool server, String &errorStr)
// Resolve objects transmitted from server
if (!server) {
for (S32 i = 0; i < Body::MaxSounds; i++)
sfxResolve( &body.sound[ i ], errorStr );
{
if (mBodySounds[i])
{
_setBodySounds(getBodySounds(i), i);
}
}
for (S32 j = 0; j < Sounds::MaxSounds; j++)
{
if (mWaterSounds[j])
{
_setWaterSounds(getWaterSounds(j), j);
}
}
}
if( !dustEmitter && dustID != 0 )
@ -353,8 +369,10 @@ void RigidShapeData::packData(BitStream* stream)
stream->write(body.restitution);
stream->write(body.friction);
for( U32 i = 0; i < Body::MaxSounds; ++ i )
sfxWrite( stream, body.sound[ i ] );
for (U32 i = 0; i < Body::MaxSounds; ++i)
{
PACKDATA_ASSET_ARRAY(BodySounds, i);
}
stream->write(minImpactSpeed);
stream->write(softImpactSpeed);
@ -383,8 +401,10 @@ void RigidShapeData::packData(BitStream* stream)
stream->write(enablePhysicsRep);
// write the water sound profiles
for( U32 i = 0; i < MaxSounds; ++ i )
sfxWrite( stream, waterSound[ i ] );
for (U32 i = 0; i < Sounds::MaxSounds; ++i)
{
PACKDATA_ASSET_ARRAY(WaterSounds, i);
}
if (stream->writeFlag( dustEmitter ))
stream->writeRangedU32( dustEmitter->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
@ -412,8 +432,10 @@ void RigidShapeData::unpackData(BitStream* stream)
stream->read(&body.restitution);
stream->read(&body.friction);
for( U32 i = 0; i < Body::MaxSounds; i++)
sfxRead( stream, &body.sound[ i ] );
for (U32 i = 0; i < Body::Sounds::MaxSounds; i++)
{
UNPACKDATA_ASSET_ARRAY(BodySounds, i);
}
stream->read(&minImpactSpeed);
stream->read(&softImpactSpeed);
@ -442,8 +464,10 @@ void RigidShapeData::unpackData(BitStream* stream)
stream->read(&enablePhysicsRep);
// write the water sound profiles
for( U32 i = 0; i < MaxSounds; ++ i )
sfxRead( stream, &waterSound[ i ] );
for (U32 i = 0; i < Sounds::MaxSounds; ++i)
{
UNPACKDATA_ASSET_ARRAY(WaterSounds, i);
}
if( stream->readFlag() )
dustID = (S32) stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
@ -515,21 +539,15 @@ void RigidShapeData::initPersistFields()
addGroup( "Sounds" );
addField("softImpactSound", TypeSFXTrackName, Offset(body.sound[Body::SoftImpactSound], RigidShapeData),
"Sound to play when body impacts with at least softImageSpeed but less than hardImpactSpeed." );
addField("hardImpactSound", TypeSFXTrackName, Offset(body.sound[Body::HardImpactSound], RigidShapeData),
"Sound to play when body impacts with at least hardImpactSpeed." );
INITPERSISTFIELD_SOUNDASSET_ARRAY(BodySounds, Body::Sounds::MaxSounds, RigidShapeData, "Sounds for body.");
addField("exitSplashSoundVelocity", TypeF32, Offset(exitSplashSoundVel, RigidShapeData), "The minimum velocity at which the exit splash sound will be played when emerging from water.\n");
addField("softSplashSoundVelocity", TypeF32, Offset(softSplashSoundVel, RigidShapeData),"The minimum velocity at which the soft splash sound will be played when impacting water.\n");
addField("mediumSplashSoundVelocity", TypeF32, Offset(medSplashSoundVel, RigidShapeData), "The minimum velocity at which the medium splash sound will be played when impacting water.\n");
addField("hardSplashSoundVelocity", TypeF32, Offset(hardSplashSoundVel, RigidShapeData), "The minimum velocity at which the hard splash sound will be played when impacting water.\n");
addField("exitingWater", TypeSFXTrackName, Offset(waterSound[ExitWater], RigidShapeData), "The AudioProfile will be used to produce sounds when emerging from water.\n");
addField("impactWaterEasy", TypeSFXTrackName, Offset(waterSound[ImpactSoft], RigidShapeData), "The AudioProfile will be used to produce sounds when a soft impact with water occurs.\n");
addField("impactWaterMedium", TypeSFXTrackName, Offset(waterSound[ImpactMedium], RigidShapeData), "The AudioProfile will be used to produce sounds when a medium impact with water occurs.\n");
addField("impactWaterHard", TypeSFXTrackName, Offset(waterSound[ImpactHard], RigidShapeData), "The AudioProfile will be used to produce sounds when a hard impact with water occurs.\n");
addField("waterWakeSound", TypeSFXTrackName, Offset(waterSound[Wake], RigidShapeData), "The AudioProfile will be used to produce sounds when a water wake is displayed.\n");
INITPERSISTFIELD_SOUNDASSET_ARRAY(WaterSounds, Sounds::MaxSounds, RigidShapeData, "Sounds for interacting with water.");
endGroup( "Sounds" );
addGroup( "Camera" );
@ -1154,27 +1172,27 @@ void RigidShape::updatePos(F32 dt)
if (collSpeed >= mDataBlock->softImpactSpeed)
impactSound = RigidShapeData::Body::SoftImpactSound;
if (impactSound != -1 && mDataBlock->body.sound[impactSound] != NULL)
SFX->playOnce(mDataBlock->body.sound[impactSound], &getTransform());
if (impactSound != -1 && mDataBlock->getBodySoundsProfile(impactSound))
SFX->playOnce(mDataBlock->getBodySoundsProfile(impactSound), &getTransform());
}
// Water volume sounds
F32 vSpeed = getVelocity().len();
if (!inLiquid && mWaterCoverage >= 0.8f) {
if (vSpeed >= mDataBlock->hardSplashSoundVel)
SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactHard], &getTransform());
SFX->playOnce(mDataBlock->getWaterSoundsProfile(RigidShapeData::ImpactHard), &getTransform());
else
if (vSpeed >= mDataBlock->medSplashSoundVel)
SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactMedium], &getTransform());
SFX->playOnce(mDataBlock->getWaterSoundsProfile(RigidShapeData::ImpactMedium), &getTransform());
else
if (vSpeed >= mDataBlock->softSplashSoundVel)
SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ImpactSoft], &getTransform());
SFX->playOnce(mDataBlock->getWaterSoundsProfile(RigidShapeData::ImpactSoft), &getTransform());
inLiquid = true;
}
else
if (inLiquid && mWaterCoverage < 0.8f) {
if (vSpeed >= mDataBlock->exitSplashSoundVel)
SFX->playOnce(mDataBlock->waterSound[RigidShapeData::ExitWater], &getTransform());
SFX->playOnce(mDataBlock->getWaterSoundsProfile(RigidShapeData::ExitWater), &getTransform());
inLiquid = false;
}
}

View file

@ -35,6 +35,8 @@
#include "T3D/physics/physicsBody.h"
#endif
#include "T3D/assets/SoundAsset.h"
class ParticleEmitter;
class ParticleEmitterData;
class ClippedPolyList;
@ -57,11 +59,13 @@ class RigidShapeData : public ShapeBaseData
HardImpactSound,
MaxSounds,
};
SFXTrack* sound[MaxSounds];
F32 restitution;
F32 friction;
} body;
DECLARE_SOUNDASSET_ARRAY(RigidShapeData, BodySounds, Body::Sounds::MaxSounds)
DECLARE_ASSET_ARRAY_SETGET(RigidShapeData, BodySounds);
enum RigidShapeConsts
{
VC_NUM_DUST_EMITTERS = 1,
@ -79,7 +83,8 @@ class RigidShapeData : public ShapeBaseData
Wake,
MaxSounds
};
SFXTrack* waterSound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(RigidShapeData, WaterSounds, Sounds::MaxSounds)
DECLARE_ASSET_ARRAY_SETGET(RigidShapeData, WaterSounds);
F32 exitSplashSoundVel;
F32 softSplashSoundVel;

View file

@ -94,22 +94,23 @@ ColorI SFXEmitter::smRenderColorRangeSphere( 200, 0, 0, 90 );
SFXEmitter::SFXEmitter()
: SceneObject(),
mSource( NULL ),
mTrack( NULL ),
mUseTrackDescriptionOnly( false ),
mLocalProfile( &mDescription ),
mPlayOnAdd( true )
{
mTypeMask |= MarkerObjectType;
mNetFlags.set( Ghostable | ScopeAlways );
mDescription.mIs3D = true;
mDescription.mIsLooping = true;
mDescription.mIsStreaming = false;
mDescription.mFadeInTime = -1.f;
mDescription.mFadeOutTime = -1.f;
mLocalProfile.mFilename = StringTable->EmptyString();
mLocalProfile._registerSignals();
INIT_ASSET(Sound);
mObjBox.minExtents.set( -1.f, -1.f, -1.f );
mObjBox.maxExtents.set( 1.f, 1.f, 1.f );
}
@ -174,15 +175,17 @@ void SFXEmitter::consoleInit()
void SFXEmitter::initPersistFields()
{
addGroup( "Media" );
addField( "track", TypeSFXTrackName, Offset( mTrack, SFXEmitter),
INITPERSISTFIELD_SOUNDASSET(Sound, SFXEmitter, "");
/*addField("track", TypeSFXTrackName, Offset(mTrack, SFXEmitter),
"The track which the emitter should play.\n"
"@note If assigned, this field will take precedence over a #fileName that may also be assigned to the "
"emitter." );
addField( "fileName", TypeStringFilename, Offset( mLocalProfile.mFilename, SFXEmitter),
"The sound file to play.\n"
"Use @b either this property @b or #track. If both are assigned, #track takes precendence. The primary purpose of this "
"field is to avoid the need for the user to define SFXTrack datablocks for all sounds used in a level." );
"field is to avoid the need for the user to define SFXTrack datablocks for all sounds used in a level." );*/
endGroup( "Media");
@ -287,12 +290,13 @@ U32 SFXEmitter::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
stream->writeAffineTransform( mObjToWorld );
// track
if( stream->writeFlag( mDirty.test( Track ) ) )
sfxWrite( stream, mTrack );
PACK_ASSET(con, Sound);
//if (stream->writeFlag(mDirty.test(Track)))
// sfxWrite( stream, mTrack );
// filename
if( stream->writeFlag( mDirty.test( Filename ) ) )
stream->writeString( mLocalProfile.mFilename );
//if( stream->writeFlag( mDirty.test( Filename ) ) )
// stream->writeString( mLocalProfile.mFilename );
// volume
if( stream->writeFlag( mDirty.test( Volume ) ) )
@ -397,7 +401,8 @@ void SFXEmitter::unpackUpdate( NetConnection *conn, BitStream *stream )
}
// track
if ( _readDirtyFlag( stream, Track ) )
UNPACK_ASSET(conn, Sound);
/*if (_readDirtyFlag(stream, Track))
{
String errorStr;
if( !sfxReadAndResolve( stream, &mTrack, errorStr ) )
@ -406,7 +411,7 @@ void SFXEmitter::unpackUpdate( NetConnection *conn, BitStream *stream )
// filename
if ( _readDirtyFlag( stream, Filename ) )
mLocalProfile.mFilename = stream->readSTString();
mLocalProfile.mFilename = stream->readSTString();*/
// volume
if ( _readDirtyFlag( stream, Volume ) )
@ -586,8 +591,8 @@ void SFXEmitter::inspectPostApply()
// Parent will call setScale so sync up scale with distance.
F32 maxDistance = mDescription.mMaxDistance;
if( mUseTrackDescriptionOnly && mTrack )
maxDistance = mTrack->getDescription()->mMaxDistance;
if( mUseTrackDescriptionOnly && mSoundAsset )
maxDistance = mSoundAsset->getSfxDescription()->mMaxDistance;
mObjScale.set( maxDistance, maxDistance, maxDistance );
@ -608,8 +613,8 @@ bool SFXEmitter::onAdd()
mDescription.validate();
// Read an old 'profile' field for backwards-compatibility.
if( !mTrack )
/*
if(mSoundAsset.isNull() || !mSoundAsset->getSfxProfile())
{
static const char* sProfile = StringTable->insert( "profile" );
const char* profileName = getDataField( sProfile, NULL );
@ -643,7 +648,7 @@ bool SFXEmitter::onAdd()
// Remove the old 'channel' field.
setDataField( sChannel, NULL, "" );
}
}
}*/
}
else
{
@ -683,6 +688,12 @@ void SFXEmitter::_update()
// we can restore it.
SFXStatus prevState = mSource ? mSource->getStatus() : SFXStatusNull;
if (mSoundAsset.notNull() )
{
mLocalProfile = *mSoundAsset->getSfxProfile();
mDescription = *mSoundAsset->getSfxDescription();
}
// Make sure all the settings are valid.
mDescription.validate();
@ -695,12 +706,12 @@ void SFXEmitter::_update()
SFX_DELETE( mSource );
// Do we have a track?
if( mTrack )
if( mSoundAsset && mSoundAsset->getSfxProfile() )
{
mSource = SFX->createSource( mTrack, &transform, &velocity );
mSource = SFX->createSource(mSoundAsset->getSfxProfile(), &transform, &velocity );
if( !mSource )
Con::errorf( "SFXEmitter::_update() - failed to create sound for track %i (%s)",
mTrack->getId(), mTrack->getName() );
mSoundAsset->getSfxProfile()->getId(), mSoundAsset->getSfxProfile()->getName() );
// If we're supposed to play when the emitter is
// added to the scene then also restart playback
@ -739,12 +750,12 @@ void SFXEmitter::_update()
// is toggled on a local profile sound. It makes the
// editor feel responsive and that things are working.
if( gEditingMission &&
!mTrack &&
(mSoundAsset.isNull() || !mSoundAsset->getSfxProfile()) &&
mPlayOnAdd &&
mDirty.test( IsLooping ) )
prevState = SFXStatusPlaying;
bool useTrackDescriptionOnly = ( mUseTrackDescriptionOnly && mTrack );
bool useTrackDescriptionOnly = ( mUseTrackDescriptionOnly && mSoundAsset.notNull() && mSoundAsset->getSfxProfile());
// The rest only applies if we have a source.
if( mSource )
@ -1087,8 +1098,8 @@ SFXStatus SFXEmitter::_getPlaybackStatus() const
bool SFXEmitter::is3D() const
{
if( mTrack != NULL )
return mTrack->getDescription()->mIs3D;
if( mSoundAsset.notNull() && mSoundAsset->getSfxProfile() != NULL )
return mSoundAsset->getSfxProfile()->getDescription()->mIs3D;
else
return mDescription.mIs3D;
}
@ -1124,8 +1135,8 @@ void SFXEmitter::setScale( const VectorF &scale )
{
F32 maxDistance;
if( mUseTrackDescriptionOnly && mTrack )
maxDistance = mTrack->getDescription()->mMaxDistance;
if( mUseTrackDescriptionOnly && mSoundAsset.notNull() && mSoundAsset->getSfxProfile())
maxDistance = mSoundAsset->getSfxProfile()->getDescription()->mMaxDistance;
else
{
// Use the average of the three coords.

View file

@ -36,6 +36,7 @@
#include "gfx/gfxStateBlock.h"
#endif
#include "T3D/assets/SoundAsset.h"
class SFXSource;
class SFXTrack;
@ -103,13 +104,11 @@ class SFXEmitter : public SceneObject
/// The current dirty flags.
BitSet32 mDirty;
DECLARE_SOUNDASSET(SFXEmitter, Sound);
DECLARE_ASSET_NET_SETGET(SFXEmitter, Sound, DirtyUpdateMask);
/// The sound source for the emitter.
SFXSource *mSource;
/// The selected track or null if the local
/// profile should be used.
SFXTrack *mTrack;
/// Whether to leave sound setup exclusively to the assigned mTrack and not
/// override part of the track's description with emitter properties.
bool mUseTrackDescriptionOnly;

View file

@ -197,8 +197,8 @@ ShapeBaseData::ShapeBaseData()
renderWhenDestroyed( true ),
inheritEnergyFromMount( false )
{
INIT_SHAPEASSET(Shape);
INIT_SHAPEASSET(DebrisShape);
INIT_ASSET(Shape);
INIT_ASSET(DebrisShape);
dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
remap_txr_tags = NULL;
@ -214,13 +214,13 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game
shadowProjectionDistance = other.shadowProjectionDistance;
shadowSphereAdjust = other.shadowSphereAdjust;
cloakTexName = other.cloakTexName;
CLONE_SHAPEASSET(Shape);
CLONE_ASSET(Shape);
cubeDescName = other.cubeDescName;
cubeDescId = other.cubeDescId;
reflectorDesc = other.reflectorDesc;
debris = other.debris;
debrisID = other.debrisID; // -- for pack/unpack of debris ptr
CLONE_SHAPEASSET(DebrisShape);
CLONE_ASSET(DebrisShape);
explosion = other.explosion;
explosionID = other.explosionID; // -- for pack/unpack of explosion ptr
underwaterExplosion = other.underwaterExplosion;
@ -757,8 +757,8 @@ void ShapeBaseData::packData(BitStream* stream)
stream->write(shadowProjectionDistance);
stream->write(shadowSphereAdjust);
PACKDATA_SHAPEASSET(Shape);
PACKDATA_SHAPEASSET(DebrisShape);
PACKDATA_ASSET(Shape);
PACKDATA_ASSET(DebrisShape);
stream->writeString(cloakTexName);
if(stream->writeFlag(mass != gShapeBaseDataProto.mass))
@ -835,8 +835,8 @@ void ShapeBaseData::unpackData(BitStream* stream)
stream->read(&shadowProjectionDistance);
stream->read(&shadowSphereAdjust);
UNPACKDATA_SHAPEASSET(Shape);
UNPACKDATA_SHAPEASSET(DebrisShape);
UNPACKDATA_ASSET(Shape);
UNPACKDATA_ASSET(DebrisShape);
cloakTexName = stream->readSTString();
if(stream->readFlag())
@ -1009,7 +1009,7 @@ ShapeBase::ShapeBase()
for (i = 0; i < MaxSoundThreads; i++) {
mSoundThread[i].play = false;
mSoundThread[i].profile = 0;
mSoundThread[i].asset = 0;
mSoundThread[i].sound = 0;
}
@ -2233,24 +2233,30 @@ void ShapeBase::applyImpulse(const Point3F&,const VectorF&)
//----------------------------------------------------------------------------
void ShapeBase::playAudio(U32 slot,SFXTrack* profile)
void ShapeBase::playAudio(U32 slot, StringTableEntry assetId)
{
AssertFatal( slot < MaxSoundThreads, "ShapeBase::playAudio() bad slot index" );
Sound& st = mSoundThread[slot];
if( profile && ( !st.play || st.profile != profile ) )
if (AssetDatabase.isDeclaredAsset(assetId))
{
AssetPtr<SoundAsset> tempSoundAsset;
tempSoundAsset = assetId;
SoundThread& st = mSoundThread[slot];
if (tempSoundAsset && (!st.play || st.asset != tempSoundAsset))
{
setMaskBits(SoundMaskN << slot);
st.play = true;
st.profile = profile;
st.asset = tempSoundAsset;
updateAudioState(st);
}
}
}
void ShapeBase::stopAudio(U32 slot)
{
AssertFatal( slot < MaxSoundThreads, "ShapeBase::stopAudio() bad slot index" );
Sound& st = mSoundThread[slot];
SoundThread& st = mSoundThread[slot];
if ( st.play )
{
st.play = false;
@ -2263,7 +2269,7 @@ void ShapeBase::updateServerAudio()
{
// Timeout non-looping sounds
for (S32 i = 0; i < MaxSoundThreads; i++) {
Sound& st = mSoundThread[i];
SoundThread& st = mSoundThread[i];
if (st.play && st.timeout && st.timeout < Sim::getCurrentTime()) {
clearMaskBits(SoundMaskN << i);
st.play = false;
@ -2271,17 +2277,18 @@ void ShapeBase::updateServerAudio()
}
}
void ShapeBase::updateAudioState(Sound& st)
void ShapeBase::updateAudioState(SoundThread& st)
{
SFX_DELETE( st.sound );
if ( st.play && st.profile )
if ( st.play && st.asset )
{
if ( isGhost() )
{
if ( Sim::findObject( SimObjectId((uintptr_t)st.profile), st.profile ) )
// if asset is valid, play
if (st.asset->isAssetValid() )
{
st.sound = SFX->createSource( st.profile, &getTransform() );
st.sound = SFX->createSource( st.asset->getSfxProfile() , &getTransform() );
if ( st.sound )
st.sound->play();
}
@ -2292,12 +2299,17 @@ void ShapeBase::updateAudioState(Sound& st)
{
// Non-looping sounds timeout on the server
st.timeout = 0;
if ( !st.profile->getDescription()->mIsLooping )
if ( !st.asset->getSfxDescription()->mIsLooping )
st.timeout = Sim::getCurrentTime() + sAudioTimeout;
}
}
else
{
// st.sound was not stopped before. If this causes issues remove.
st.play = false;
if (st.sound)
st.sound->stop();
}
}
void ShapeBase::updateAudioPos()
@ -3122,13 +3134,15 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
if (stream->writeFlag(mask & SoundMask)) {
for (S32 i = 0; i < MaxSoundThreads; i++) {
Sound& st = mSoundThread[i];
SoundThread& st = mSoundThread[i];
if (stream->writeFlag(mask & (SoundMaskN << i)))
if (stream->writeFlag(st.play))
stream->writeRangedU32(st.profile->getId(),DataBlockObjectIdFirst,
DataBlockObjectIdLast);
{
NetStringHandle assetIdStr = st.asset->getAssetId();
con->packNetStringHandleU(stream, assetIdStr);
}
}
}
if (stream->writeFlag(mask & ImageMask)) {
for (S32 i = 0; i < MaxMountedImages; i++)
@ -3242,12 +3256,18 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
{
if ( stream->readFlag() )
{
Sound& st = mSoundThread[i];
SoundThread& st = mSoundThread[i];
st.play = stream->readFlag();
if ( st.play )
{
st.profile = (SFXTrack*)(uintptr_t)stream->readRangedU32( DataBlockObjectIdFirst,
DataBlockObjectIdLast );
StringTableEntry temp = StringTable->insert(con->unpackNetStringHandleU(stream).getString());
if (AssetDatabase.isDeclaredAsset(temp))
{
AssetPtr<SoundAsset> tempSoundAsset;
tempSoundAsset = temp;
st.asset = temp;
}
}
if ( isProperlyAdded() )
@ -3777,7 +3797,7 @@ DefineEngineMethod( ShapeBase, isHidden, bool, (),,
}
//----------------------------------------------------------------------------
DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, SFXTrack* track ),,
DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, StringTableEntry assetId),,
"@brief Attach a sound to this shape and start playing it.\n\n"
"@param slot Audio slot index for the sound (valid range is 0 - 3)\n" // 3 = ShapeBase::MaxSoundThreads-1
@ -3786,8 +3806,8 @@ DefineEngineMethod( ShapeBase, playAudio, bool, ( S32 slot, SFXTrack* track ),,
"@see stopAudio()\n")
{
if (track && slot >= 0 && slot < ShapeBase::MaxSoundThreads) {
object->playAudio(slot,track);
if (assetId && slot >= 0 && slot < ShapeBase::MaxSoundThreads) {
object->playAudio(slot, assetId);
return true;
}
return false;

View file

@ -73,6 +73,7 @@
// Need full definition visible for SimObjectPtr<ParticleEmitter>
#include "T3D/fx/particleEmitter.h"
#include "T3D/assets/SoundAsset.h"
class GFXCubemap;
class TSShapeInstance;
@ -116,7 +117,7 @@ class ShapeBaseConvex : public Convex
Box3F box;
public:
ShapeBaseConvex() :pShapeBase(NULL), transform(NULL), hullId(NULL), nodeTransform(0) { mType = ShapeBaseConvexType; }
ShapeBaseConvex() :pShapeBase(NULL), transform(NULL), hullId(0), nodeTransform(0) { mType = ShapeBaseConvexType; }
ShapeBaseConvex(const ShapeBaseConvex& cv) {
mObject = cv.mObject;
pShapeBase = cv.pShapeBase;
@ -259,11 +260,13 @@ struct ShapeBaseImageData: public GameBaseData {
/// the imageSlot.
ParticleEmitterData* emitter; ///< A particle emitter; this emitter will emit as long as the gun is in this
/// this state.
SFXTrack* sound;
//SFXTrack* sound;
F32 emitterTime; ///<
S32 emitterNode[MaxShapes]; ///< Node ID on the shape to emit from
SoundAsset* sound;
SFXTrack* soundTrack; ///<Holdover for special, non-asset cases like SFXPlaylists
};
/// @name State Data
/// Individual state data used to initialize struct array
/// @{
@ -321,7 +324,10 @@ struct ShapeBaseImageData: public GameBaseData {
bool stateIgnoreLoadedForReady [MaxStates];
SFXTrack* stateSound [MaxStates];
DECLARE_SOUNDASSET_ARRAY(ShapeBaseImageData, stateSound, MaxStates);
DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, stateSound);
//SFXTrack* stateSound [MaxStates];
const char* stateScript [MaxStates];
ParticleEmitterData* stateEmitter [MaxStates];
@ -374,10 +380,10 @@ struct ShapeBaseImageData: public GameBaseData {
///< when the script prefix has changed.
DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes); ///< Name of shape to render.
DECLARE_SHAPEASSET_ARRAY_SETGET(ShapeBaseImageData, Shape);
DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, Shape);
//DECLARE_SHAPEASSET(ShapeBaseImageData, ShapeFP); ///< Name of shape to render in first person (optional).
//DECLARE_SHAPEASSET_SETGET(ShapeBaseImageData, ShapeFP);
//DECLARE_ASSET_SETGET(ShapeBaseImageData, ShapeFP);
StringTableEntry imageAnimPrefix; ///< Passed along to the mounting shape to modify
/// animation sequences played in 3rd person. [optional]
@ -541,7 +547,7 @@ public:
F32 shadowSphereAdjust;
DECLARE_SHAPEASSET(ShapeBaseData, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(ShapeBaseData, Shape);
DECLARE_ASSET_SETGET(ShapeBaseData, Shape);
StringTableEntry cloakTexName;
@ -557,7 +563,7 @@ public:
S32 debrisID;
DECLARE_SHAPEASSET(ShapeBaseData, DebrisShape, onDebrisChanged);
DECLARE_SHAPEASSET_SETGET(ShapeBaseData, DebrisShape);
DECLARE_ASSET_SETGET(ShapeBaseData, DebrisShape);
ExplosionData* explosion;
S32 explosionID;
@ -662,7 +668,7 @@ public:
DECLARE_CALLBACK( void, onCollision, ( ShapeBase* obj, SceneObject* collObj, VectorF vec, F32 len ) );
DECLARE_CALLBACK( void, onDamage, ( ShapeBase* obj, F32 delta ) );
DECLARE_CALLBACK( void, onTrigger, ( ShapeBase* obj, S32 index, bool state ) );
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
DECLARE_CALLBACK( void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
/// @}
struct TextureTagRemapping
@ -739,13 +745,13 @@ protected:
/// @name Scripted Sound
/// @{
struct Sound {
struct SoundThread {
bool play; ///< Are we playing this sound?
SimTime timeout; ///< Time until we stop playing this sound.
SFXTrack* profile; ///< Profile on server
AssetPtr<SoundAsset> asset; ///< Asset on server
SFXSource* sound; ///< Sound on client
};
Sound mSoundThread[MaxSoundThreads];
SoundThread mSoundThread[MaxSoundThreads];
/// @}
/// @name Scripted Animation Threads
@ -1109,7 +1115,7 @@ protected:
/// Updates the audio state of the supplied sound
/// @param st Sound
void updateAudioState(Sound& st);
void updateAudioState(SoundThread& st);
/// Recalculates the spacial sound based on the current position of the object
/// emitting the sound.
@ -1323,9 +1329,7 @@ public:
/// Plays an audio sound from a mounted object
/// @param slot Mount slot ID
/// @param track Audio track to play
void playAudio(U32 slot,SFXTrack* track);
void playAudio( U32 slot, SFXProfile* profile ) { playAudio( slot, ( SFXTrack* ) profile ); }
void playAudio(U32 slot, StringTableEntry assetId);
/// Stops audio from a mounted object
/// @param slot Mount slot ID

View file

@ -132,7 +132,8 @@ ShapeBaseImageData::StateData::StateData()
loaded = IgnoreLoaded;
spin = IgnoreSpin;
recoil = NoRecoil;
sound = 0;
sound = NULL;
soundTrack = NULL;
emitter = NULL;
shapeSequence = NULL;
shapeSequenceScale = true;
@ -156,6 +157,7 @@ ShapeBaseImageData::StateData::StateData()
flashSequence[i] = false;
emitterNode[i] = -1;
}
}
static ShapeBaseImageData::StateData gDefaultStateData;
@ -256,7 +258,7 @@ ShapeBaseImageData::ShapeBaseImageData()
stateShapeSequence[i] = 0;
stateScaleShapeSequence[i] = false;
stateSound[i] = 0;
INIT_ASSET_ARRAY(stateSound, i);
stateScript[i] = 0;
stateEmitter[i] = 0;
stateEmitterTime[i] = 0;
@ -294,7 +296,7 @@ ShapeBaseImageData::ShapeBaseImageData()
hasFlash[i] = false;
shapeIsValid[i] = false;
INIT_SHAPEASSET_ARRAY(Shape, i);
INIT_ASSET_ARRAY(Shape, i);
}
shakeCamera = false;
@ -303,6 +305,7 @@ ShapeBaseImageData::ShapeBaseImageData()
camShakeDuration = 1.5f;
camShakeRadius = 3.0f;
camShakeFalloff = 10.0f;
}
ShapeBaseImageData::~ShapeBaseImageData()
@ -368,7 +371,21 @@ bool ShapeBaseImageData::onAdd()
s.shapeSequence = stateShapeSequence[i];
s.shapeSequenceScale = stateScaleShapeSequence[i];
s.sound = stateSound[i];
//_setstateSound(getstateSound(i),i);
s.sound = getstateSoundAsset(i);
if (s.sound == NULL && mstateSoundName[i] != StringTable->EmptyString())
{
//ok, so we've got some sort of special-case here like a fallback or SFXPlaylist. So do the hook-up now
SFXTrack* sndTrack;
if (!Sim::findObject(mstateSoundName[i], sndTrack))
{
Con::errorf("ShapeBaseImageData::onAdd() - attempted to find sound %s but failed!", mstateSoundName[i]);
}
else
{
s.soundTrack = sndTrack;
}
}
s.script = stateScript[i];
s.emitter = stateEmitter[i];
s.emitterTime = stateEmitterTime[i];
@ -407,7 +424,6 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
{
if (!Parent::preload(server, errorStr))
return false;
bool shapeError = false;
// Resolve objects transmitted from server
if (!server) {
@ -419,10 +435,14 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
if (state[i].emitter)
if (!Sim::findObject(SimObjectId((uintptr_t)state[i].emitter), state[i].emitter))
Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");
String str;
if( !sfxResolve( &state[ i ].sound, str ) )
Con::errorf( ConsoleLogEntry::General, str.c_str() );
if (getstateSound(i) != StringTable->EmptyString())
{
_setstateSound(getstateSound(i), i);
if (!getstateSoundProfile(i))
Con::errorf("ShapeBaseImageData::preload() - Could not find profile for asset %s on state %d", getstateSound(i), i);
}
}
}
@ -922,8 +942,8 @@ void ShapeBaseImageData::initPersistFields()
addField( "stateScaleShapeSequence", TypeBool, Offset(stateScaleShapeSequence, ShapeBaseImageData), MaxStates,
"Indicates if the sequence to be played on the mounting shape should be scaled to the length of the state." );
addField( "stateSound", TypeSFXTrackName, Offset(stateSound, ShapeBaseImageData), MaxStates,
"Sound to play on entry to this state." );
INITPERSISTFIELD_SOUNDASSET_ARRAY(stateSound, MaxStates, ShapeBaseImageData, "State sound.");
addField( "stateScript", TypeCaseString, Offset(stateScript, ShapeBaseImageData), MaxStates,
"@brief Method to execute on entering this state.\n\n"
"Scoped to this image class name, then ShapeBaseImageData. The script "
@ -976,7 +996,7 @@ void ShapeBaseImageData::packData(BitStream* stream)
for (U32 j = 0; j < MaxShapes; ++j)
{
PACKDATA_SHAPEASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional)
PACKDATA_ASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional)
}
stream->writeString(imageAnimPrefix);
@ -1140,7 +1160,7 @@ void ShapeBaseImageData::packData(BitStream* stream)
}
}
sfxWrite( stream, s.sound );
PACKDATA_ASSET_ARRAY(stateSound, i);
}
stream->write(maxConcurrentSounds);
stream->writeFlag(useRemainderDT);
@ -1160,7 +1180,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
for (U32 j = 0; j < MaxShapes; ++j)
{
UNPACKDATA_SHAPEASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional)
UNPACKDATA_ASSET_ARRAY(Shape, j); // shape 0 for normal use, shape 1 for first person use (optional)
}
imageAnimPrefix = stream->readSTString();
@ -1345,7 +1365,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
else
s.emitter = 0;
sfxRead( stream, &s.sound );
UNPACKDATA_ASSET_ARRAY(stateSound, i);
}
}
@ -2574,7 +2594,7 @@ bool ShapeBase::hasImageState(U32 imageSlot, const char* state)
return false;
}
void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
void ShapeBase::setImageState(U32 imageSlot, U32 newState, bool force)
{
if (!mMountedImageList[imageSlot].dataBlock)
return;
@ -2605,12 +2625,12 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
// Eject shell casing on every state change (client side only)
ShapeBaseImageData::StateData& nextStateData = image.dataBlock->state[newState];
if (isGhost() && nextStateData.ejectShell) {
ejectShellCasing( imageSlot );
ejectShellCasing(imageSlot);
}
// Shake camera on client.
if (isGhost() && nextStateData.fire && image.dataBlock->shakeCamera) {
shakeCamera( imageSlot );
shakeCamera(imageSlot);
}
// Server must animate the shape if it is a firestate...
@ -2626,12 +2646,12 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
if (!force && image.state == &image.dataBlock->state[newState]) {
image.delayTime = image.state->timeoutValue;
if (image.state->script && !isGhost())
scriptCallback(imageSlot,image.state->script);
scriptCallback(imageSlot, image.state->script);
// If this is a flash sequence, we need to select a new position for the
// animation if we're returning to that state...
F32 randomPos = Platform::getRandom();
for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
for (U32 i = 0; i < ShapeBaseImageData::MaxShapes; ++i)
{
if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
continue;
@ -2659,7 +2679,7 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
// Mount pending images
if (image.nextImage != InvalidImagePtr && stateData.allowImageChange) {
setImage(imageSlot,image.nextImage,image.nextSkinNameHandle,image.nextLoaded);
setImage(imageSlot, image.nextImage, image.nextSkinNameHandle, image.nextLoaded);
return;
}
@ -2667,16 +2687,16 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
// (the first key frame should be it's off state).
// We need to do this across all image shapes to make sure we have no hold overs when switching
// rendering shapes while in the middle of a state change.
for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
for (U32 i = 0; i < ShapeBaseImageData::MaxShapes; ++i)
{
// If we are to do a sequence transition then we need to keep the previous animThread active
if (image.animThread[i] && image.animThread[i]->getSequence()->isCyclic() && (stateData.sequenceNeverTransition || !(stateData.sequenceTransitionIn || lastState->sequenceTransitionOut))) {
image.shapeInstance[i]->setPos(image.animThread[i],0);
image.shapeInstance[i]->setTimeScale(image.animThread[i],0);
image.shapeInstance[i]->setPos(image.animThread[i], 0);
image.shapeInstance[i]->setTimeScale(image.animThread[i], 0);
}
if (image.flashThread[i]) {
image.shapeInstance[i]->setPos(image.flashThread[i],0);
image.shapeInstance[i]->setTimeScale(image.flashThread[i],0);
image.shapeInstance[i]->setPos(image.flashThread[i], 0);
image.shapeInstance[i]->setTimeScale(image.flashThread[i], 0);
}
}
@ -2689,10 +2709,10 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
if (image.delayTime <= 0 || !stateData.waitForTimeout)
{
if ((ns = stateData.transition.loaded[image.loaded]) != -1) {
setImageState(imageSlot,ns);
setImageState(imageSlot, ns);
return;
}
for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
for (U32 i = 0; i < ShapeBaseImageData::MaxGenericTriggers; ++i)
{
if ((ns = stateData.transition.genericTrigger[i][image.genericTrigger[i]]) != -1) {
setImageState(imageSlot, ns);
@ -2701,7 +2721,7 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
}
//if (!imageData.usesEnergy)
if ((ns = stateData.transition.ammo[image.ammo]) != -1) {
setImageState(imageSlot,ns);
setImageState(imageSlot, ns);
return;
}
if ((ns = stateData.transition.target[image.target]) != -1) {
@ -2717,11 +2737,11 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
return;
}
if ((ns = stateData.transition.trigger[image.triggerDown]) != -1) {
setImageState(imageSlot,ns);
setImageState(imageSlot, ns);
return;
}
if ((ns = stateData.transition.altTrigger[image.altTriggerDown]) != -1) {
setImageState(imageSlot,ns);
setImageState(imageSlot, ns);
return;
}
}
@ -2746,28 +2766,37 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
// Apply recoil
if (stateData.recoil != ShapeBaseImageData::StateData::NoRecoil)
onImageRecoil(imageSlot,stateData.recoil);
onImageRecoil(imageSlot, stateData.recoil);
// Apply image state animation on mounting shape
if (stateData.shapeSequence && stateData.shapeSequence[0])
{
onImageStateAnimation(imageSlot, stateData.shapeSequence, stateData.direction, stateData.shapeSequenceScale, stateData.timeoutValue);
}
// Delete any loooping sounds that were in the previous state.
if (lastState->sound && lastState->sound->getDescription()->mIsLooping)
// this is the crazy bit =/ needs to know prev state in order to stop sounds.
// lastState does not return an id for the prev state so we keep track of it.
if (lastState->sound && lastState->sound->getSfxProfile()->getDescription()->mIsLooping)
{
for(Vector<SFXSource*>::iterator i = image.mSoundSources.begin(); i != image.mSoundSources.end(); i++)
for (Vector<SFXSource*>::iterator i = image.mSoundSources.begin(); i != image.mSoundSources.end(); i++)
SFX_DELETE((*i));
image.mSoundSources.clear();
}
// Play sound
if( stateData.sound && isGhost() )
if (isGhost())
{
if (stateData.sound)
{
const Point3F& velocity = getVelocity();
image.addSoundSource(SFX->createSource( stateData.sound, &getRenderTransform(), &velocity ));
image.addSoundSource(SFX->createSource(stateData.sound->getSfxProfile(), &getRenderTransform(), &velocity));
}
if (stateData.soundTrack)
{
const Point3F& velocity = getVelocity();
image.addSoundSource(SFX->createSource(stateData.soundTrack, &getRenderTransform(), &velocity));
}
}
// Play animation

View file

@ -173,6 +173,13 @@ Trigger::Trigger()
mTripOnce = false;
mTrippedBy = 0xFFFFFFFF;
mTripCondition = "";
//Default up a basic square
Point3F vecs[3] = { Point3F(1.0, 0.0, 0.0),
Point3F(0.0, -1.0, 0.0),
Point3F(0.0, 0.0, 1.0) };
mTriggerPolyhedron = Polyhedron(Point3F(-0.5, 0.5, 0.0), vecs);
}
Trigger::~Trigger()
@ -731,7 +738,8 @@ void Trigger::potentialEnterObject(GameBase* enter)
if(evalCmD(&mEnterCommand))
{
String command = String("%obj = ") + enter->getIdString() + ";" + mEnterCommand;
String command = String("%obj = ") + enter->getIdString() + ";";
command = command + String("%this = ") + getIdString() + ";" + mEnterCommand;
Con::evaluate(command.c_str());
}
@ -779,7 +787,8 @@ void Trigger::processTick(const Move* move)
if (evalCmD(&mLeaveCommand))
{
String command = String("%obj = ") + remove->getIdString() + ";" + mLeaveCommand;
String command = String("%obj = ") + remove->getIdString() + ";";
command = command + String("%this = ") + getIdString() + ";" + mLeaveCommand;
Con::evaluate(command.c_str());
}
if (testTrippable() && testCondition())

View file

@ -54,6 +54,7 @@
#include "materials/materialFeatureTypes.h"
#include "console/engineAPI.h"
#include "T3D/accumulationVolume.h"
#include "math/mTransform.h"
#include "gui/editor/inspector/group.h"
#include "console/typeValidators.h"
@ -149,7 +150,7 @@ TSStatic::TSStatic()
mAnimOffset = 0.0f;
mAnimSpeed = 1.0f;
INIT_SHAPEASSET(Shape);
INIT_ASSET(Shape);
}
TSStatic::~TSStatic()
@ -418,6 +419,8 @@ bool TSStatic::_createShape()
// Reapply the current skin
mAppliedSkinName = "";
reSkin();
updateMaterials();
}
prepCollision();
@ -958,7 +961,7 @@ U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
if (stream->writeFlag(mask & AdvancedStaticOptionsMask))
{
PACK_SHAPEASSET(con, Shape);
PACK_ASSET(con, Shape);
stream->write((U32)mDecalType);
@ -1015,7 +1018,7 @@ U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
con->packNetStringHandleU(stream, matNameStr);
}
mChangingMaterials.clear();
//mChangingMaterials.clear();
}
return retMask;
@ -1073,7 +1076,7 @@ void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream)
if (stream->readFlag()) // AdvancedStaticOptionsMask
{
UNPACK_SHAPEASSET(con, Shape);
UNPACK_ASSET(con, Shape);
stream->read((U32*)&mDecalType);
@ -1085,15 +1088,16 @@ void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream)
stream->read(&mForceDetail);
if (stream->readFlag())
mAnimOffset = stream->readFloat(7);
if (stream->readFlag())
mAnimOffset = stream->readFloat(7);
if (stream->readFlag())
mAnimSpeed = stream->readSignedFloat(7) * AnimSpeedMax;
if (stream->readFlag())
mAnimSpeed = stream->readSignedFloat(7) * AnimSpeedMax;
mPlayAmbient = stream->readFlag();
//update our shape, figuring that it likely changed
_createShape();
}
mUseAlphaFade = stream->readFlag();
@ -1585,7 +1589,7 @@ U32 TSStatic::getNumDetails()
void TSStatic::updateMaterials()
{
if (mChangingMaterials.empty() || !mShape)
if (mChangingMaterials.empty() || !mShapeInstance)
return;
TSMaterialList* pMatList = mShapeInstance->getMaterialList();
@ -1617,8 +1621,6 @@ void TSStatic::updateMaterials()
}
}
mChangingMaterials.clear();
// Initialize the material instances
mShapeInstance->initMaterialList();
}
@ -1670,53 +1672,45 @@ void TSStatic::onInspect(GuiInspector* inspector)
{
StringTableEntry materialname = StringTable->insert(mShapeAsset->getShape()->materialList->getMaterialName(i).c_str());
//Iterate through our assetList to find the compliant entry in our matList
for (U32 m = 0; m < mShapeAsset->getMaterialCount(); m++)
AssetPtr<MaterialAsset> matAsset;
if(MaterialAsset::getAssetByMaterialName(materialname, &matAsset) == MaterialAsset::Ok)
{
AssetPtr<MaterialAsset> matAsset = mShapeAsset->getMaterialAsset(m);
dSprintf(matFieldName, 128, "MaterialSlot%d", i);
if (matAsset->getMaterialDefinitionName() == materialname)
GuiInspectorField* fieldGui = materialGroup->constructField(TypeMaterialAssetPtr);
fieldGui->init(inspector, materialGroup);
fieldGui->setSpecialEditField(true);
fieldGui->setTargetObject(this);
StringTableEntry fldnm = StringTable->insert(matFieldName);
fieldGui->setSpecialEditVariableName(fldnm);
fieldGui->setInspectorField(NULL, fldnm);
fieldGui->setDocs("");
if (fieldGui->registerObject())
{
dSprintf(matFieldName, 128, "MaterialSlot%d", i);
StringTableEntry fieldValue = matAsset->getAssetId();
//addComponentField(matFieldName, "A material used in the shape file", "Material", matAsset->getAssetId(), "");
//Con::executef(this, "onConstructComponentField", mTargetComponent, field->mFieldName);
Con::printf("Added material field for MaterialSlot %d", i);
GuiInspectorField* fieldGui = materialGroup->constructField(TypeMaterialAssetPtr);
fieldGui->init(inspector, materialGroup);
fieldGui->setSpecialEditField(true);
fieldGui->setTargetObject(this);
StringTableEntry fldnm = StringTable->insert(matFieldName);
fieldGui->setSpecialEditVariableName(fldnm);
fieldGui->setInspectorField(NULL, fldnm);
fieldGui->setDocs("");
if (fieldGui->registerObject())
//Check if we'd already actually changed it, and display the modified value
for (U32 c = 0; c < mChangingMaterials.size(); c++)
{
fieldGui->setValue(materialname);
stack->addObject(fieldGui);
}
else
{
SAFE_DELETE(fieldGui);
if (mChangingMaterials[c].slot == i)
{
fieldValue = StringTable->insert(mChangingMaterials[i].assetId.c_str());
break;
}
}
/*if (materialGroup->isMethod("onConstructField"))
{
//ensure our stack variable is bound if we need it
//Con::evaluatef("%d.stack = %d;", materialGroup->getId(), materialGroup->at(0)->getId());
fieldGui->setValue(fieldValue);
Con::executef(materialGroup, "onConstructField", matFieldName,
matFieldName, "material", matFieldName,
materialname, "", "", this);
}*/
break;
stack->addObject(fieldGui);
}
else
{
SAFE_DELETE(fieldGui);
}
}
}
@ -1871,3 +1865,31 @@ void TSStatic::setSelectionFlags(U8 flags)
}
}
void TSStatic::getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat)
{
S32 nodeIDx = getShapeResource()->findNode(nodeName);
MatrixF mountTransform = mShapeInstance->mNodeTransforms[nodeIDx];
mountTransform.mul(xfm);
const Point3F &scale = getScale();
// The position of the mount point needs to be scaled.
Point3F position = mountTransform.getPosition();
position.convolve(scale);
mountTransform.setPosition(position);
// Also we would like the object to be scaled to the model.
outMat->mul(mObjToWorld, mountTransform);
return;
}
DefineEngineMethod(TSStatic, getNodeTransform, TransformF, (const char *nodeName), ,
"@brief Get the world transform of the specified mount slot.\n\n"
"@param slot Image slot to query\n"
"@return the mount transform\n\n")
{
MatrixF xf(true);
object->getNodeTransform(nodeName, MatrixF::Identity, &xf);
return xf;
}

View file

@ -192,7 +192,7 @@ protected:
Convex* mConvexList;
DECLARE_SHAPEASSET(TSStatic, Shape, onShapeChanged);
DECLARE_SHAPEASSET_NET_SETGET(TSStatic, Shape, AdvancedStaticOptionsMask);
DECLARE_ASSET_NET_SETGET(TSStatic, Shape, AdvancedStaticOptionsMask);
U32 mShapeHash;
Vector<S32> mCollisionDetails;
@ -276,6 +276,7 @@ public:
void updateMaterials();
bool isAnimated() { return mPlayAmbient; }
void getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat);
virtual void getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList);

View file

@ -257,7 +257,7 @@ ConsoleDocClass( TurretShape,
TurretShape::TurretShape()
{
mTypeMask |= VehicleObjectType | DynamicShapeObjectType;
mTypeMask |= VehicleObjectType | DynamicShapeObjectType | TurretObjectType;
mDataBlock = 0;
allowManualRotation = true;

View file

@ -116,7 +116,7 @@ FlyingVehicleData::FlyingVehicleData()
jetEmitter[j] = 0;
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = 0;
INIT_ASSET_ARRAY(FlyingSounds, i);
vertThrustMultiple = 1.0;
}
@ -131,9 +131,12 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
// Resolve objects transmitted from server
if (!server) {
for (S32 i = 0; i < MaxSounds; i++)
if (sound[i])
Sim::findObject(SimObjectId((uintptr_t)sound[i]),sound[i]);
{
if (mFlyingSounds[i])
{
_setFlyingSounds(getFlyingSounds(i), i);
}
}
for (S32 j = 0; j < MaxJetEmitters; j++)
if (jetEmitter[j])
Sim::findObject(SimObjectId((uintptr_t)jetEmitter[j]),jetEmitter[j]);
@ -163,10 +166,8 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
void FlyingVehicleData::initPersistFields()
{
addField( "jetSound", TYPEID< SFXProfile >(), Offset(sound[JetSound], FlyingVehicleData),
"Looping sound to play while the vehicle is jetting." );
addField( "engineSound", TYPEID< SFXProfile >(), Offset(sound[EngineSound], FlyingVehicleData),
"Looping engine sound." );
INITPERSISTFIELD_SOUNDASSET_ARRAY(FlyingSounds, Sounds::MaxSounds, FlyingVehicleData, "Sounds for flying vehicle");
addField( "maneuveringForce", TypeF32, Offset(maneuveringForce, FlyingVehicleData),
"@brief Maximum X and Y (horizontal plane) maneuvering force.\n\n"
@ -240,11 +241,7 @@ void FlyingVehicleData::packData(BitStream* stream)
for (S32 i = 0; i < MaxSounds; i++)
{
if (stream->writeFlag(sound[i]))
{
SimObjectId writtenId = mPacked ? SimObjectId((uintptr_t)sound[i]) : sound[i]->getId();
stream->writeRangedU32(writtenId, DataBlockObjectIdFirst, DataBlockObjectIdLast);
}
PACKDATA_ASSET_ARRAY(FlyingSounds, i);
}
for (S32 j = 0; j < MaxJetEmitters; j++)
@ -277,11 +274,9 @@ void FlyingVehicleData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
for (S32 i = 0; i < MaxSounds; i++) {
sound[i] = NULL;
if (stream->readFlag())
sound[i] = (SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
for (S32 i = 0; i < MaxSounds; i++)
{
UNPACKDATA_ASSET_ARRAY(FlyingSounds, i);
}
for (S32 j = 0; j < MaxJetEmitters; j++) {
@ -353,9 +348,6 @@ bool FlyingVehicle::onAdd()
return false;
addToScene();
if (isServerObject())
scriptOnAdd();
return true;
}
@ -374,11 +366,11 @@ bool FlyingVehicle::onNewDataBlock(GameBaseData* dptr, bool reload)
SFX_DELETE( mJetSound );
SFX_DELETE( mEngineSound );
if ( mDataBlock->sound[FlyingVehicleData::EngineSound] )
mEngineSound = SFX->createSource( mDataBlock->sound[FlyingVehicleData::EngineSound], &getTransform() );
if ( mDataBlock->getFlyingSounds(FlyingVehicleData::EngineSound) )
mEngineSound = SFX->createSource( mDataBlock->getFlyingSoundsProfile(FlyingVehicleData::EngineSound), &getTransform() );
if ( mDataBlock->sound[FlyingVehicleData::JetSound] )
mJetSound = SFX->createSource( mDataBlock->sound[FlyingVehicleData::JetSound], &getTransform() );
if ( mDataBlock->getFlyingSounds(FlyingVehicleData::JetSound))
mJetSound = SFX->createSource( mDataBlock->getFlyingSoundsProfile(FlyingVehicleData::JetSound), &getTransform() );
}
// Jet Sequences
@ -405,7 +397,6 @@ void FlyingVehicle::onRemove()
SFX_DELETE( mJetSound );
SFX_DELETE( mEngineSound );
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}

View file

@ -45,7 +45,8 @@ struct FlyingVehicleData: public VehicleData {
EngineSound,
MaxSounds,
};
SFXProfile* sound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(FlyingVehicleData, FlyingSounds, Sounds::MaxSounds);
DECLARE_ASSET_ARRAY_SETGET(FlyingVehicleData, FlyingSounds);
enum Jets {
// These enums index into a static name list.

View file

@ -68,6 +68,16 @@ ConsoleDocClass( HoverVehicle,
"@ingroup Vehicles\n"
);
typedef HoverVehicleData::Sounds hoverSoundsEnum;
DefineEnumType(hoverSoundsEnum);
ImplementEnumType(hoverSoundsEnum, "enum types.\n"
"@ingroup HoverVehicleData\n\n")
{ HoverVehicleData::JetSound, "JetSound", "..." },
{ HoverVehicleData::EngineSound, "EngineSound", "..." },
{ HoverVehicleData::FloatSound, "FloatSound", "..." },
EndImplementEnumType;
namespace {
const U32 sCollisionMoveMask = (TerrainObjectType | PlayerObjectType |
@ -152,7 +162,7 @@ HoverVehicleData::HoverVehicleData()
jetEmitter[j] = 0;
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = 0;
INIT_ASSET_ARRAY(HoverSounds, i);
}
HoverVehicleData::~HoverVehicleData()
@ -232,14 +242,8 @@ void HoverVehicleData::initPersistFields()
addField( "pitchForce", TypeF32, Offset(pitchForce, HoverVehicleData),
"Pitch (rotation about the X-axis) force applied when steering in the y-axis direction." );
addField( "jetSound", TYPEID< SFXProfile >(), Offset(sound[JetSound], HoverVehicleData),
"Looping sound played when the vehicle is jetting." );
addField( "engineSound", TYPEID< SFXProfile >(), Offset(sound[EngineSound], HoverVehicleData),
"Looping engine sound.\nThe volume is dynamically adjusted based on the "
"current thrust level." );
addField( "floatSound", TYPEID< SFXProfile >(), Offset(sound[FloatSound], HoverVehicleData),
"Looping sound played while the vehicle is floating.\n\n@see stabMinLen" );
INITPERSISTFIELD_SOUNDASSET_ENUMED(HoverSounds, hoverSoundsEnum, Sounds::MaxSounds, HoverVehicleData, "Sounds for hover vehicle.");
addField( "dustTrailEmitter", TYPEID< ParticleEmitterData >(), Offset(dustTrailEmitter, HoverVehicleData),
"Emitter to generate particles for the vehicle's dust trail.\nThe trail "
"of dust particles is generated only while the vehicle is moving." );
@ -311,9 +315,13 @@ bool HoverVehicleData::preload(bool server, String &errorStr)
// Resolve objects transmitted from server
if (!server) {
for (S32 i = 0; i < MaxSounds; i++)
if (sound[i])
Sim::findObject(SimObjectId((uintptr_t)sound[i]),sound[i]);
if (getHoverSounds(i) != StringTable->EmptyString())
{
_setHoverSounds(getHoverSounds(i), i);
}
for (S32 j = 0; j < MaxJetEmitters; j++)
if (jetEmitter[j])
Sim::findObject(SimObjectId((uintptr_t)jetEmitter[j]),jetEmitter[j]);
@ -361,9 +369,9 @@ void HoverVehicleData::packData(BitStream* stream)
stream->write(dustTrailFreqMod);
for (S32 i = 0; i < MaxSounds; i++)
if (stream->writeFlag(sound[i]))
stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)sound[i]):
sound[i]->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
{
PACKDATA_ASSET_ARRAY(HoverSounds, i);
}
for (S32 j = 0; j < MaxJetEmitters; j++)
{
@ -410,9 +418,9 @@ void HoverVehicleData::unpackData(BitStream* stream)
stream->read(&dustTrailFreqMod);
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = stream->readFlag()?
(SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast): 0;
{
UNPACKDATA_ASSET_ARRAY(HoverSounds, i);
}
for (S32 j = 0; j < MaxJetEmitters; j++) {
jetEmitter[j] = NULL;
@ -504,10 +512,6 @@ bool HoverVehicle::onAdd()
}
}
if (isServerObject())
scriptOnAdd();
return true;
}
@ -518,7 +522,6 @@ void HoverVehicle::onRemove()
SFX_DELETE( mEngineSound );
SFX_DELETE( mFloatSound );
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
@ -539,14 +542,14 @@ bool HoverVehicle::onNewDataBlock(GameBaseData* dptr, bool reload)
SFX_DELETE( mFloatSound );
SFX_DELETE( mJetSound );
if ( mDataBlock->sound[HoverVehicleData::EngineSound] )
mEngineSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::EngineSound], &getTransform() );
if ( mDataBlock->getHoverSounds(HoverVehicleData::EngineSound) )
mEngineSound = SFX->createSource( mDataBlock->getHoverSoundsProfile(HoverVehicleData::EngineSound), &getTransform() );
if ( !mDataBlock->sound[HoverVehicleData::FloatSound] )
mFloatSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::FloatSound], &getTransform() );
if ( !mDataBlock->getHoverSounds(HoverVehicleData::FloatSound) )
mFloatSound = SFX->createSource( mDataBlock->getHoverSoundsProfile(HoverVehicleData::FloatSound), &getTransform() );
if ( mDataBlock->sound[HoverVehicleData::JetSound] )
mJetSound = SFX->createSource( mDataBlock->sound[HoverVehicleData::JetSound], &getTransform() );
if ( mDataBlock->getHoverSounds(HoverVehicleData::JetSound) )
mJetSound = SFX->createSource( mDataBlock->getHoverSoundsProfile(HoverVehicleData::JetSound), &getTransform() );
}
// Todo: Uncomment if this is a "leaf" class

View file

@ -46,7 +46,7 @@ class HoverVehicleData : public VehicleData
FloatSound,
MaxSounds
};
SFXProfile* sound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(HoverVehicleData, HoverSounds, Sounds::MaxSounds);
enum Jets {
// These enums index into a static name list.

View file

@ -80,6 +80,28 @@ static U32 sTriggerMask = ItemObjectType |
IMPLEMENT_CONOBJECT(VehicleData);
typedef VehicleData::Body::Sounds bodySounds;
DefineEnumType(bodySounds);
ImplementEnumType(bodySounds, "enum types.\n"
"@ingroup VehicleData\n\n")
{ VehicleData::Body::SoftImpactSound, "SoftImpactSound", "..." },
{ VehicleData::Body::HardImpactSound, "HardImpactSound", "..." },
EndImplementEnumType;
typedef VehicleData::Sounds vehSoundsEnum;
DefineEnumType(vehSoundsEnum);
ImplementEnumType(vehSoundsEnum, "enum types.\n"
"@ingroup VehicleData\n\n")
{ VehicleData::ExitWater, "ExitWater", "..." },
{ VehicleData::ImpactSoft, "ImpactSoft", "..." },
{ VehicleData::ImpactMedium, "ImpactMedium", "..." },
{ VehicleData::ImpactHard, "ImpactHard", "..." },
{ VehicleData::Wake, "Wake", "..." },
EndImplementEnumType;
ConsoleDocClass( VehicleData,
"@brief Base properties shared by all Vehicles (FlyingVehicle, HoverVehicle, "
"WheeledVehicle).\n\n"
@ -166,7 +188,9 @@ VehicleData::VehicleData()
powerSteering = false;
for (S32 i = 0; i < Body::MaxSounds; i++)
body.sound[i] = 0;
{
INIT_ASSET_ARRAY(VehicleBodySounds, i);
}
dustEmitter = NULL;
dustID = 0;
@ -189,7 +213,8 @@ VehicleData::VehicleData()
medSplashSoundVel = 2.0;
hardSplashSoundVel = 3.0;
dMemset(waterSound, 0, sizeof(waterSound));
for (S32 i = 0; i < Sounds::MaxSounds; i++)
INIT_ASSET_ARRAY(VehicleWaterSounds, i);
collDamageThresholdVel = 20;
collDamageMultiplier = 0.05f;
@ -215,8 +240,20 @@ bool VehicleData::preload(bool server, String &errorStr)
// Resolve objects transmitted from server
if (!server) {
for (S32 i = 0; i < Body::MaxSounds; i++)
if (body.sound[i])
Sim::findObject(SimObjectId((uintptr_t)body.sound[i]),body.sound[i]);
{
if (getVehicleBodySounds(i) != StringTable->EmptyString() )
{
_setVehicleBodySounds(getVehicleBodySounds(i), i);
}
}
for (S32 j = 0; j < Sounds::MaxSounds; j++)
{
if (getVehicleWaterSounds(j) != StringTable->EmptyString())
{
_setVehicleWaterSounds(getVehicleWaterSounds(j), j);
}
}
}
if( !dustEmitter && dustID != 0 )
@ -264,10 +301,9 @@ void VehicleData::packData(BitStream* stream)
stream->write(body.restitution);
stream->write(body.friction);
for (i = 0; i < Body::MaxSounds; i++)
if (stream->writeFlag(body.sound[i]))
stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)body.sound[i]):
body.sound[i]->getId(),DataBlockObjectIdFirst,
DataBlockObjectIdLast);
{
PACKDATA_ASSET_ARRAY(VehicleBodySounds, i);
}
stream->write(minImpactSpeed);
stream->write(softImpactSpeed);
@ -308,9 +344,10 @@ void VehicleData::packData(BitStream* stream)
stream->write(enablePhysicsRep);
// write the water sound profiles
for(i = 0; i < MaxSounds; i++)
if(stream->writeFlag(waterSound[i]))
stream->writeRangedU32(waterSound[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
for (i = 0; i < MaxSounds; i++)
{
PACKDATA_ASSET_ARRAY(VehicleWaterSounds, i);
}
if (stream->writeFlag( dustEmitter ))
{
@ -359,11 +396,9 @@ void VehicleData::unpackData(BitStream* stream)
stream->read(&body.restitution);
stream->read(&body.friction);
S32 i;
for (i = 0; i < Body::MaxSounds; i++) {
body.sound[i] = NULL;
if (stream->readFlag())
body.sound[i] = (SFXProfile*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
DataBlockObjectIdLast);
for (i = 0; i < Body::MaxSounds; i++)
{
UNPACKDATA_ASSET_ARRAY(VehicleBodySounds, i);
}
stream->read(&minImpactSpeed);
@ -405,12 +440,10 @@ void VehicleData::unpackData(BitStream* stream)
stream->read(&enablePhysicsRep);
// write the water sound profiles
for(i = 0; i < MaxSounds; i++)
if(stream->readFlag())
{
U32 id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
waterSound[i] = dynamic_cast<SFXProfile*>( Sim::findObject(id) );
}
for (i = 0; i < Sounds::MaxSounds; i++)
{
UNPACKDATA_ASSET_ARRAY(VehicleWaterSounds, i);
}
if( stream->readFlag() )
{
@ -491,15 +524,8 @@ void VehicleData::initPersistFields()
addField( "bodyFriction", TypeF32, Offset(body.friction, VehicleData),
"Collision friction coefficient.\nHow well this object will slide against "
"objects it collides with." );
addField( "softImpactSound", TYPEID< SFXProfile >(), Offset(body.sound[Body::SoftImpactSound], VehicleData),
"@brief Sound to play on a 'soft' impact.\n\n"
"This sound is played if the impact speed is < hardImpactSpeed and >= "
"softImpactSpeed.\n\n"
"@see softImpactSpeed" );
addField( "hardImpactSound", TYPEID< SFXProfile >(), Offset(body.sound[Body::HardImpactSound], VehicleData),
"@brief Sound to play on a 'hard' impact.\n\n"
"This sound is played if the impact speed >= hardImpactSpeed.\n\n"
"@see hardImpactSpeed" );
INITPERSISTFIELD_SOUNDASSET_ENUMED(VehicleBodySounds, bodySounds, Body::Sounds::MaxSounds, VehicleData, "Sounds for vehicle body impacts.");
addField( "minImpactSpeed", TypeF32, Offset(minImpactSpeed, VehicleData),
"Minimum collision speed for the onImpact callback to be invoked." );
@ -596,18 +622,8 @@ void VehicleData::initPersistFields()
addField( "hardSplashSoundVelocity", TypeF32, Offset(hardSplashSoundVel, VehicleData),
"Minimum velocity when entering the water for the imapactWaterHard sound "
"to play.\n\n@see impactWaterHard" );
addField( "exitingWater", TYPEID< SFXProfile >(), Offset(waterSound[ExitWater], VehicleData),
"Sound to play when exiting the water." );
addField( "impactWaterEasy", TYPEID< SFXProfile >(), Offset(waterSound[ImpactSoft], VehicleData),
"Sound to play when entering the water with speed >= softSplashSoundVelocity "
"and < mediumSplashSoundVelocity." );
addField( "impactWaterMedium", TYPEID< SFXProfile >(), Offset(waterSound[ImpactMedium], VehicleData),
"Sound to play when entering the water with speed >= mediumSplashSoundVelocity "
"and < hardSplashSoundVelocity." );
addField( "impactWaterHard", TYPEID< SFXProfile >(), Offset(waterSound[ImpactHard], VehicleData),
"Sound to play when entering the water with speed >= hardSplashSoundVelocity." );
addField( "waterWakeSound", TYPEID< SFXProfile >(), Offset(waterSound[Wake], VehicleData),
"Looping sound to play while moving through the water." );
INITPERSISTFIELD_SOUNDASSET_ENUMED(WaterSounds, vehSoundsEnum, VehicleData::Sounds::MaxSounds, VehicleData, "Sounds for interacting with water.");
addField( "collDamageThresholdVel", TypeF32, Offset(collDamageThresholdVel, VehicleData),
"Minimum collision velocity to cause damage to this vehicle.\nCurrently unused." );
@ -876,8 +892,8 @@ bool Vehicle::onNewDataBlock(GameBaseData* dptr,bool reload)
// costs and makes the system easier to understand.
SFX_DELETE( mWakeSound );
if ( mDataBlock->waterSound[VehicleData::Wake] )
mWakeSound = SFX->createSource( mDataBlock->waterSound[VehicleData::Wake], &getTransform() );
if ( mDataBlock->getVehicleWaterSounds(VehicleData::Wake) != NULL )
mWakeSound = SFX->createSource( mDataBlock->getVehicleWaterSoundsProfile(VehicleData::Wake), &getTransform() );
}
return true;
@ -1140,27 +1156,27 @@ void Vehicle::updatePos(F32 dt)
if (collSpeed >= mDataBlock->softImpactSpeed)
impactSound = VehicleData::Body::SoftImpactSound;
if (impactSound != -1 && mDataBlock->body.sound[impactSound] != NULL)
SFX->playOnce( mDataBlock->body.sound[impactSound], &getTransform() );
if (impactSound != -1 && mDataBlock->getVehicleBodySoundsProfile(impactSound) != NULL)
SFX->playOnce( mDataBlock->getVehicleBodySoundsProfile(impactSound), &getTransform() );
}
// Water volume sounds
F32 vSpeed = getVelocity().len();
if (!inLiquid && mWaterCoverage >= 0.8f) {
if (vSpeed >= mDataBlock->hardSplashSoundVel)
SFX->playOnce( mDataBlock->waterSound[VehicleData::ImpactHard], &getTransform() );
SFX->playOnce( mDataBlock->getVehicleWaterSoundsProfile(VehicleData::ImpactHard), &getTransform() );
else
if (vSpeed >= mDataBlock->medSplashSoundVel)
SFX->playOnce( mDataBlock->waterSound[VehicleData::ImpactMedium], &getTransform() );
SFX->playOnce( mDataBlock->getVehicleWaterSoundsProfile(VehicleData::ImpactMedium), &getTransform() );
else
if (vSpeed >= mDataBlock->softSplashSoundVel)
SFX->playOnce( mDataBlock->waterSound[VehicleData::ImpactSoft], &getTransform() );
SFX->playOnce( mDataBlock->getVehicleWaterSoundsProfile(VehicleData::ImpactSoft), &getTransform() );
inLiquid = true;
}
else
if(inLiquid && mWaterCoverage < 0.8f) {
if (vSpeed >= mDataBlock->exitSplashSoundVel)
SFX->playOnce( mDataBlock->waterSound[VehicleData::ExitWater], &getTransform() );
SFX->playOnce( mDataBlock->getVehicleWaterSoundsProfile(VehicleData::ExitWater), &getTransform() );
inLiquid = false;
}
}

View file

@ -45,11 +45,12 @@ struct VehicleData : public RigidShapeData
HardImpactSound,
MaxSounds,
};
SFXProfile* sound[MaxSounds];
F32 restitution;
F32 friction;
} body;
DECLARE_SOUNDASSET_ARRAY(VehicleData, VehicleBodySounds, Body::Sounds::MaxSounds)
enum VehicleConsts
{
VC_NUM_DUST_EMITTERS = 1,
@ -69,7 +70,9 @@ struct VehicleData : public RigidShapeData
Wake,
MaxSounds
};
SFXProfile* waterSound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(VehicleData, VehicleWaterSounds, Sounds::MaxSounds)
F32 exitSplashSoundVel;
F32 softSplashSoundVel;
F32 medSplashSoundVel;

View file

@ -75,7 +75,7 @@ ConsoleDocClass( WheeledVehicleTire,
WheeledVehicleTire::WheeledVehicleTire()
{
INIT_SHAPEASSET(Shape);
INIT_ASSET(Shape);
staticFriction = 1;
kineticFriction = 0.5f;
@ -177,7 +177,7 @@ void WheeledVehicleTire::packData(BitStream* stream)
{
Parent::packData(stream);
PACKDATA_SHAPEASSET(Shape);
PACKDATA_ASSET(Shape);
stream->write(mass);
stream->write(staticFriction);
@ -196,7 +196,7 @@ void WheeledVehicleTire::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
UNPACKDATA_SHAPEASSET(Shape);
UNPACKDATA_ASSET(Shape);
stream->read(&mass);
stream->read(&staticFriction);
@ -289,6 +289,17 @@ ConsoleDocClass( WheeledVehicleData,
"@ingroup Vehicles\n"
);
typedef WheeledVehicleData::Sounds wheelSoundsEnum;
DefineEnumType(wheelSoundsEnum);
ImplementEnumType(wheelSoundsEnum, "enum types.\n"
"@ingroup WheeledVehicleData\n\n")
{WheeledVehicleData::JetSound, "JetSound", "..." },
{WheeledVehicleData::EngineSound, "EngineSound", "..." },
{WheeledVehicleData::SquealSound, "SquealSound", "..." },
{WheeledVehicleData::WheelImpactSound, "WheelImpactSound", "..." },
EndImplementEnumType;
WheeledVehicleData::WheeledVehicleData()
{
tireEmitter = 0;
@ -301,7 +312,7 @@ WheeledVehicleData::WheeledVehicleData()
wheelCount = 0;
dMemset(&wheel, 0, sizeof(wheel));
for (S32 i = 0; i < MaxSounds; i++)
sound[i] = 0;
INIT_ASSET_ARRAY(WheeledVehicleSounds, i);
}
@ -335,10 +346,9 @@ bool WheeledVehicleData::preload(bool server, String &errorStr)
if (!server) {
for (S32 i = 0; i < MaxSounds; i++)
{
if (!sfxResolve(&sound[i], errorStr))
if (getWheeledVehicleSounds(i) != StringTable->EmptyString())
{
delete si;
return false;
_setWheeledVehicleSounds(getWheeledVehicleSounds(i), i);
}
}
@ -438,16 +448,7 @@ bool WheeledVehicleData::mirrorWheel(Wheel* we)
void WheeledVehicleData::initPersistFields()
{
addField( "jetSound", TYPEID< SFXTrack >(), Offset(sound[JetSound], WheeledVehicleData),
"Looping sound played when the vehicle is jetting." );
addField( "engineSound", TYPEID< SFXTrack >(), Offset(sound[EngineSound], WheeledVehicleData),
"@brief Looping engine sound.\n\n"
"The pitch is dynamically adjusted based on the current engine RPM" );
addField("squealSound", TYPEID< SFXTrack >(), Offset(sound[SquealSound], WheeledVehicleData),
"@brief Looping sound played while any of the wheels is slipping.\n\n"
"The volume is dynamically adjusted based on how much the wheels are slipping." );
addField("WheelImpactSound", TYPEID< SFXTrack >(), Offset(sound[WheelImpactSound], WheeledVehicleData),
"Sound played when the wheels impact the ground.\nCurrently unused." );
INITPERSISTFIELD_SOUNDASSET_ENUMED(WheeledVehicleSounds, wheelSoundsEnum, MaxSounds, WheeledVehicleData, "Sounds related to wheeled vehicle.");
addField("tireEmitter",TYPEID< ParticleEmitterData >(), Offset(tireEmitter, WheeledVehicleData),
"ParticleEmitterData datablock used to generate particles from each wheel "
@ -481,7 +482,9 @@ void WheeledVehicleData::packData(BitStream* stream)
tireEmitter->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
for (S32 i = 0; i < MaxSounds; i++)
sfxWrite( stream, sound[ i ] );
{
PACKDATA_ASSET_ARRAY(WheeledVehicleSounds, i);
}
stream->write(maxWheelSpeed);
stream->write(engineTorque);
@ -498,7 +501,9 @@ void WheeledVehicleData::unpackData(BitStream* stream)
DataBlockObjectIdLast): 0;
for (S32 i = 0; i < MaxSounds; i++)
sfxRead( stream, &sound[ i ] );
{
UNPACKDATA_ASSET_ARRAY(WheeledVehicleSounds, i);
}
stream->read(&maxWheelSpeed);
stream->read(&engineTorque);
@ -560,8 +565,6 @@ bool WheeledVehicle::onAdd()
return false;
addToScene();
if (isServerObject())
scriptOnAdd();
return true;
}
@ -583,7 +586,6 @@ void WheeledVehicle::onRemove()
SFX_DELETE( mSquealSound );
//
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
@ -683,14 +685,14 @@ bool WheeledVehicle::onNewDataBlock(GameBaseData* dptr, bool reload)
SFX_DELETE( mSquealSound );
SFX_DELETE( mJetSound );
if ( mDataBlock->sound[WheeledVehicleData::EngineSound] )
mEngineSound = SFX->createSource( mDataBlock->sound[WheeledVehicleData::EngineSound], &getTransform() );
if ( mDataBlock->getWheeledVehicleSounds(WheeledVehicleData::EngineSound) )
mEngineSound = SFX->createSource( mDataBlock->getWheeledVehicleSoundsProfile(WheeledVehicleData::EngineSound), &getTransform() );
if ( mDataBlock->sound[WheeledVehicleData::SquealSound] )
mSquealSound = SFX->createSource( mDataBlock->sound[WheeledVehicleData::SquealSound], &getTransform() );
if ( mDataBlock->getWheeledVehicleSounds(WheeledVehicleData::SquealSound) )
mSquealSound = SFX->createSource( mDataBlock->getWheeledVehicleSoundsProfile(WheeledVehicleData::SquealSound), &getTransform() );
if ( mDataBlock->sound[WheeledVehicleData::JetSound] )
mJetSound = SFX->createSource( mDataBlock->sound[WheeledVehicleData::JetSound], &getTransform() );
if ( mDataBlock->getWheeledVehicleSounds(WheeledVehicleData::JetSound) )
mJetSound = SFX->createSource( mDataBlock->getWheeledVehicleSoundsProfile(WheeledVehicleData::JetSound), &getTransform() );
}
scriptOnNewDataBlock();

View file

@ -44,7 +44,7 @@ struct WheeledVehicleTire: public SimDataBlock
typedef SimDataBlock Parent;
DECLARE_SHAPEASSET(WheeledVehicleTire, Shape, onShapeChanged);
DECLARE_SHAPEASSET_SETGET(WheeledVehicleTire, Shape);
DECLARE_ASSET_SETGET(WheeledVehicleTire, Shape);
// Physical properties
F32 mass; // Mass of the whole wheel
@ -118,7 +118,8 @@ struct WheeledVehicleData: public VehicleData
WheelImpactSound,
MaxSounds,
};
SFXTrack* sound[MaxSounds];
DECLARE_SOUNDASSET_ARRAY(WheeledVehicleData, WheeledVehicleSounds, Sounds::MaxSounds);
ParticleEmitterData* tireEmitter;

Some files were not shown because too many files have changed in this diff Show more