Merge branch 'Preview4_0' into feature-vfs-security

This commit is contained in:
Robert MacGregor 2022-06-13 08:05:26 -04:00
commit 161ffc62fe
3013 changed files with 348715 additions and 182470 deletions

View file

@ -102,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");
}
//------------------------------------------------------------------------------
@ -115,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)
@ -226,6 +226,13 @@ DefineEngineMethod(GUIAsset, getScriptPath, const char*, (), ,
{
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
//-----------------------------------------------------------------------------

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

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

@ -154,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.");
}
@ -173,7 +174,11 @@ void MaterialAsset::initializeAsset()
return;
}
if (Torque::FS::IsScriptFile(mScriptPath))
if (size() != 0 && mScriptPath == StringTable->EmptyString())
{
mLoadedState = EmbeddedDefinition;
}
else if (Torque::FS::IsScriptFile(mScriptPath))
{
if (!Sim::findObject(mMatDefinitionName))
{
@ -230,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.
@ -245,9 +249,28 @@ void MaterialAsset::setScriptFile(const char* pScriptFile)
void MaterialAsset::loadMaterial()
{
if (mMaterialDefinition)
SAFE_DELETE(mMaterialDefinition);
{
mMaterialDefinition->safeDeleteObject();
}
if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && 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))
@ -260,7 +283,7 @@ void MaterialAsset::loadMaterial()
mMaterialDefinition = matDef;
mLoadedState = Ok;
mMaterialDefinition->setInternalName(getAssetId());
mMaterialDefinition->reload();
return;
}
@ -296,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;
@ -388,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"
@ -396,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();
}

View file

@ -48,7 +48,9 @@
#include "sim/netConnection.h"
#endif
#ifndef _GUI_INSPECTOR_TYPES_H_
#include "gui/editor/guiInspectorTypes.h"
#endif
#include "materials/matTextureTarget.h"
#include "materials/materialDefinition.h"
@ -75,6 +77,7 @@ public:
{
ScriptLoaded = AssetErrCode::Extended,
DefinitionAlreadyExists,
EmbeddedDefinition,
Extended
};
@ -108,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.

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

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

@ -51,6 +51,9 @@
#endif
#include "util/imposterCapture.h"
#include "ts/tsShapeInstance.h"
#include "gfx/bitmap/imageUtils.h"
StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL;
//-----------------------------------------------------------------------------
@ -470,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;
}
@ -560,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
@ -604,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")
{
@ -625,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), (""),

View file

@ -191,7 +191,7 @@ public:
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:

View file

@ -218,6 +218,9 @@ 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
@ -225,6 +228,9 @@ bool SoundAsset::loadSound()
mSFXProfile.setDescription(&mProfileDesc);
mSFXProfile.setSoundFileName(mSoundPath);
mSFXProfile.setPreload(mPreload);
//give it a nudge to preload if required
mSFXProfile.getBuffer();
}
}
@ -257,7 +263,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
if (fileName == StringTable->EmptyString())
return StringTable->EmptyString();
StringTableEntry materialAssetId = "";
StringTableEntry soundAssetId = StringTable->EmptyString();
AssetQuery query;
U32 foundCount = AssetDatabase.findAssetType(&query, "SoundAsset");
@ -268,7 +274,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
SoundAsset* soundAsset = AssetDatabase.acquireAsset<SoundAsset>(query.mAssetList[i]);
if (soundAsset && soundAsset->getSoundPath() == fileName)
{
materialAssetId = soundAsset->getAssetId();
soundAssetId = soundAsset->getAssetId();
AssetDatabase.releaseAsset(query.mAssetList[i]);
break;
}
@ -276,7 +282,7 @@ StringTableEntry SoundAsset::getAssetIdByFileName(StringTableEntry fileName)
}
}
return materialAssetId;
return soundAssetId;
}
U32 SoundAsset::getAssetById(StringTableEntry assetId, AssetPtr<SoundAsset>* soundAsset)
@ -330,15 +336,18 @@ DefineEngineMethod(SoundAsset, getSoundPath, const char*, (), , "")
}
DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zero),
"Gets the number of materials for this shape asset.\n"
"@return Material count.\n")
"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();
if(source)
return source->getId();
else
return 0;
}
else
return 0;

View file

@ -40,6 +40,9 @@
#endif
#include "gui/editor/guiInspectorTypes.h"
#ifndef _ASSET_PTR_H_
#include "assets/assetPtr.h"
#endif
#ifndef _BITSTREAM_H_
#include "core/stream/bitStream.h"
@ -57,6 +60,10 @@
#include "sfx/sfxProfile.h"
#endif // !_SFXPROFILE_H_
#ifndef _RESOURCEMANAGER_H_
#include "core/resourceManager.h"
#endif
#include "assetMacroHelpers.h"
class SFXResource;
@ -178,6 +185,8 @@ public:
StringTableEntry m##name##AssetId;\
AssetPtr<SoundAsset> m##name##Asset = NULL;\
SFXProfile* m##name##Profile = NULL;\
SFXDescription* m##name##Desc = NULL;\
SimObjectId m##name##SFXId = NULL;\
public: \
const StringTableEntry get##name##File() const { return m##name##Name; }\
void set##name##File(const FileName &_in) { m##name##Name = StringTable->insert(_in.c_str());}\
@ -245,7 +254,7 @@ public: \
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 && (m##name##Name != StringTable->EmptyString() && !Sim::findObject(m##name##Name)))\
{\
Con::errorf("%s(%s)::_set%s() - Couldn't load sound \"%s\"", macroText(className), getName(), macroText(name), _in);\
return false;\
@ -271,7 +280,15 @@ public: \
SFXProfile* get##name##Profile()\
{\
if (get##name() != StringTable->EmptyString() && m##name##Asset.notNull())\
return m##name##Asset->getSfxProfile();\
m##name##Profile = m##name##Asset->getSfxProfile();\
return m##name##Profile;\
return NULL;\
}\
SFXDescription* get##name##Description()\
{\
if (get##name() != StringTable->EmptyString() && m##name##Asset.notNull())\
m##name##Desc = m##name##Asset->getSfxDescription();\
return m##name##Desc;\
return NULL;\
}\
bool is##name##Valid() { return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
@ -290,10 +307,61 @@ public: \
#endif // TORQUE_SHOW_LEGACY_FILE_FIELDS
//network send - datablock
#define PACKDATA_SOUNDASSET(name)\
if (stream->writeFlag(m##name##Asset.notNull()))\
{\
stream->writeString(m##name##Asset.getAssetId());\
}\
else\
{\
if(stream->writeFlag(Sim::findObject(m##name##Name)))\
{\
SFXTrack* sndTrack;\
Sim::findObject(m##name##Name, sndTrack);\
stream->writeRangedU32(SimObjectId(sndTrack->getId()), DataBlockObjectIdFirst, DataBlockObjectIdLast);\
}\
else\
{\
stream->writeString(m##name##Name);\
}\
}
//network recieve - datablock
#define UNPACKDATA_SOUNDASSET(name)\
if (stream->readFlag())\
{\
m##name##AssetId = stream->readSTString();\
_set##name(m##name##AssetId);\
}\
else\
{\
if(stream->readFlag())\
{\
m##name##SFXId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );\
}\
else\
{\
m##name##Name = stream->readSTString(); \
_set##name(m##name##Name); \
}\
}
#pragma endregion
#pragma region Arrayed Asset Macros
#define INIT_SOUNDASSET_ARRAY(name, 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] = NULL;\
m##name##SFXId[index] = 0;\
}
#define DECLARE_SOUNDASSET_ARRAY(className,name,max) public: \
static const U32 sm##name##Count = max;\
Resource<SFXResource> m##name[max];\
@ -301,6 +369,7 @@ public: \
StringTableEntry m##name##AssetId[max];\
AssetPtr<SoundAsset> m##name##Asset[max];\
SFXProfile* m##name##Profile[max];\
SimObjectId m##name##SFXId[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());}\
@ -376,7 +445,7 @@ public: \
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])\
else if (!m##name[index] && (m##name##Name[index] != StringTable->EmptyString() && !Sim::findObject(m##name##Name[index])))\
{\
Con::errorf("%s(%s)::_set%s(%i) - Couldn't load sound \"%s\"", macroText(className), getName(), macroText(name),index, _in);\
return false;\
@ -448,6 +517,46 @@ if (m##name##AssetId[index] != StringTable->EmptyString())\
addField(assetEnumNameConcat(enumString, Asset), TypeSoundAssetId, Offset(m##name##AssetId[0], consoleClass) + sizeof(m##name##AssetId[0])*i, assetText(name, asset reference.));\
}\
}
#define PACKDATA_SOUNDASSET_ARRAY(name, index)\
if (stream->writeFlag(m##name##Asset[index].notNull()))\
{\
stream->writeString(m##name##Asset[index].getAssetId());\
}\
else\
{\
if(stream->writeFlag(Sim::findObject(m##name##Name[index])))\
{\
SFXTrack* sndTrack;\
Sim::findObject(m##name##Name[index], sndTrack);\
stream->writeRangedU32(SimObjectId(sndTrack->getId()), DataBlockObjectIdFirst, DataBlockObjectIdLast);\
}\
else\
{\
stream->writeString(m##name##Name[index]);\
}\
}
//network recieve - datablock
#define UNPACKDATA_SOUNDASSET_ARRAY(name, index)\
if (stream->readFlag())\
{\
m##name##AssetId[index] = stream->readSTString();\
_set##name(m##name##AssetId[index], index);\
}\
else\
{\
if(stream->readFlag())\
{\
m##name##SFXId[index] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );\
}\
else\
{\
m##name##Name[index] = stream->readSTString(); \
_set##name(m##name##Name[index], index); \
}\
}
#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

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);",
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"TerrainMaterialAsset\", \"AssetBrowser.changeAsset\", %s, %s);",
mInspector->getIdString(), mCaption);
mMatPreviewButton->setField("Command", szBuffer);
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_

View file

@ -79,6 +79,8 @@ AssetImportConfig::AssetImportConfig() :
SeparateAnimationPrefix(""),
animTiming("FrameCount"),
animFPS(false),
AlwaysAddShapeAnimationSuffix(true),
AddedShapeAnimationSuffix("_anim"),
GenerateCollisions(false),
GenCollisionType(""),
CollisionMeshPrefix(""),
@ -190,6 +192,8 @@ void AssetImportConfig::initPersistFields()
addField("SeparateAnimationPrefix", TypeRealString, Offset(SeparateAnimationPrefix, AssetImportConfig), "If separating animations out from a source file, what prefix should be added to the names for grouping association");
addField("animTiming", TypeRealString, Offset(animTiming, AssetImportConfig), "Defines the animation timing for the given animation sequence. Options are FrameTime, Seconds, Milliseconds");
addField("animFPS", TypeBool, Offset(animFPS, AssetImportConfig), "The FPS of the animation sequence");
addField("AlwaysAddShapeAnimationSuffix", TypeBool, Offset(AlwaysAddShapeAnimationSuffix, AssetImportConfig), "When importing a shape animation, this indicates if it should automatically add a standard suffix onto the name");
addField("AddedShapeAnimationSuffix", TypeString, Offset(AddedShapeAnimationSuffix, AssetImportConfig), " If AlwaysAddShapeAnimationSuffix is on, this is the suffix to be added");
endGroup("Animation");
addGroup("Collision");
@ -287,6 +291,8 @@ void AssetImportConfig::loadImportConfig(Settings* configSettings, String config
SeparateAnimationPrefix = configSettings->value(String(configName + "/Animations/SeparateAnimationPrefix").c_str());
animTiming = configSettings->value(String(configName + "/Animations/animTiming").c_str());
animFPS = dAtof(configSettings->value(String(configName + "/Animations/animFPS").c_str()));
AlwaysAddShapeAnimationSuffix = dAtob(configSettings->value(String(configName + "/Animations/AlwaysAddShapeAnimationSuffix").c_str()));
AddedShapeAnimationSuffix = configSettings->value(String(configName + "/Animations/AddedShapeAnimationSuffix").c_str());
//Collisions
GenerateCollisions = dAtob(configSettings->value(String(configName + "/Collision/GenerateCollisions").c_str()));
@ -379,6 +385,8 @@ void AssetImportConfig::CopyTo(AssetImportConfig* target) const
target->SeparateAnimationPrefix = SeparateAnimationPrefix;
target->animTiming = animTiming;
target->animFPS = animFPS;
target->AlwaysAddShapeAnimationSuffix = AlwaysAddShapeAnimationSuffix;
target->AddedShapeAnimationSuffix = AddedShapeAnimationSuffix;
//Collisions
target->GenerateCollisions = GenerateCollisions;
@ -609,14 +617,32 @@ AssetImportObject* AssetImporter::addImportingAsset(String assetType, Torque::Pa
assetImportObj->registerObject();
//sanitize
assetName.replace(' ', '_');
assetName.replace('~', '_');
assetName.replace('`', '_');
assetName.replace('-', '_');
assetName.replace('*', '_');
assetName.replace('-', '_');
assetName.replace('+', '_');
assetName.replace('&', '_');
String processedString = assetName;
U32 start;
U32 end;
String firstNumber = String::GetFirstNumber(processedString, start, end);
if (!firstNumber.isEmpty() && processedString.startsWith(firstNumber.c_str()))
processedString = processedString.replace(firstNumber, "");
processedString = processedString.replace(" ", "_");
U32 len = processedString.length() + 1;
char* sanitizedStr = Con::getReturnBuffer(len);
dStrcpy(sanitizedStr, processedString.c_str(), len);
U32 pos = dStrcspn(sanitizedStr, "-+*/%$&<26>=()[].?\\\"#,;!~<>|<7C>^{}");
while (pos < dStrlen(sanitizedStr))
{
dStrcpy(sanitizedStr + pos, sanitizedStr + pos + 1, len - pos);
pos = dStrcspn(sanitizedStr, "-+*/%$&<26>=()[].?\\\"#,;!~<>|<7C>^{}");
}
//If we did, indeed, modify the name, update it now
if (String(sanitizedStr) != assetName)
{
assetName = sanitizedStr;
}
assetImportObj->assetType = assetType;
assetImportObj->filePath = filePath;
@ -1513,13 +1539,15 @@ void AssetImporter::processImportAssets(AssetImportObject* assetItem)
{
processMaterialAsset(item);
}
/*else if (item->assetType == String("ShapeAnimationAsset"))
ShapeAnimationAsset::prepareAssetForImport(this, item);*/
else if (item->assetType == String("ShapeAnimationAsset"))
{
processShapeAnimationAsset(item);
}
else
{
String processCommand = "process";
processCommand += item->assetType;
if(isMethod(processCommand.c_str()))
if (isMethod(processCommand.c_str()))
Con::executef(this, processCommand.c_str(), item);
}
@ -1605,7 +1633,7 @@ void AssetImporter::processImageAsset(AssetImportObject* assetItem)
{
String diffuseToken = StringUnit::getUnit(activeImportConfig->DiffuseTypeSuffixes, 0, ",;\t");
assetItem->assetName = assetItem->assetName + diffuseToken;
assetItem->cleanAssetName = assetItem->assetName;
//assetItem->cleanAssetName = assetItem->assetName;
}
else
{
@ -1614,7 +1642,7 @@ void AssetImporter::processImageAsset(AssetImportObject* assetItem)
if ((materialAsset && materialAsset->assetName.compare(assetItem->assetName) == 0) || activeImportConfig->AlwaysAddImageSuffix)
{
assetItem->assetName = assetItem->assetName + activeImportConfig->AddedImageSuffix;
assetItem->cleanAssetName = assetItem->assetName;
//assetItem->cleanAssetName = assetItem->assetName;
}
}
@ -1645,8 +1673,8 @@ void AssetImporter::processImageAsset(AssetImportObject* assetItem)
if(assetItem->assetName == assetItem->cleanAssetName && activeImportConfig->AlwaysAddImageSuffix)
{
assetItem->assetName = assetItem->assetName + activeImportConfig->AddedImageSuffix;
assetItem->cleanAssetName = assetItem->assetName;
if (!assetItem->assetName.endsWith(activeImportConfig->AddedImageSuffix.c_str()))
assetItem->assetName = assetItem->assetName + activeImportConfig->AddedImageSuffix;
}
assetItem->importStatus = AssetImportObject::Processed;
@ -1699,7 +1727,8 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem)
//If there was no existing assetId, then lets see if it already exists in a legacy file, like a materials.cs or materials.tscript
//If it does, we'll just make our asset point to that instead of a new file
Material* mat = MATMGR->getMaterialDefinitionByName(assetName);
Material* mat;
Sim::findObject(assetName, mat);
if (!mat)
mat = MATMGR->getMaterialDefinitionByMapTo(assetName);
@ -1724,8 +1753,8 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem)
{
if (activeImportConfig->AlwaysAddMaterialSuffix) //we only opt to force on the suffix if we're not obligating using the original material defs
{
assetItem->assetName += activeImportConfig->AddedMaterialSuffix;
assetItem->cleanAssetName = assetItem->assetName;
if(!assetItem->assetName.endsWith(activeImportConfig->AddedMaterialSuffix.c_str()))
assetItem->assetName += activeImportConfig->AddedMaterialSuffix;
}
if (activeImportConfig->PopulateMaterialMaps)
@ -1908,7 +1937,7 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem)
if (newImageAssetObj->assetName == assetItem->assetName)
{
newImageAssetObj->assetName += StringUnit::getUnit(suffixList.c_str(), 0, ",;\t");
newImageAssetObj->cleanAssetName = newImageAssetObj->assetName;
//newImageAssetObj->cleanAssetName = newImageAssetObj->assetName;
}
newImageAssetObj->imageSuffixType = ImageAsset::getImageTypeNameFromType(ImageAsset::ImageTypes::Albedo);
@ -1926,7 +1955,7 @@ void AssetImporter::processMaterialAsset(AssetImportObject* assetItem)
if (matchedImageTypes[t]->assetName == assetItem->assetName)
{
matchedImageTypes[t]->assetName += StringUnit::getUnit(suffixList.c_str(), 0, ",;\t");
matchedImageTypes[t]->cleanAssetName = matchedImageTypes[t]->assetName;
//matchedImageTypes[t]->cleanAssetName = matchedImageTypes[t]->assetName;
}
}
}
@ -1972,8 +2001,8 @@ void AssetImporter::processShapeAsset(AssetImportObject* assetItem)
if (activeImportConfig->AlwaysAddShapeSuffix)
{
assetItem->assetName += activeImportConfig->AddedShapeSuffix;
assetItem->cleanAssetName = assetItem->assetName;
if(!assetItem->assetName.endsWith(activeImportConfig->AddedShapeSuffix.c_str()))
assetItem->assetName += activeImportConfig->AddedShapeSuffix;
}
S32 meshCount = dAtoi(assetItem->shapeInfo->getDataField(StringTable->insert("_meshCount"), nullptr));
@ -2030,6 +2059,73 @@ void AssetImporter::processShapeAsset(AssetImportObject* assetItem)
assetItem->importStatus = AssetImportObject::Processed;
}
void AssetImporter::processShapeAnimationAsset(AssetImportObject* assetItem)
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Preparing Shape Animation for Import: %s", assetItem->assetName.c_str());
activityLog.push_back(importLogBuffer);
String filePath = assetItem->filePath.getFullPath();
String fileName = assetItem->filePath.getFileName();
String fileExt = assetItem->filePath.getExtension();
if (assetItem->shapeInfo == nullptr)
{
GuiTreeViewCtrl* shapeInfo = new GuiTreeViewCtrl();
shapeInfo->registerObject();
if (fileExt.compare("dae") == 0)
{
enumColladaForImport(filePath, shapeInfo, false);
}
else if (fileExt.compare("dts") == 0 || fileExt.compare("dsq") == 0)
{
enumDTSForImport(filePath, shapeInfo);
}
else
{
// Check if a cached DTS is available => no need to import the source file
// if we can load the DTS instead
AssimpShapeLoader loader;
loader.fillGuiTreeView(filePath.c_str(), shapeInfo);
}
assetItem->shapeInfo = shapeInfo;
}
if (activeImportConfig->AlwaysAddShapeAnimationSuffix)
{
if (!assetItem->assetName.endsWith(activeImportConfig->AddedShapeAnimationSuffix.c_str()))
assetItem->assetName += activeImportConfig->AddedShapeAnimationSuffix;
}
S32 animCount = dAtoi(assetItem->shapeInfo->getDataField(StringTable->insert("_animCount"), nullptr));
dSprintf(importLogBuffer, sizeof(importLogBuffer), " Shape Animation Info: Anim Count: %i", animCount);
activityLog.push_back(importLogBuffer);
AssetImportConfig* cachedConfig = new AssetImportConfig();;
cachedConfig->registerObject();
activeImportConfig->CopyTo(cachedConfig);
if (!activeImportConfig->UseManualShapeConfigRules)
{
//Try and load a sis file if it exists for this format
activeImportConfig->loadSISFile(assetItem->filePath);
}
if (activeImportConfig->ImportAnimations && animCount > 0)
{
}
//restore the cached version just in case we loaded a sis file
cachedConfig->CopyTo(activeImportConfig);
cachedConfig->deleteObject();
assetItem->importStatus = AssetImportObject::Processed;
}
void AssetImporter::processShapeMaterialInfo(AssetImportObject* assetItem, S32 materialItemId)
{
String matName = assetItem->shapeInfo->getItemText(materialItemId);
@ -2099,22 +2195,28 @@ void AssetImporter::processShapeMaterialInfo(AssetImportObject* assetItem, S32 m
String imgFileName = AssetImporter::findImagePath(testFilePath.getPath() + "/" + testFilePath.getFileName());
if (imgFileName.isNotEmpty())
filePath = imgFileName;
else
filePath = Torque::Path(""); //no luck, so we just won't try importing in the image
}
}
matAssetItem = addImportingAsset("MaterialAsset", shapePathBase + "/" + matName, assetItem, matName);
AssetImportObject* imageAssetItem = addImportingAsset("ImageAsset", filePath, matAssetItem, "");
String suffixType;
String suffix = parseImageSuffixes(imageAssetItem->assetName, &suffixType);
if (suffix.isNotEmpty())
if (!filePath.isEmpty())
{
imageAssetItem->imageSuffixType = suffixType;
}
else
{
//we'll assume it's albedo
imageAssetItem->imageSuffixType = "Albedo";
AssetImportObject* imageAssetItem = addImportingAsset("ImageAsset", filePath, matAssetItem, "");
String suffixType;
String suffix = parseImageSuffixes(imageAssetItem->assetName, &suffixType);
if (suffix.isNotEmpty())
{
imageAssetItem->imageSuffixType = suffixType;
}
else
{
//we'll assume it's albedo
imageAssetItem->imageSuffixType = "Albedo";
}
}
}
else
@ -2136,8 +2238,8 @@ void AssetImporter::processSoundAsset(AssetImportObject* assetItem)
if (activeImportConfig->AlwaysAddSoundSuffix)
{
assetItem->assetName += activeImportConfig->AddedSoundSuffix;
assetItem->cleanAssetName = assetItem->assetName;
if (!assetItem->assetName.endsWith(activeImportConfig->AddedSoundSuffix.c_str()))
assetItem->assetName += activeImportConfig->AddedSoundSuffix;
}
assetItem->importStatus = AssetImportObject::Processed;
@ -2164,9 +2266,20 @@ bool AssetImporter::validateAssets()
void AssetImporter::validateAsset(AssetImportObject* assetItem)
{
if (assetItem->importStatus == AssetImportObject::Skipped || assetItem->importStatus == AssetImportObject::NotProcessed)
if (assetItem->importStatus == AssetImportObject::Skipped || assetItem->importStatus == AssetImportObject::NotProcessed
|| assetItem->importStatus == AssetImportObject::UseForDependencies)
return;
//If this item's already been marked as being in error, don't bother with it. It knows what it did.
//This avoids running collision checks on an item already known to have a collision, which could erroneously
//mark the original, not-colliding item as colliding with this item, invaliding both
if (assetItem->status == String("Error") || assetItem->statusType.isNotEmpty())
{
importIssues = true;
return;
}
//Runm this item against our other importing assets and check for any collisions
if (checkAssetForCollision(assetItem))
{
importIssues = true;
@ -2270,7 +2383,7 @@ bool AssetImporter::checkAssetForCollision(AssetImportObject* assetItemToCheck,
{
AssetImportObject* importingAsset = itemList[i];
if (importingAsset->importStatus == AssetImportObject::Skipped)
if (importingAsset->importStatus == AssetImportObject::Skipped || importingAsset->importStatus == AssetImportObject::UseForDependencies)
continue;
if ((assetItemToCheck->assetName.compare(importingAsset->assetName) == 0) && (assetItemToCheck->getId() != importingAsset->getId()))
@ -2506,11 +2619,16 @@ StringTableEntry AssetImporter::autoImportFile(Torque::Path filePath, String typ
else
{
importAssets();
acquireAssets();
}
dumpActivityLog();
if (hasIssues)
if (hasIssues ||
assetItem->importStatus == AssetImportObject::Skipped ||
assetItem->importStatus == AssetImportObject::UseForDependencies ||
assetItem->importStatus == AssetImportObject::Error)
{
return StringTable->EmptyString();
}
@ -2560,6 +2678,10 @@ void AssetImporter::importAssets(AssetImportObject* assetItem)
{
assetPath = importMaterialAsset(item);
}
else if (item->assetType == String("ShapeAnimationAsset"))
{
assetPath = importShapeAnimationAsset(item);
}
else
{
finalImportedAssetPath = String::EmptyString;
@ -2601,7 +2723,7 @@ void AssetImporter::importAssets(AssetImportObject* assetItem)
else
{
//Any special-case post-reg stuff here
if (item->assetType == String("ShapeAsset"))
if (item->assetType == String("ShapeAsset") || item->assetType == String("ShapeAnimationAsset"))
{
//forcefully update it's shape constructor
TSShapeConstructor* tss = TSShapeConstructor::findShapeConstructorByAssetId(assetId);
@ -2610,10 +2732,6 @@ void AssetImporter::importAssets(AssetImportObject* assetItem)
tss->setShapeAssetId(assetId);
}
}
//Go ahead and force the asset to load now just to kick it for immediate use
AssetBase* assetDef = AssetDatabase.acquireAsset<AssetBase>(assetId);
AssetDatabase.releaseAsset(assetId);
}
else
{
@ -2638,6 +2756,34 @@ void AssetImporter::importAssets(AssetImportObject* assetItem)
dumpActivityLog();
}
void AssetImporter::acquireAssets(AssetImportObject* assetItem)
{
Vector<AssetImportObject*> itemList = importingAssets;
if (assetItem != nullptr)
itemList = assetItem->childAssetItems;
for (U32 i = 0; i < itemList.size(); i++)
{
AssetImportObject* item = itemList[i];
if (item->importStatus == AssetImportObject::Skipped ||
item->importStatus == AssetImportObject::NotProcessed ||
item->importStatus == AssetImportObject::Error)
continue;
//recurse if needed, we want to process child items first for dependency reasons
acquireAssets(item);
//Go ahead and force the asset to load now just to kick it for immediate use
String assetId = item->moduleName + ":" + item->assetName;
if (AssetDatabase.isDeclaredAsset(assetId))
{
AssetBase* assetDef = AssetDatabase.acquireAsset<AssetBase>(assetId);
AssetDatabase.releaseAsset(assetId);
}
}
}
//
// Type-specific import logic
//
@ -2673,7 +2819,7 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem)
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::isFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -2724,8 +2870,6 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
String tamlPath = targetPath + "/" + assetName + ".asset.taml";
String scriptName = assetItem->assetName + "." TORQUE_SCRIPT_EXTENSION;
String scriptPath = targetPath + "/" + scriptName;
String originalPath = assetItem->filePath.getFullPath().c_str();
char qualifiedFromFile[2048];
@ -2737,10 +2881,13 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
#endif
newAsset->setAssetName(assetName);
newAsset->setScriptFile(scriptName.c_str());
if (!isReimport && Torque::FS::isFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
newAsset->setDataField(StringTable->insert("materialDefinitionName"), nullptr, assetName);
//iterate through and write out the material maps dependencies
S32 dependencySlotId = 0;
@ -2762,16 +2909,6 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
dependencySlotId++;
}
Taml tamlWriter;
bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
if (!importSuccessful)
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
activityLog.push_back(importLogBuffer);
return "";
}
//build the ORMConfig file if we're flagged to and have valid image maps
if (activeImportConfig->CreateORMConfig)
{
@ -2810,109 +2947,12 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
}
}
FileObject* file = new FileObject();
file->registerObject();
if (activeImportConfig->UseExistingMaterials && Torque::FS::IsFile(qualifiedFromFile))
//If we're not using existing materials, or the material in question doesn't actually already exist, spool it up
if (!activeImportConfig->UseExistingMaterials || !Sim::findObject(assetName))
{
//Now write the script file containing our material out
//There's 2 ways to do this. If we're in-place importing an existing asset, we can see if the definition existed already, like in an old
//materials.tscript file. if it does, we can just find the object by name, and save it out to our new file
//If not, we'll just generate one
Material* existingMat = MATMGR->getMaterialDefinitionByName(assetName);
//It's also possible that, for legacy models, the material hooks in via the material's mapTo field, and the material name is something completely different
//So we'll check for that as well if we didn't find it by name up above
if (existingMat == nullptr)
existingMat = MATMGR->getMaterialDefinitionByMapTo(assetName);
if (existingMat == nullptr && assetItem->assetName != assetItem->cleanAssetName)
{
existingMat = MATMGR->getMaterialDefinitionByName(assetItem->cleanAssetName);
if (existingMat == nullptr)
existingMat = MATMGR->getMaterialDefinitionByMapTo(assetItem->cleanAssetName);
}
if (existingMat)
{
PersistenceManager* persistMgr;
if (Sim::findObject("ImageAssetValidator", persistMgr))
{
for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
{
AssetImportObject* childItem = assetItem->childAssetItems[i];
if (childItem->canImport() || childItem->assetType.compare("ImageAsset") != 0)
continue;
String path = childItem->filePath.getFullFileName();
String mapFieldName = "";
String assetFieldName = "";
ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
{
mapFieldName = "DiffuseMap";
}
else if (imageType == ImageAsset::ImageTypes::Normal)
{
mapFieldName = "NormalMap";
}
else if (imageType == ImageAsset::ImageTypes::ORMConfig)
{
mapFieldName = "ORMConfig";
}
else if (imageType == ImageAsset::ImageTypes::Metalness)
{
mapFieldName = "MetalMap";
}
else if (imageType == ImageAsset::ImageTypes::AO)
{
mapFieldName = "AOMap";
}
else if (imageType == ImageAsset::ImageTypes::Roughness)
{
mapFieldName = "RoughMap";
}
assetFieldName = mapFieldName + "Asset[0]";
mapFieldName += "[0]";
//If there's already an existing image map file on the material definition in this slot, don't override it
if (!path.isEmpty())
existingMat->writeField(mapFieldName.c_str(), path.c_str());
String targetAsset = targetModuleId + ":" + childItem->assetName;
existingMat->writeField(assetFieldName.c_str(), targetAsset.c_str());
}
persistMgr->setDirty(existingMat);
}
else
{
Con::errorf("ImageAssetValidator not found!");
}
}
else
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Failed to find original material definition %s!", assetName);
activityLog.push_back(importLogBuffer);
return tamlPath;
}
}
else if (file->openForWrite(scriptPath.c_str()))
{
file->writeLine((U8*)"//--- OBJECT WRITE BEGIN ---");
char lineBuffer[1024];
dSprintf(lineBuffer, 1024, "singleton Material(%s) {", assetName);
file->writeLine((U8*)lineBuffer);
dSprintf(lineBuffer, 1024, " mapTo=\"%s\";", assetName);
file->writeLine((U8*)lineBuffer);
Material* newMat = new Material();
newMat->registerObject(assetName);
newMat->mMapTo = assetItem->cleanAssetName;
bool hasRoughness = false;
for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
@ -2922,63 +2962,58 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
if ((!childItem->canImport() && childItem->importStatus != AssetImportObject::UseForDependencies) || childItem->assetType.compare("ImageAsset") != 0)
continue;
String mapFieldName = "";
String assetFieldName = "";
ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
String assetMapFillIn = targetModuleId + ":" + childItem->assetName;
StringTableEntry assetMapFillInStr = StringTable->insert(assetMapFillIn.c_str());
if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
{
mapFieldName = "DiffuseMap";
newMat->mDiffuseMapAssetId[0] = assetMapFillInStr;
}
else if (imageType == ImageAsset::ImageTypes::Normal)
{
mapFieldName = "NormalMap";
newMat->mNormalMapAssetId[0] = assetMapFillInStr;
}
else if (imageType == ImageAsset::ImageTypes::ORMConfig)
{
mapFieldName = "ORMConfigMap";
newMat->mORMConfigMapAssetId[0] = assetMapFillInStr;
}
else if (imageType == ImageAsset::ImageTypes::Metalness)
{
mapFieldName = "MetalMap";
newMat->mMetalMapAssetId[0] = assetMapFillInStr;
}
else if (imageType == ImageAsset::ImageTypes::AO)
{
mapFieldName = "AOMap";
newMat->mAOMapAssetId[0] = assetMapFillInStr;
}
else if (imageType == ImageAsset::ImageTypes::Roughness)
{
mapFieldName = "RoughMap";
newMat->mRoughMapAssetId[0] = assetMapFillInStr;
hasRoughness = true;
}
assetFieldName = mapFieldName + "Asset";
assetFieldName += "[0]";
//String path = childItem->filePath.getFullFileName();
//dSprintf(lineBuffer, 1024, " %s = \"%s\";", mapFieldName.c_str(), path.c_str());
//file->writeLine((U8*)lineBuffer);
dSprintf(lineBuffer, 1024, " %s = \"%s:%s\";", assetFieldName.c_str(), targetModuleId.c_str(), childItem->assetName.c_str());
file->writeLine((U8*)lineBuffer);
}
if (hasRoughness)
{
file->writeLine((U8*)" invertSmoothness = true;");
newMat->mInvertRoughness[0] = true;
}
file->writeLine((U8*)"};");
file->writeLine((U8*)"//--- OBJECT WRITE END ---");
file->close();
newAsset->addObject(newMat);
}
else
else
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset script file %s", scriptPath.c_str());
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Set to use an existing material, so avoiding writing a material definition to new asset definition for material: %s", assetName);
activityLog.push_back(importLogBuffer);
return "";
}
Taml tamlWriter;
bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
if (!importSuccessful)
{
dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
activityLog.push_back(importLogBuffer);
return "";
}
@ -3037,7 +3072,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::isFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3317,7 +3352,7 @@ Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem)
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::isFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3378,7 +3413,7 @@ Torque::Path AssetImporter::importShapeAnimationAsset(AssetImportObject* assetIt
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS:::isFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}

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>
@ -800,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>
@ -898,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

View file

@ -92,7 +92,9 @@ DefineEngineMethod(AssetImporter, resolveAssetItemIssues, void, (AssetImportObje
DefineEngineMethod(AssetImporter, importAssets, void, (),,
"Runs the actual import action on the items.")
{
return object->importAssets();
object->importAssets();
object->acquireAssets();
}
DefineEngineMethod(AssetImporter, getAssetItemCount, S32, (),,

View file

@ -1205,11 +1205,15 @@ void ConvexShape::_updateMaterial()
//update our custom surface materials
for (U32 i = 0; i<mSurfaceTextures.size(); i++)
{
mSurfaceTextures[i]._setMaterial(mSurfaceTextures[i].getMaterial());
//If we already have the material inst and it hasn't changed, skip
if (mSurfaceTextures[i].materialInst &&
mSurfaceTextures[i].getMaterialAsset()->getMaterialDefinitionName() == mSurfaceTextures[i].materialInst->getMaterial()->getName())
mSurfaceTextures[i].getMaterialAsset()->getMaterialDefinitionName() == mSurfaceTextures[i].materialInst->getMaterial()->getName() &&
mSurfaceTextures[i].materialInst->getVertexFormat() == getGFXVertexFormat<VertexType>())
continue;
SAFE_DELETE(mSurfaceTextures[i].materialInst);
Material* material = mSurfaceTextures[i].getMaterialResource();
if (material == nullptr)
@ -1227,8 +1231,10 @@ void ConvexShape::_updateMaterial()
}
}
_setMaterial(getMaterial());
// If the material name matches then don't bother updating it.
if (mMaterialInst && getMaterialAsset()->getMaterialDefinitionName() == mMaterialInst->getMaterial()->getName())
if (mMaterialInst && getMaterialAsset()->getMaterialDefinitionName() == mMaterialInst->getMaterial()->getName() &&
mMaterialInst->getVertexFormat() == getGFXVertexFormat<VertexType>())
return;
SAFE_DELETE( mMaterialInst );
@ -1240,12 +1246,6 @@ void ConvexShape::_updateMaterial()
mMaterialInst = material->createMatInstance();
//GFXStateBlockDesc desc;
//desc.setCullMode( GFXCullNone );
//desc.setBlend( false );
//mMaterialInst->addStateBlockDesc( desc );
FeatureSet features = MATMGR->getDefaultFeatures();
//features.addFeature( MFT_DiffuseVertColor );
@ -1436,10 +1436,12 @@ void ConvexShape::_updateGeometry( bool updateCollision )
for (S32 k = 0; k < 3; k++)
{
pVert->normal = face.normal;
pVert->tangent = face.tangent;
pVert->color = faceColor;
pVert->T = face.tangent;
pVert->B = mCross(face.normal,face.tangent);
//pVert->color = faceColor;
pVert->point = pointList[facePntMap[triangles[j][k]]];
pVert->texCoord = face.texcoords[triangles[j][k]];
pVert->texCoord2 = pVert->texCoord;
pVert++;
vc++;

View file

@ -77,9 +77,6 @@ GFXDeclareVertexFormat( ConvexVert )
class PhysicsBody;
// Define our vertex format here so we don't have to
// change it in multiple spots later
typedef ConvexVert VertexType;
class ConvexShape : public SceneObject
{
@ -100,6 +97,10 @@ public:
// the otherwise excessively deep scoping we had.
// eg. ConvexShape::Face::Triangle ...
// Define our vertex format here so we don't have to
// change it in multiple spots later
typedef GFXVertexPNTTB VertexType;
struct Edge
{
U32 p0;

View file

@ -1425,6 +1425,7 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
ri->prim->numPrimitives = currentBatch->iCount / 3;
ri->prim->startVertex = 0;
ri->prim->numVertices = currentBatch->vCount;
ri->translucentSort = !currentBatch->matInst->getMaterial()->isTranslucent();
// Ugly hack for ProjectedShadow!
if ( customTex )

View file

@ -60,6 +60,7 @@ RenderMeshExample::RenderMeshExample()
mTypeMask |= StaticObjectType | StaticShapeObjectType;
INIT_ASSET(Material);
mMaterialInst = NULL;
}
RenderMeshExample::~RenderMeshExample()

View file

@ -59,6 +59,7 @@ RenderShapeExample::RenderShapeExample()
mTypeMask |= StaticObjectType | StaticShapeObjectType;
// Make sure to initialize our TSShapeInstance to NULL
INIT_ASSET(Shape);
mShapeInstance = NULL;
}

View file

@ -652,6 +652,7 @@ void ExplosionData::packData(BitStream* stream)
PACKDATA_ASSET(ExplosionShape);
//PACKDATA_SOUNDASSET(Sound);
PACKDATA_ASSET(Sound);
if (stream->writeFlag(particleEmitter))
@ -859,9 +860,6 @@ bool ExplosionData::preload(bool server, String &errorStr)
if (Parent::preload(server, errorStr) == false)
return false;
if (!server && !getSoundProfile())
return false;
if( !server )
{
@ -870,12 +868,18 @@ bool ExplosionData::preload(bool server, String &errorStr)
_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()) {

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 )
@ -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." );
@ -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

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

View file

@ -293,7 +293,7 @@ void ParticleData::packData(BitStream* stream)
stream->writeFloat( times[i], 8);
}
//PACKDATA_ASSET(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_ASSET(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_ASSET(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_ASSET(Texture);
UNPACKDATA_ASSET(TextureExt);
constrain_pos = stream->readFlag();
start_angle = 360.0f*stream->readFloat(11);

View file

@ -1562,33 +1562,45 @@ void GameConnection::packetDropped(PacketNotify *note)
//----------------------------------------------------------------------------
void GameConnection::play2D(SFXProfile* profile)
void GameConnection::play2D(StringTableEntry assetId)
{
postNetEvent(new Sim2DAudioEvent(profile));
if (AssetDatabase.isDeclaredAsset(assetId))
{
postNetEvent(new SimSoundAssetEvent(assetId));
}
}
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(assetId, *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(assetId, *transform));
}
}
}
void GameConnection::doneScopingScene()
@ -2010,49 +2022,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(StringTableEntry assetId, const MatrixF& mat)
{
// cant get here unless the asset is declared.
mAsset = assetId;
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(StringTableEntry assetId = StringTable->EmptyString(), const MatrixF& mat = MatrixF::Identity);
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

@ -73,7 +73,7 @@ extern F32 gDecalBias;
extern GFXTexHandle gLevelAccuMap;
/// Default SFXAmbience used to reset the global soundscape.
static SFXAmbience sDefaultAmbience;
extern SFXAmbience* sDefaultAmbience;
//-----------------------------------------------------------------------------
@ -256,7 +256,7 @@ void LevelInfo::unpackUpdate(NetConnection *conn, BitStream *stream)
if( mSoundAmbience )
mSoundscape->setAmbience( mSoundAmbience );
else
mSoundscape->setAmbience( &sDefaultAmbience );
mSoundscape->setAmbience( sDefaultAmbience );
}
SFX->setDistanceModel( mSoundDistanceModel );
@ -302,7 +302,7 @@ bool LevelInfo::onAdd()
void LevelInfo::onRemove()
{
if( mSoundscape )
mSoundscape->setAmbience( &sDefaultAmbience );
mSoundscape->setAmbience( sDefaultAmbience );
Parent::onRemove();
}

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

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

@ -6365,15 +6365,11 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
if(len > 8191)
len = 8191;
stream->writeInt((S32)len, 13);
// constrain the range of mRot.z
while (mRot.z < 0.0f)
mRot.z += M_2PI_F;
while (mRot.z > M_2PI_F)
mRot.z -= M_2PI_F;
}
// constrain the range of mRot.z
mRot.z = mWrapF(mRot.z, 0.0f, M_2PI_F);
stream->writeFloat(mRot.z / M_2PI_F, 7);
stream->writeSignedFloat(mHead.x / (mDataBlock->maxLookAngle - mDataBlock->minLookAngle), 6);
stream->writeSignedFloat(mHead.z / mDataBlock->maxFreelookAngle, 6);

View file

@ -616,3 +616,9 @@ void ExplodePrefabUndoAction::redo()
name = Sim::getUniqueName( name );
mGroup->assignName( name );
}
DefineEngineMethod(Prefab, getChildGroup, S32, (),,
"")
{
return object->getChildGroup();
}

View file

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

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

@ -265,6 +265,7 @@ struct ShapeBaseImageData: public GameBaseData {
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
@ -503,6 +504,8 @@ struct ShapeBaseImageData: public GameBaseData {
void inspectPostApply();
void handleStateSoundTrack(const U32& stateId);
/// @}
/// @name Callbacks
@ -744,13 +747,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
@ -1114,7 +1117,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.
@ -1328,9 +1331,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

@ -133,6 +133,7 @@ ShapeBaseImageData::StateData::StateData()
spin = IgnoreSpin;
recoil = NoRecoil;
sound = NULL;
soundTrack = NULL;
emitter = NULL;
shapeSequence = NULL;
shapeSequenceScale = true;
@ -257,7 +258,7 @@ ShapeBaseImageData::ShapeBaseImageData()
stateShapeSequence[i] = 0;
stateScaleShapeSequence[i] = false;
INIT_ASSET_ARRAY(stateSound, i);
INIT_SOUNDASSET_ARRAY(stateSound, i);
stateScript[i] = 0;
stateEmitter[i] = 0;
stateEmitterTime[i] = 0;
@ -371,7 +372,8 @@ bool ShapeBaseImageData::onAdd()
s.shapeSequenceScale = stateScaleShapeSequence[i];
//_setstateSound(getstateSound(i),i);
s.sound = getstateSoundAsset(i);
handleStateSoundTrack(i);
s.script = stateScript[i];
s.emitter = stateEmitter[i];
s.emitterTime = stateEmitterTime[i];
@ -577,6 +579,45 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
return true;
}
void ShapeBaseImageData::handleStateSoundTrack(const U32& stateId)
{
if (stateId > MaxStates)
return;
StateData& s = state[stateId];
s.sound = getstateSoundAsset(stateId);
if (s.sound == NULL)
{
if (mstateSoundName[stateId] != 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[stateId], sndTrack))
{
Con::errorf("ShapeBaseImageData::onAdd() - attempted to find sound %s but failed!", mstateSoundName[stateId]);
}
else
{
s.soundTrack = sndTrack;
}
}
else if (mstateSoundSFXId[stateId] != 0)
{
SFXTrack* sndTrack;
if (!Sim::findObject(mstateSoundSFXId[stateId], sndTrack))
{
Con::errorf("ShapeBaseImageData::onAdd() - attempted to find sound %i but failed!", mstateSoundSFXId[stateId]);
}
else
{
s.soundTrack = sndTrack;
}
}
}
}
S32 ShapeBaseImageData::lookupState(const char* name)
{
if (!name || !name[0])
@ -1146,7 +1187,7 @@ void ShapeBaseImageData::packData(BitStream* stream)
}
}
PACKDATA_ASSET_ARRAY(stateSound, i);
PACKDATA_SOUNDASSET_ARRAY(stateSound, i);
}
stream->write(maxConcurrentSounds);
stream->writeFlag(useRemainderDT);
@ -1351,7 +1392,8 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
else
s.emitter = 0;
UNPACKDATA_ASSET_ARRAY(stateSound, i);
UNPACKDATA_SOUNDASSET_ARRAY(stateSound, i);
handleStateSoundTrack(i);
}
}
@ -2580,7 +2622,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;
@ -2611,12 +2653,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...
@ -2632,12 +2674,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;
@ -2665,7 +2707,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;
}
@ -2673,16 +2715,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);
}
}
@ -2695,10 +2737,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);
@ -2707,7 +2749,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) {
@ -2723,11 +2765,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;
}
}
@ -2752,7 +2794,7 @@ 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])
@ -2764,17 +2806,25 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
// 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->getSfxProfile(), &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()

View file

@ -419,6 +419,8 @@ bool TSStatic::_createShape()
// Reapply the current skin
mAppliedSkinName = "";
reSkin();
updateMaterials();
}
prepCollision();
@ -1619,8 +1621,6 @@ void TSStatic::updateMaterials()
}
}
mChangingMaterials.clear();
// Initialize the material instances
mShapeInstance->initMaterialList();
}