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

View file

@ -186,7 +186,7 @@ void VEditorButton::onRender( Point2I offset, const RectI& updateRect )
{
RectI boundsRect( offset, getExtent() );
if ( mDepressed || mStateOn || mMouseOver )
if ( mDepressed || mStateOn || mHighlighted )
{
renderFilledBorder( boundsRect, mProfile->mBorderColorHL, mProfile->mFillColorHL );
}

View file

@ -221,7 +221,7 @@ void afxSpellButton::onRender(Point2I offset, const RectI& updateRect)
if (mActive)
{
if (mMouseOver) state = HILIGHT;
if (mHighlighted) state = HILIGHT;
if (mDepressed || mStateOn) state = DEPRESSED;
}
else

View file

@ -55,11 +55,11 @@ extern StringTableEntry assetAutoUnloadField;
//#define ASSET_BASE_AUTOUNLOAD_FIELD "AssetAutoUnload"
//-----------------------------------------------------------------------------
class AssetBase : public SimObject
class AssetBase : public SimGroup
{
friend class AssetManager;
typedef SimObject Parent;
typedef SimGroup Parent;
protected:
AssetManager* mpOwningAssetManager;

View file

@ -35,8 +35,8 @@
#include "console/sim.h"
#endif
#ifndef _SIMOBJECT_H_
#include "console/simObject.h"
#ifndef _SIMSET_H_
#include "console/simSet.h"
#endif
#ifndef _CONSOLEOBJECT_H_

View file

@ -399,7 +399,12 @@ U32 ConditionalExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
TypeReq ConditionalExprNode::getPreferredType()
{
return trueExpr->getPreferredType();
// We can't make it calculate a type based on subsequent expressions as the expression
// could be a string, or just numbers. To play it safe, stringify anything that deals with
// a conditional, and let the interpreter cast as needed to other types safely.
//
// See: Regression Test 7 in ScriptTest. It has a string result in the else portion of the ?: ternary.
return TypeReqString;
}
//------------------------------------------------------------

View file

@ -1620,17 +1620,17 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
++ip; // To skip the recurse flag if the object wasnt found
if (curObject)
{
SimGroup* group = dynamic_cast<SimGroup*>(curObject);
if (group)
SimSet* set = dynamic_cast<SimSet*>(curObject);
if (set)
{
StringTableEntry intName = StringTable->insert(stack[_STK].getString());
bool recurse = code[ip - 1];
SimObject* obj = group->findObjectByInternalName(intName, recurse);
SimObject* obj = set->findObjectByInternalName(intName, recurse);
stack[_STK].setInt(obj ? obj->getId() : 0);
}
else
{
Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-group %s of class %s.", getFileLine(ip - 2), curObject->getName(), curObject->getClassName());
Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-set %s of class %s.", getFileLine(ip - 2), curObject->getName(), curObject->getClassName());
stack[_STK].setInt(0);
}
}

View file

@ -46,29 +46,28 @@
extern StringStack STR;
extern ConsoleValueStack<4096> gCallStack;
Vector<ConsoleValue::ConversionBuffer> ConsoleValue::sConversionBuffer;
DataChunker ConsoleValue::sConversionAllocator;
void ConsoleValue::init()
{
sConversionBuffer.reserve(8192);
sConversionAllocator.setChunkSize(8092);
}
void ConsoleValue::resetConversionBuffer()
{
sConversionBuffer.resetAndTreatAsScratchBuffer();
sConversionAllocator.freeBlocks();
}
char* ConsoleValue::convertToBuffer() const
{
ConversionBuffer conversion;
char* buffer = static_cast<char*>(sConversionAllocator.alloc(32));
if (type == ConsoleValueType::cvFloat)
dSprintf(conversion.buffer, ConversionBufferStride, "%.9g", f);
dSprintf(buffer, 32, "%.9g", f);
else
dSprintf(conversion.buffer, ConversionBufferStride, "%lld", i);
dSprintf(buffer, 32, "%lld", i);
sConversionBuffer.push_back(std::move(conversion));
return sConversionBuffer.last().buffer;
return buffer;
}
const char* ConsoleValue::getConsoleData() const

View file

@ -146,17 +146,7 @@ class ConsoleValue
S32 type;
enum Constants
{
ConversionBufferStride = 32
};
struct ConversionBuffer
{
char buffer[ConversionBufferStride];
};
static Vector<ConversionBuffer> sConversionBuffer;
static DataChunker sConversionAllocator;
char* convertToBuffer() const;
@ -239,8 +229,10 @@ public:
return f;
if (type == ConsoleValueType::cvInteger)
return i;
if (isStringType())
return dAtof(s);
if (type == ConsoleValueType::cvSTEntry)
return s == StringTable->EmptyString() ? 0.0f : dAtof(s);
if (type == ConsoleValueType::cvString)
return dStrcmp(s, "") == 0 ? 0.0f : dAtof(s);
return dAtof(getConsoleData());
}
@ -250,8 +242,10 @@ public:
return i;
if (type == ConsoleValueType::cvFloat)
return f;
if (isStringType())
return dAtoi(s);
if (type == ConsoleValueType::cvSTEntry)
return s == StringTable->EmptyString() ? 0 : dAtoi(s);
if (type == ConsoleValueType::cvString)
return dStrcmp(s, "") == 0 ? 0 : dAtoi(s);
return dAtoi(getConsoleData());
}
@ -275,8 +269,10 @@ public:
return (bool)i;
if (type == ConsoleValueType::cvFloat)
return (bool)f;
if (isStringType())
return dAtob(s);
if (type == ConsoleValueType::cvSTEntry)
return s == StringTable->EmptyString() ? false : dAtob(s);
if (type == ConsoleValueType::cvString)
return dStrcmp(s, "") == 0 ? false : dAtob(s);
return dAtob(getConsoleData());
}

View file

@ -2859,3 +2859,21 @@ DefineEngineFunction(getTimestamp, const char*, (), ,
return returnBuffer;
}
#ifdef TORQUE_TOOLS
DefineEngineFunction(systemCommand, S32, (const char* commandLineAction, const char* callBackFunction), (""), "")
{
if (commandLineAction != "")
{
S32 result = system(commandLineAction);
if (callBackFunction != "" && callBackFunction[0])
{
if (Con::isFunction(callBackFunction))
Con::executef(callBackFunction, result);
}
}
return -1;
}
#endif

View file

@ -387,7 +387,17 @@ DefineEngineFunction(isFile, bool, ( const char* fileName ),,
"@ingroup FileSystem")
{
return Torque::FS::IsFile(fileName);
Torque::Path givenPath(fileName);
if (givenPath.getFileName().isEmpty() && givenPath.getExtension().isNotEmpty())
{
//specially named or hidden files, like .gitignore parse incorrectly due to having
//"no" filename, so we adjust that
givenPath.setFileName(String(".") + givenPath.getExtension());
givenPath.setExtension("");
}
return Torque::FS::IsFile(givenPath);
}
DefineEngineFunction(isScriptFile, bool, (const char* fileName), ,
@ -860,4 +870,20 @@ DefineEngineFunction( createPath, bool, ( const char* path ),,
return Torque::FS::CreatePath(path);
}
DefineEngineFunction(deleteDirectory, bool, (const char* path), ,
"@brief Delete a directory from the hard drive\n\n"
"@param path Name and path of the folder to delete\n"
"@note THERE IS NO RECOVERY FROM THIS. Deleted files are gone for good.\n"
"@return True if file was successfully deleted\n"
"@ingroup FileSystem")
{
static char fileName[1024];
static char sandboxFileName[1024];
Con::expandScriptFilename(fileName, sizeof(fileName), path);
Platform::makeFullPathName(fileName, sandboxFileName, sizeof(sandboxFileName));
return Platform::deleteDirectory(sandboxFileName);
}
#endif // TORQUE_TOOLS

View file

@ -68,6 +68,8 @@ namespace Sim
ImplementNamedSet(SFXAmbienceSet)
ImplementNamedSet(TerrainMaterialSet)
ImplementNamedSet(DataBlockSet);
ImplementNamedSet(ForestBrushSet);
ImplementNamedSet(ForestItemDataSet);
ImplementNamedGroup(ActionMapGroup)
ImplementNamedGroup(ClientGroup)
ImplementNamedGroup(GuiGroup)

View file

@ -107,6 +107,8 @@ namespace Sim
DeclareNamedSet(SFXAmbienceSet);
DeclareNamedSet(TerrainMaterialSet);
DeclareNamedSet(DataBlockSet);
DeclareNamedSet(ForestBrushSet);
DeclareNamedSet(ForestItemDataSet);
DeclareNamedGroup(ActionMapGroup)
DeclareNamedGroup(ClientGroup)
DeclareNamedGroup(GuiGroup)

View file

@ -565,6 +565,8 @@ void init()
InstantiateNamedSet(SFXAmbienceSet);
InstantiateNamedSet(TerrainMaterialSet);
InstantiateNamedSet(DataBlockSet);
InstantiateNamedSet(ForestBrushSet);
InstantiateNamedSet(ForestItemDataSet);
InstantiateNamedGroup(ActionMapGroup);
InstantiateNamedGroup(ClientGroup);
InstantiateNamedGroup(GuiGroup);

View file

@ -77,6 +77,7 @@ SimObject::SimObject()
mObjectName = NULL;
mOriginalName = NULL;
mInternalName = NULL;
mInheritFrom = NULL;
nextNameObject = nullptr;
nextManagerNameObject = nullptr;
nextIdObject = NULL;
@ -154,6 +155,9 @@ void SimObject::initPersistFields()
addProtectedField( "name", TypeName, Offset(mObjectName, SimObject), &setProtectedName, &defaultProtectedGetFn,
"Optional global name of this object." );
addProtectedField("inheritFrom", TypeString, Offset(mInheritFrom, SimObject), &setInheritFrom, &defaultProtectedGetFn,
"Optional Name of object to inherit from as a parent.");
endGroup( "Ungrouped" );
@ -300,6 +304,10 @@ bool SimObject::writeField(StringTableEntry fieldname, const char* value)
void SimObject::writeFields(Stream &stream, U32 tabStop)
{
// Write static fields.
// Create a default object of the same type
ConsoleObject* defaultConObject = ConsoleObject::create(getClassName());
SimObject* defaultObject = dynamic_cast<SimObject*>(defaultConObject);
const AbstractClassRep::FieldList &list = getFieldList();
@ -328,6 +336,11 @@ void SimObject::writeFields(Stream &stream, U32 tabStop)
if (!writeField(f->pFieldname, valCopy))
continue;
//If the field hasn't been changed from the default value, then don't bother writing it out
const char* defaultValueCheck = defaultObject->getDataField(f->pFieldname, array);
if (defaultValueCheck && defaultValueCheck[0] != '\0' && dStricmp(defaultValueCheck, valCopy) == 0)
continue;
val = valCopy;
U32 expandedBufferSize = ( nBufferSize * 2 ) + dStrlen(f->pFieldname) + 32;
@ -362,6 +375,9 @@ void SimObject::writeFields(Stream &stream, U32 tabStop)
if(mFieldDictionary && mCanSaveFieldDictionary)
mFieldDictionary->writeFields(this, stream, tabStop);
// Cleanup our created default object
delete defaultConObject;
}
//-----------------------------------------------------------------------------
@ -1133,7 +1149,7 @@ const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const ch
//-----------------------------------------------------------------------------
void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *_array, const char *value)
{
// Sanity!
AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
@ -1142,7 +1158,7 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
// Set value without prefix if there's no value.
if (*value == 0)
{
setDataField(fieldName, NULL, value);
setDataField(fieldName, _array, value);
return;
}
@ -1156,7 +1172,7 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
if (fieldPrefix == StringTable->EmptyString())
{
// No, so set the data field in the usual way.
setDataField(fieldName, NULL, value);
setDataField(fieldName, _array, value);
return;
}
@ -1167,23 +1183,23 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
{
// No, so set the data field in the usual way.
setDataField(fieldName, NULL, value);
setDataField(fieldName, _array, value);
return;
}
// Yes, so set the data excluding the prefix.
setDataField(fieldName, NULL, value + fieldPrefixLength);
setDataField(fieldName, _array, value + fieldPrefixLength);
}
//-----------------------------------------------------------------------------
const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType)
const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *_array, const S32 fieldType)
{
// Sanity!
AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
// Fetch field value.
const char* pFieldValue = getDataField(fieldName, array);
const char* pFieldValue = getDataField(fieldName, _array);
// Sanity.
AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
@ -2235,10 +2251,10 @@ bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
{
if (preventNameChanging)
return false;
SimObject *object = static_cast<SimObject*>(obj);
if ( object->isProperlyAdded() )
object->assignName( data );
SimObject* object = static_cast<SimObject*>(obj);
if (object->isProperlyAdded())
object->assignName(data);
// always return false because we assign the name here
return false;
@ -2246,6 +2262,31 @@ bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
//-----------------------------------------------------------------------------
bool SimObject::setInheritFrom(void* obj, const char* index, const char* data)
{
SimObject* object = static_cast<SimObject*>(obj);
SimObject* parent;
if (Sim::findObject(data, parent))
{
object->setCopySource(parent);
object->assignFieldsFrom(parent);
// copy any substitution statements
SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
if (parent_db)
{
SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(object);
if (currentNewObject_db)
currentNewObject_db->copySubstitutionsFrom(parent_db);
}
}
return true;
}
//-----------------------------------------------------------------------------
void SimObject::inspectPreApply()
{
}

View file

@ -299,6 +299,8 @@ class SimObject: public ConsoleObject, public TamlCallbacks
SimObject* nextManagerNameObject;
SimObject* nextIdObject;
StringTableEntry mInheritFrom;
/// SimGroup we're contained in, if any.
SimGroup* mGroup;
@ -380,6 +382,9 @@ class SimObject: public ConsoleObject, public TamlCallbacks
// Object name protected set method
static bool setProtectedName(void *object, const char *index, const char *data);
// Sets object to inherit default values from
static bool setInheritFrom(void* object, const char* index, const char* data);
public:
inline void setProgenitorFile(const char* pFile) { mProgenitorFile = StringTable->insert(pFile); }
inline StringTableEntry getProgenitorFile(void) const { return mProgenitorFile; }

View file

@ -1079,6 +1079,22 @@ TEST(Script, MiscRegressions)
)");
ASSERT_EQ(regression6.getBool(), true);
ConsoleValue regression7 = RunScript(R"(
function Tween::vectorAdd(%v1, %v2)
{
%temp = "";
for (%i = 0; %i < getWordCount(%v1); %i++) {
%e = getWord(%v1, %i) + getWord(%v2, %i);
%temp = %i == 0 ? %e : %temp SPC %e;
}
return %temp;
}
return Tween::vectorAdd("1 2 3", "4 5 6");
)");
ASSERT_STREQ(regression7.getString(), "5 7 9");
}
#endif

View file

@ -254,17 +254,16 @@ class String::StringData : protected StringDataImpl
public:
///
StringData( const StringChar* data, bool interned = false )
StringData( const StringChar* data, U32 length, bool interned = false )
{
mRefCount = 1;
mNumChars = U32_MAX;
mHashCase = U32_MAX;
mHashNoCase = U32_MAX;
mUTF16 = NULL;
mLength = length;
mIsInterned = interned;
// mLength is initialized by operator new()
if( data )
{
dMemcpy( mData, data, sizeof( StringChar ) * mLength );
@ -280,14 +279,26 @@ class String::StringData : protected StringDataImpl
~StringData()
{
AssertFatal( mRefCount == 0, "StringData::~StringData invalid refcount" );
if( mUTF16 )
delete [] mUTF16;
}
TORQUE_NOINLINE void* operator new(size_t size, U32 len);
TORQUE_NOINLINE void* operator new( size_t size, U32 len, DataChunker& chunker );
void operator delete(void *);
static StringData* Create(const StringChar* data, U32 len, bool interned = false)
{
void* memory = dMalloc(sizeof(StringData) + sizeof(StringChar) * len);
StringData* result = new(memory) StringData(data, len, interned);
return result;
}
static StringData* Create(const StringChar* data, U32 len, DataChunker& chunker, bool interned = false)
{
void* memory = chunker.alloc( sizeof(StringData) + len * sizeof(StringChar));
StringData* result = new(memory) StringData(data, len, interned);
return result;
}
bool isShared() const
{
return ( mRefCount > 1 );
@ -492,51 +503,6 @@ DefineEngineFunction( dumpStringMemStats, void, (), , "()"
//-----------------------------------------------------------------------------
void* String::StringData::operator new( size_t size, U32 len )
{
AssertFatal( len != 0, "String::StringData::operator new() - string must not be empty" );
StringData *str = static_cast<StringData*>( dMalloc( size + len * sizeof(StringChar) ) );
str->mLength = len;
#ifdef TORQUE_DEBUG
dFetchAndAdd( sgStringMemBytes, size + len * sizeof(StringChar) );
dFetchAndAdd( sgStringInstances, 1 );
#endif
return str;
}
void String::StringData::operator delete(void *ptr)
{
StringData* sub = static_cast<StringData *>(ptr);
AssertFatal( sub->mRefCount == 0, "StringData::delete() - invalid refcount" );
#ifdef TORQUE_DEBUG
dFetchAndAdd( sgStringMemBytes, U32( -( S32( sizeof( StringData ) + sub->mLength * sizeof(StringChar) ) ) ) );
dFetchAndAdd( sgStringInstances, U32( -1 ) );
#endif
dFree( ptr );
}
void* String::StringData::operator new( size_t size, U32 len, DataChunker& chunker )
{
AssertFatal( len != 0, "String::StringData::operator new() - string must not be empty" );
StringData *str = static_cast<StringData*>( chunker.alloc( size + len * sizeof(StringChar) ) );
str->mLength = len;
#ifdef TORQUE_DEBUG
dFetchAndAdd( sgStringMemBytes, size + len * sizeof(StringChar) );
dFetchAndAdd( sgStringInstances, 1 );
#endif
return str;
}
//-----------------------------------------------------------------------------
String::String()
{
PROFILE_SCOPE(String_default_constructor);
@ -556,7 +522,7 @@ String::String(const StringChar *str)
if( str && *str )
{
U32 len = dStrlen(str);
_string = new ( len ) StringData( str );
_string = StringData::Create(str, len);
}
else
_string = StringData::Empty();
@ -567,7 +533,7 @@ String::String(const StringChar *str, SizeType len)
PROFILE_SCOPE(String_char_len_constructor);
if (str && *str && len!=0)
{
_string = new ( len ) StringData( str );
_string = StringData::Create(str, len);
}
else
_string = StringData::Empty();
@ -581,7 +547,7 @@ String::String(const UTF16 *str)
{
UTF8* utf8 = createUTF8string( str );
U32 len = dStrlen( utf8 );
_string = new ( len ) StringData( utf8 );
_string = StringData::Create(utf8, len);
delete [] utf8;
}
else
@ -619,7 +585,7 @@ String String::intern() const
// Create new.
StringData* data = new ( length(), sInternTable->mChunker ) StringData( c_str(), true );
StringData* data = StringData::Create(c_str(), length(), sInternTable->mChunker, true);
iter = sInternTable->insertUnique( data, data );
return ( *iter ).value;
@ -710,7 +676,7 @@ String& String::operator=(StringChar c)
{
_string->release();
_string = new ( 2 ) StringData( 0 );
_string = StringData::Create(NULL, 2);
_string->utf8()[ 0 ] = c;
_string->utf8()[ 1 ] = '\0';
@ -721,8 +687,8 @@ String& String::operator+=(StringChar c)
{
// Append the given string into a new string
U32 len = _string->getLength();
StringData* sub = new ( len + 1 ) StringData( NULL );
StringData* sub = StringData::Create(NULL, len + 1);
copy( sub->utf8(), _string->utf8(), len );
sub->utf8()[len] = c;
sub->utf8()[len+1] = 0;
@ -748,7 +714,7 @@ String& String::operator=(const StringChar *str)
if (str && *str)
{
U32 len = dStrlen(str);
_string = new ( len ) StringData( str );
_string = StringData::Create(str, len);
}
else
_string = StringData::Empty();
@ -782,7 +748,7 @@ String& String::operator+=(const StringChar *src)
sub = StringData::Empty();
else
{
sub = new ( newlen ) StringData( NULL );
sub = StringData::Create(NULL, newlen);
copy(sub->utf8(),_string->utf8(),lena);
copy(sub->utf8() + lena,src,lenb + 1);
@ -809,7 +775,7 @@ String& String::operator+=(const String &src)
sub = StringData::Empty();
else
{
sub = new ( newlen ) StringData( NULL );
sub = StringData::Create(NULL, newlen);
copy(sub->utf8(),_string->utf8(),lena);
copy(sub->utf8() + lena,src._string->utf8(),lenb + 1);
@ -835,7 +801,7 @@ String operator+(const String &a, const String &b)
U32 lena = a.length();
U32 lenb = b.length();
String::StringData *sub = new ( lena + lenb ) String::StringData( NULL );
String::StringData* sub = String::StringData::Create(NULL, lena + lenb);
String::copy(sub->utf8(),a._string->utf8(),lena);
String::copy(sub->utf8() + lena,b._string->utf8(),lenb + 1);
@ -848,7 +814,7 @@ String operator+(const String &a, StringChar c)
//PROFILE_SCOPE( String_String_plus_Char );
U32 lena = a.length();
String::StringData *sub = new ( lena + 1 ) String::StringData( NULL );
String::StringData* sub = String::StringData::Create(NULL, lena + 1);
String::copy(sub->utf8(),a._string->utf8(),lena);
@ -863,7 +829,7 @@ String operator+(StringChar c, const String &a)
//PROFILE_SCOPE( String_Char_plus_String );
U32 lena = a.length();
String::StringData *sub = new ( lena + 1 ) String::StringData( NULL );
String::StringData* sub = String::StringData::Create(NULL, lena + 1);
String::copy(sub->utf8() + 1,a._string->utf8(),lena + 1);
sub->utf8()[0] = c;
@ -886,7 +852,7 @@ String operator+(const String &a, const StringChar *b)
if( !lenb )
return a;
String::StringData *sub = new ( lena + lenb ) String::StringData( NULL );
String::StringData* sub = String::StringData::Create(NULL, lena + lenb);
String::copy(sub->utf8(),a._string->utf8(),lena);
String::copy(sub->utf8() + lena,b,lenb + 1);
@ -908,7 +874,7 @@ String operator+(const StringChar *a, const String &b)
U32 lenb = b.length();
String::StringData* sub = new ( lena + lenb ) String::StringData( NULL );
String::StringData* sub = String::StringData::Create(NULL, lena + lenb);
String::copy(sub->utf8(),a,lena);
String::copy(sub->utf8() + lena,b._string->utf8(),lenb + 1);
@ -1117,7 +1083,7 @@ String& String::insert(SizeType pos, const StringChar *str, SizeType len)
sub = StringData::Empty();
else
{
sub = new ( newlen ) StringData( NULL );
sub = StringData::Create(NULL, newlen);
String::copy(sub->utf8(),_string->utf8(),pos);
String::copy(sub->utf8() + pos,str,len);
@ -1146,7 +1112,7 @@ String& String::erase(SizeType pos, SizeType len)
sub = StringData::Empty();
else
{
sub = new ( newlen ) StringData( NULL );
sub = StringData::Create(NULL, newlen);
if (pos > 0)
String::copy(sub->utf8(),_string->utf8(),pos);
@ -1176,7 +1142,7 @@ String& String::replace(SizeType pos, SizeType len, const StringChar *str)
sub = StringData::Empty();
else
{
sub = new ( newlen ) StringData( NULL );
sub = StringData::Create(NULL, newlen);
String::copy(sub->utf8(),_string->utf8(), pos);
String::copy(sub->utf8() + pos,str,rlen);
@ -1207,7 +1173,8 @@ String& String::replace( StringChar c1, StringChar c2 )
{
if( !foundReplacement )
{
sub = new ( length() ) StringData( _string->utf8() );
sub = StringData::Create(_string->utf8(), length());
c = &sub->utf8()[ c - _string->utf8() ];
foundReplacement = true;
}
@ -1261,7 +1228,7 @@ String &String::replace(const String &s1, const String &s2)
sub = StringData::Empty();
else
{
sub = new (newSize - 1 ) StringData( NULL );
sub = StringData::Create(NULL, newSize - 1);
// Now assemble the new string from the pieces of the old...
@ -1327,7 +1294,7 @@ String String::substr(SizeType pos, SizeType len) const
if( !len )
sub = StringData::Empty();
else
sub = new ( len ) StringData( _string->utf8() + pos );
sub = StringData::Create(_string->utf8() + pos, len);
return sub;
}
@ -1356,7 +1323,7 @@ String String::trim() const
if( !len )
sub = StringData::Empty();
else
sub = new ( len ) StringData( start );
sub = StringData::Create(start, len);
return sub;
}
@ -1573,7 +1540,7 @@ String String::VToString(const char* str, va_list args)
sub = StringData::Empty();
else
{
sub = new ( len ) StringData( NULL );
sub = StringData::Create(NULL, len);
format.copy( sub->utf8() );
sub->utf8()[ len ] = 0;
@ -1590,7 +1557,7 @@ String String::SpanToString(const char *start, const char *end)
AssertFatal( end > start, "Invalid arguments to String::SpanToString - end is before start" );
U32 len = U32(end - start);
StringData* sub = new ( len ) StringData( start );
String::StringData* sub = StringData::Create(start, len);
return sub;
}
@ -1600,7 +1567,8 @@ String String::ToLower(const String &string)
if ( string.isEmpty() )
return String();
StringData* sub = new ( string.length() ) StringData( string );
String::StringData* sub = StringData::Create(string, string.length());
dStrlwr( sub->utf8() );
return sub;
@ -1611,7 +1579,8 @@ String String::ToUpper(const String &string)
if ( string.isEmpty() )
return String();
StringData* sub = new ( string.length() ) StringData( string );
String::StringData* sub = StringData::Create(string, string.length());
dStrupr( sub->utf8() );
return sub;

View file

@ -160,7 +160,6 @@ class Vector
void erase(U32 index, U32 count);
void erase_fast(iterator);
void clear();
void resetAndTreatAsScratchBuffer();
void compact();
void sort(compare_func f);
void fill( const T& value );
@ -530,15 +529,6 @@ template<class T> inline void Vector<T>::clear()
mElementCount = 0;
}
/// This method sets the vector as its 0 and will overwrite memory on subsequent usage.
/// Note that the current memory in use is never freed or deallocated, so only use this if the vector
/// is being used as a scratch buffer only.
template<class T> inline
void Vector<T>::resetAndTreatAsScratchBuffer()
{
mElementCount = 0;
}
template<class T> inline void Vector<T>::compact()
{
resize(mElementCount);

View file

@ -904,10 +904,6 @@ S32 MountSystem::findByPattern( const Path &inBasePath, const String &inFilePatt
while ( dir->read( &attrs ) )
{
// skip hidden files
if ( attrs.name.c_str()[0] == '.' )
continue;
String name( attrs.name );
if ( (attrs.flags & FileNode::Directory) && inRecursive )

View file

@ -734,7 +734,7 @@ void DecalRoad::prepRenderImage( SceneRenderState* state )
coreRI.sortDistSq = F32_MAX;
// If we need lights then set them up.
if ( matInst->isForwardLit() )
if ( matInst->isForwardLit() && !coreRI.lights[0])
{
LightQuery query;
query.init( getWorldSphere() );
@ -784,6 +784,7 @@ void DecalRoad::prepRenderImage( SceneRenderState* state )
*ri = coreRI;
ri->matInst = matInst;
ri->prim = renderPass->allocPrim();
ri->prim->type = GFXTriangleList;
ri->prim->minIndex = 0;
@ -791,6 +792,7 @@ void DecalRoad::prepRenderImage( SceneRenderState* state )
ri->prim->numPrimitives = triangleCount;
ri->prim->startVertex = 0;
ri->prim->numVertices = endBatch.endVert + 1;
ri->translucentSort = !matInst->getMaterial()->isTranslucent();
// For sorting we first sort by render priority
// and then by objectId.

View file

@ -651,7 +651,7 @@ void ScatterSky::prepRenderImage( SceneRenderState *state )
ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind( this, &ScatterSky::_render );
ri->type = RenderPassManager::RIT_Sky;
ri->defaultKey = 10;
ri->defaultKey = 15;
ri->defaultKey2 = 0;
renderPass->addInst(ri);
@ -700,7 +700,7 @@ void ScatterSky::prepRenderImage( SceneRenderState *state )
moonRI->renderDelegate.bind( this, &ScatterSky::_renderMoon );
moonRI->type = RenderPassManager::RIT_Sky;
// Render after sky objects and before CloudLayer!
moonRI->defaultKey = 5;
moonRI->defaultKey = 10;
moonRI->defaultKey2 = 0;
renderPass->addInst(moonRI);
}
@ -758,73 +758,146 @@ bool ScatterSky::_initShader()
return true;
}
void ScatterSky::clearVectors()
{
tmpVertices.clear();
vertsVec.clear();
}
void ScatterSky::addVertex(Point3F vert)
{
vertsVec.push_back(vert.x);
vertsVec.push_back(vert.y);
vertsVec.push_back(vert.z);
}
void ScatterSky::BuildFinalVert()
{
U32 count = vertsVec.size();
U32 i, j;
for (i = 0, j = 0; i < count; i += 3, j += 2)
{
FinalVertexData temp;
temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
finalVertData.push_back(temp);
}
}
void ScatterSky::_initVBIB()
{
U32 rings = 18;
U32 height = 9;
U32 radius = 10;
F32 x, y, z, xy; // vertex position
F32 ringStep = M_2PI / rings;
F32 heightStep = M_HALFPI / height; // M_PI for full sphere.
F32 ringAng, heightAng;
//clear vecs
clearVectors();
for (U32 i = 0; i <= height; ++i)
{
heightAng = M_PI / 2 - (F32)i * heightStep;
xy = radius * mCos(heightAng);
z = radius * mSin(heightAng);
for (U32 j = 0; j <= rings; ++j)
{
SphereVertex vert;
ringAng = j * ringStep;
x = xy * mCos(ringAng);
y = xy * mSin(ringAng);
vert.pos.set(Point3F(x, y, z));
tmpVertices.push_back(vert);
}
}
SphereVertex v1, v2, v3, v4;
U32 vi1, vi2 = 0;
for (U32 i = 0; i < height; ++i)
{
vi1 = i * (rings + 1);
vi2 = (i + 1) * (rings + 1);
for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
{
v1 = tmpVertices[vi1];
v2 = tmpVertices[vi2];
v3 = tmpVertices[vi1 + 1];
v4 = tmpVertices[vi2 + 1];
// 1st = triangle.
if (i == 0)
{
// verts for tri.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v4.pos);
}
/* UNCOMMENT WHEN FULL SPHERE
else if (i == (height - 1))
{
// verts for tri.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v3.pos);
}*/
else
{
// verts for quad.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v3.pos);
addVertex(v3.pos);
addVertex(v4.pos);
addVertex(v2.pos);
}
}
}
BuildFinalVert();
// Vertex Buffer...
U32 vertStride = 50;
U32 strideMinusOne = vertStride - 1;
mVertCount = vertStride * vertStride;
mPrimCount = strideMinusOne * strideMinusOne * 2;
Point3F vertScale( 16.0f, 16.0f, 4.0f );
F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
mVertCount = finalVertData.size();
mPrimCount = mVertCount / 3;
mVB.set( GFX, mVertCount, GFXBufferTypeStatic );
GFXVertexP *pVert = mVB.lock();
if(!pVert) return;
for ( U32 y = 0; y < vertStride; y++ )
for ( U32 i = 0; i < mVertCount; i++ )
{
F32 v = ( (F32)y / (F32)strideMinusOne - 0.5f ) * 2.0f;
for ( U32 x = 0; x < vertStride; x++ )
{
F32 u = ( (F32)x / (F32)strideMinusOne - 0.5f ) * 2.0f;
F32 sx = u;
F32 sy = v;
F32 sz = (mCos( mSqrt( sx*sx + sy*sy ) ) * 1.0f) + zOffset;
//F32 sz = 1.0f;
pVert->point.set( sx, sy, sz );
pVert->point *= vertScale;
pVert->point.set(finalVertData[i].pos);
pVert->point.normalize();
pVert->point *= 200000.0f;
pVert++;
}
}
mVB.unlock();
// Primitive Buffer...
mPrimBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic );
mPrimBuffer.set( GFX, mVertCount, mPrimCount, GFXBufferTypeStatic );
U16 *pIdx = NULL;
mPrimBuffer.lock(&pIdx);
U32 curIdx = 0;
for ( U32 y = 0; y < strideMinusOne; y++ )
for ( U32 i = 0, k = 0; i < mPrimCount; i++, k+=3 )
{
for ( U32 x = 0; x < strideMinusOne; x++ )
{
U32 offset = x + y * vertStride;
pIdx[curIdx] = offset;
pIdx[curIdx] = k;
curIdx++;
pIdx[curIdx] = offset + 1;
pIdx[curIdx] = k + 1;
curIdx++;
pIdx[curIdx] = offset + vertStride + 1;
pIdx[curIdx] = k + 2;
curIdx++;
pIdx[curIdx] = offset;
curIdx++;
pIdx[curIdx] = offset + vertStride + 1;
curIdx++;
pIdx[curIdx] = offset + vertStride;
curIdx++;
}
}
mPrimBuffer.unlock();
@ -963,21 +1036,17 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
Point3F camPos2 = state->getCameraPosition();
MatrixF xfm(true);
xfm.setPosition(camPos2 - Point3F(0, 0, mZOffset));
xfm.setPosition(Point3F(
camPos2.x,
camPos2.y,
mZOffset) );
GFX->multWorld(xfm);
MatrixF xform(proj);//GFX->getProjectionMatrix());
xform *= GFX->getViewMatrix();
xform *= GFX->getWorldMatrix();
if(state->isReflectPass())
{
static MatrixF rotMat(EulerF(0.0, 0.0, M_PI_F));
xform.mul(rotMat);
rotMat.set(EulerF(M_PI_F, 0.0, 0.0));
xform.mul(rotMat);
}
mShaderConsts->setSafe( mModelViewProjSC, xform );
mShaderConsts->setSafe( mMiscSC, miscParams );
mShaderConsts->setSafe( mSphereRadiiSC, sphereRadii );

View file

@ -104,6 +104,27 @@ public:
///
F32 getElevation() const { return mSunElevation; }
struct SphereVertex
{
Point3F pos;
};
Vector<SphereVertex> tmpVertices;
Vector<F32> vertsVec;
struct FinalVertexData
{
Point3F pos;
};
Vector<FinalVertexData> finalVertData;
void addVertex(Point3F vert);
void BuildFinalVert();
void clearVectors();
protected:
void _render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );

View file

@ -645,4 +645,4 @@ BaseMatInstance* SkyBox::_getMaterialInstance()
DefineEngineMethod( SkyBox, postApply, void, (), , "")
{
object->inspectPostApply();
}
}

View file

@ -0,0 +1,645 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "environment/skySphere.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxTransformSaver.h"
#include "core/stream/fileStream.h"
#include "core/stream/bitStream.h"
#include "materials/materialManager.h"
#include "materials/materialFeatureTypes.h"
#include "materials/sceneData.h"
#include "T3D/gameFunctions.h"
#include "renderInstance/renderBinManager.h"
#include "materials/processedMaterial.h"
#include "gfx/gfxDebugEvent.h"
#include "math/util/matrixSet.h"
IMPLEMENT_CO_NETOBJECT_V1(SkySphere);
ConsoleDocClass(SkySphere,
"@brief Represents the sky with an artist-created spherical map.\n\n"
"SkySphere is not a directional light and should be used in conjunction with a Sun object.\n\n"
"@ingroup Atmosphere"
);
SkySphere::SkySphere()
{
mTypeMask |= EnvironmentObjectType | StaticObjectType;
mNetFlags.set(Ghostable | ScopeAlways);
INIT_ASSET(Material);
mMatInstance = NULL;
mIsVBDirty = false;
mPrimCount = 0;
mFogBandHeight = 0;
mFogPrimCount = 0;
mMatrixSet = reinterpret_cast<MatrixSet*>(dMalloc_aligned(sizeof(MatrixSet), 16));
constructInPlace(mMatrixSet);
mFogBandMat = NULL;
mFogBandMatInst = NULL;
}
SkySphere::~SkySphere()
{
dFree_aligned(mMatrixSet);
if (mMatInstance)
SAFE_DELETE(mMatInstance);
SAFE_DELETE(mFogBandMatInst);
if (mFogBandMat)
{
mFogBandMat->deleteObject();
mFogBandMat = NULL;
}
}
bool SkySphere::onAdd()
{
if (!Parent::onAdd())
return false;
setGlobalBounds();
resetWorldBox();
addToScene();
if (isClientObject())
{
_initRender();
_updateMaterial();
}
return true;
}
void SkySphere::onRemove()
{
removeFromScene();
Parent::onRemove();
}
void SkySphere::initPersistFields()
{
addGroup("Sky Sphere");
INITPERSISTFIELD_MATERIALASSET(Material, SkySphere, "The name of a cubemap material for the sky box.");
addField("fogBandHeight", TypeF32, Offset(mFogBandHeight, SkySphere),
"The height (0-1) of the fog band from the horizon to the top of the SkySphere.");
endGroup("Sky Sphere");
Parent::initPersistFields();
}
void SkySphere::inspectPostApply()
{
Parent::inspectPostApply();
_updateMaterial();
}
U32 SkySphere::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(conn, mask, stream);
PACK_ASSET(conn, Material);
stream->write(mFogBandHeight);
return retMask;
}
void SkySphere::unpackUpdate(NetConnection* conn, BitStream* stream)
{
Parent::unpackUpdate(conn, stream);
StringTableEntry oldMatName = getMaterial();
UNPACK_ASSET(conn, Material);
if (oldMatName != getMaterial())
{
_updateMaterial();
}
F32 bandHeight = 0;
stream->read(&bandHeight);
// If this flag has changed
// we need to update the vertex buffer.
if ( bandHeight != mFogBandHeight)
{
mFogBandHeight = bandHeight;
mIsVBDirty = true;
_initRender();
}
}
void SkySphere::prepRenderImage(SceneRenderState* state)
{
PROFILE_SCOPE(SkySphere_prepRenderImage);
if (state->isShadowPass() ||
mVB.isNull() ||
mFogBandVB.isNull() ||
!mMatInstance)
return;
mMatrixSet->setSceneView(GFX->getWorldMatrix());
mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
ri->renderDelegate.bind(this, &SkySphere::_renderObject);
ri->type = RenderPassManager::RIT_Sky;
ri->defaultKey = 9;
ri->defaultKey2 = 0;
state->getRenderPass()->addInst(ri);
}
void SkySphere::_renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi)
{
GFXDEBUGEVENT_SCOPE(SkySphere_RenderObject, ColorI::WHITE);
GFXTransformSaver saver;
GFX->setVertexBuffer(mVB);
MatrixF worldMat = MatrixF::Identity;
worldMat.setPosition(Point3F(
state->getCameraPosition().x,
state->getCameraPosition().y,
state->getCameraPosition().z));
SceneData sgData;
sgData.init(state);
sgData.objTrans = &worldMat;
mMatrixSet->restoreSceneViewProjection();
mMatrixSet->setWorld(worldMat);
if (state->isReflectPass())
mMatrixSet->setProjection(state->getSceneManager()->getNonClipProjection());
while (mMatInstance->setupPass(state, sgData))
{
mMatInstance->setTransforms(*mMatrixSet, state);
mMatInstance->setSceneInfo(state, sgData);
GFX->drawPrimitive(GFXTriangleList, 0, mPrimCount);
}
// Draw render band.
if (mFogBandHeight > 0 && mFogBandMatInst)
{
const FogData& fog = state->getSceneManager()->getFogData();
if (mLastFogColor != fog.color)
{
mLastFogColor = fog.color;
_initRender();
}
// Just need it to follow the camera... no rotation.
MatrixF camPosMat(MatrixF::Identity);
camPosMat.setPosition(worldMat.getPosition());
sgData.objTrans = &camPosMat;
mMatrixSet->setWorld(*sgData.objTrans);
while (mFogBandMatInst->setupPass(state, sgData))
{
mFogBandMatInst->setTransforms(*mMatrixSet, state);
mFogBandMatInst->setSceneInfo(state, sgData);
GFX->setVertexBuffer(mFogBandVB);
GFX->drawPrimitive(GFXTriangleList, 0, mFogPrimCount);
}
}
}
void SkySphere::clearVectors()
{
tmpVertices.clear();
finalFogVertex.clear();
tempFogVertex.clear();
colVec.clear();
fogVerts.clear();
vertsVec.clear();
normsVec.clear();
texCoordVec.clear();
finalVertData.clear();
}
void SkySphere::addVertex(Point3F vert)
{
vertsVec.push_back(vert.x);
vertsVec.push_back(vert.y);
vertsVec.push_back(vert.z);
}
void SkySphere::addNormal(Point3F nor)
{
normsVec.push_back(nor.x);
normsVec.push_back(nor.y);
normsVec.push_back(nor.z);
}
void SkySphere::addTexcoord(F32 s, F32 t)
{
texCoordVec.push_back(s);
texCoordVec.push_back(t);
}
void SkySphere::addColor(ColorI col)
{
colVec.push_back(col);
}
void SkySphere::BuildFinalVert()
{
U32 count = vertsVec.size();
U32 i, j;
for (i = 0, j = 0; i < count; i += 3, j += 2)
{
FinalVertexData temp;
temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
temp.nor.set(Point3F(normsVec[i], normsVec[i + 1], normsVec[i + 2]));
temp.s = texCoordVec[j];
temp.t = texCoordVec[j+1];
finalVertData.push_back(temp);
}
}
void SkySphere::BuildFinalFogVert()
{
U32 count = vertsVec.size();
U32 i, j;
for (i = 0, j = 0; i < count; i+=3, j++ )
{
FogVertex temp;
temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
temp.col = colVec[j];
finalFogVertex.push_back(temp);
}
}
void SkySphere::_initRender()
{
U32 rings = 32;
U32 height = 16;
U32 radius = 1;
F32 x, y, z, xy; // vertex position
F32 nx, ny, nz, lengthInv = 1.0f / radius; // normal
F32 s, t; // texCoord
F32 ringStep = M_2PI / rings;
F32 heightStep = M_PI / height; // M_HALFPI for dome.
F32 ringAng, heightAng;
//clear vecs
clearVectors();
for (U32 i = 0; i <= height; ++i)
{
heightAng = M_PI / 2 - (F32)i * heightStep;
F32 xy = radius * mCos(heightAng);
F32 z = radius * mSin(heightAng);
for (U32 j = 0; j <= rings; ++j)
{
SphereVertex vert;
ringAng = j * ringStep;
x = xy * mCos(ringAng);
y = xy * mSin(ringAng);
vert.pos.set(Point3F(x,y,z));
nx = x * lengthInv;
ny = y * lengthInv;
nz = z * lengthInv;
vert.nor.set(Point3F(nx, ny, nz));
s = (F32)j / rings;
t = (F32)i / height;
vert.s = s;
vert.t = t;
tmpVertices.push_back(vert);
}
}
SphereVertex v1, v2, v3, v4;
U32 vi1, vi2 = 0;
for (U32 i = 0; i < height; ++i)
{
vi1 = i * (rings + 1);
vi2 = (i + 1) * (rings + 1);
for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
{
v1 = tmpVertices[vi1];
v2 = tmpVertices[vi2];
v3 = tmpVertices[vi1 + 1];
v4 = tmpVertices[vi2 + 1];
// 1st = triangle.
if (i == 0)
{
// verts for tri.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v4.pos);
// texcoords for tri.
addTexcoord(v1.s, v1.t);
addTexcoord(v2.s, v2.t);
addTexcoord(v4.s, v4.t);
// normals for tri.
addNormal(v1.nor);
addNormal(v2.nor);
addNormal(v4.nor);
}
else if (i == (height - 1))
{
// verts for tri.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v3.pos);
// texcoords for tri.
addTexcoord(v1.s, v1.t);
addTexcoord(v2.s, v2.t);
addTexcoord(v3.s, v3.t);
// normals for quad.
addNormal(v1.nor);
addNormal(v2.nor);
addNormal(v3.nor);
}
else
{
// verts for quad.
addVertex(v1.pos);
addVertex(v2.pos);
addVertex(v3.pos);
addVertex(v3.pos);
addVertex(v4.pos);
addVertex(v2.pos);
// texcoords for quad.
addTexcoord(v1.s, v1.t);
addTexcoord(v2.s, v2.t);
addTexcoord(v3.s, v3.t);
addTexcoord(v3.s, v3.t);
addTexcoord(v4.s, v4.t);
addTexcoord(v2.s, v2.t);
// normals for quad.
addNormal(v1.nor);
addNormal(v2.nor);
addNormal(v3.nor);
addNormal(v3.nor);
addNormal(v4.nor);
addNormal(v2.nor);
}
}
}
BuildFinalVert();
GFXVertexPNT* tmpVerts = NULL;
U32 vertCount = finalVertData.size();
tmpVerts = new GFXVertexPNT[(vertCount)];
mPrimCount = vertCount / 3;
for (U32 i = 0; i < vertCount; i++)
{
tmpVerts[i].point.set(finalVertData[i].pos);
tmpVerts[i].normal.set(finalVertData[i].nor);
tmpVerts[i].texCoord.set(finalVertData[i].s, finalVertData[i].t);
}
if (mVB.isNull() || mIsVBDirty)
{
mVB.set(GFX, vertCount, GFXBufferTypeStatic);
mIsVBDirty = false;
}
GFXVertexPNT* vertPtr = mVB.lock();
if (!vertPtr)
{
delete[] tmpVerts;
return;
}
dMemcpy(vertPtr, tmpVerts, sizeof(GFXVertexPNT) * vertCount);
mVB.unlock();
// Clean up temp verts.
delete[] tmpVerts;
// Grab the fog color.
ColorI fogColor(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255);
ColorI fogColorAlpha(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0);
clearVectors();
U32 stepCount = 16;
F32 cylStep = M_2PI / stepCount;
F32 cylAngle;
F32 cylRadius = 10;
for (U32 i = 0; i <= stepCount; ++i)
{
cylAngle = (F32)i * cylStep;
fogVerts.push_back(mCos(cylAngle));
fogVerts.push_back(mSin(cylAngle));
}
for (U32 i = 0; i < 2; ++i)
{
for (U32 j = 0, k = 0; j <= stepCount; ++j, k += 2)
{
FogVertex temp;
F32 ux = fogVerts[k];
F32 uy = fogVerts[k+1];
if (i > 0)
{
temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), mFogBandHeight));
temp.col = fogColorAlpha;
}
else
{
temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), -mFogBandHeight));
temp.col = fogColor;
}
tempFogVertex.push_back(temp);
}
}
FogVertex f1, f2, f3, f4;
U32 k1 = 0;
U32 k2 = stepCount + 1;
for (U32 i = 0; i < stepCount; ++i, ++k1, ++k2)
{
f1 = tempFogVertex[k1];
f2 = tempFogVertex[k1 + 1];
f3 = tempFogVertex[k2];
f4 = tempFogVertex[k2 + 1];
addVertex(f3.pos);
addVertex(f2.pos);
addVertex(f4.pos);
addColor(f3.col);
addColor(f2.col);
addColor(f4.col);
addVertex(f1.pos);
addVertex(f2.pos);
addVertex(f3.pos);
addColor(f1.col);
addColor(f2.col);
addColor(f3.col);
}
BuildFinalFogVert();
U32 fogVertCount = finalFogVertex.size();
mFogPrimCount = fogVertCount / 3;
if (mFogBandVB.isNull())
mFogBandVB.set(GFX, fogVertCount, GFXBufferTypeStatic);
GFXVertexPC* bandVertPtr = mFogBandVB.lock();
if (!bandVertPtr) return;
for (U32 i = 0; i < fogVertCount; i++)
{
bandVertPtr[i].point.set(finalFogVertex[i].pos);
bandVertPtr[i].color.set(finalFogVertex[i].col);
}
mFogBandVB.unlock();
SAFE_DELETE(mFogBandMatInst);
if (mFogBandMat)
{
mFogBandMat->deleteObject();
mFogBandMat = NULL;
}
// Setup the material for this imposter.
mFogBandMat = MATMGR->allocateAndRegister(String::EmptyString);
mFogBandMat->mAutoGenerated = true;
mFogBandMat->mTranslucent = true;
mFogBandMat->mVertColor[0] = true;
mFogBandMat->mDoubleSided = true;
mFogBandMat->mEmissive[0] = true;
FeatureSet features = MATMGR->getDefaultFeatures();
features.addFeature(MFT_isBackground);
mFogBandMatInst = mFogBandMat->createMatInstance();
mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>());
}
void SkySphere::onStaticModified(const char* slotName, const char* newValue)
{
Parent::onStaticModified(slotName, newValue);
if (dStricmp(slotName, "material") == 0)
setMaskBits(0xFFFFFFFF);
}
void SkySphere::_initMaterial()
{
if (mMatInstance)
SAFE_DELETE(mMatInstance);
if (mMaterial)
mMatInstance = mMaterial->createMatInstance();
else
mMatInstance = MATMGR->createMatInstance("WarningMaterial");
// We want to disable culling and z write.
GFXStateBlockDesc desc;
desc.setCullMode(GFXCullNone);
desc.setBlend(true);
desc.setZReadWrite(true, false);
desc.zFunc = GFXCmpLessEqual;
mMatInstance->addStateBlockDesc(desc);
// Also disable lighting on the skysphere material by default.
FeatureSet features = MATMGR->getDefaultFeatures();
features.removeFeature(MFT_RTLighting);
features.removeFeature(MFT_Visibility);
features.addFeature(MFT_isBackground);
// Now initialize the material.
mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
}
void SkySphere::_updateMaterial()
{
if (!getMaterialResource().isValid())
{
//If our materialDef isn't valid, try setting it
_setMaterial(getMaterial());
}
if (getMaterialResource().isValid())
{
_initMaterial();
}
}
BaseMatInstance* SkySphere::_getMaterialInstance()
{
if (!mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial)
_initMaterial();
if (!mMatInstance)
return NULL;
return mMatInstance;
}
DefineEngineMethod(SkySphere, postApply, void, (), , "")
{
object->inspectPostApply();
}

View file

@ -0,0 +1,172 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _SKYSPHERE_H_
#define _SKYSPHERE_H_
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _CUBEMAPDATA_H_
#include "gfx/sim/cubemapData.h"
#endif
#ifndef _MATERIALLIST_H_
#include "materials/materialList.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#include "T3D/assets/MaterialAsset.h"
struct SkyMatParams
{
void init(BaseMatInstance* matInst) {};
};
class MatrixSet;
class SkySphere : public SceneObject
{
typedef SceneObject Parent;
public:
SkySphere();
virtual ~SkySphere();
DECLARE_CONOBJECT(SkySphere);
// SimObject
void onStaticModified(const char* slotName, const char* newValue);
// ConsoleObject
virtual bool onAdd();
virtual void onRemove();
static void initPersistFields();
virtual void inspectPostApply();
// NetObject
virtual U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream);
virtual void unpackUpdate(NetConnection* conn, BitStream* stream);
// SceneObject
void prepRenderImage(SceneRenderState* state);
/// Our render delegate.
void _renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi);
void clearVectors();
void addVertex(Point3F vert);
void addNormal(Point3F nor);
void addTexcoord(F32 s, F32 t);
void addColor(ColorI col);
void BuildFinalVert();
void BuildFinalFogVert();
/// Prepares rendering structures and geometry.
void _initRender();
struct SphereVertex
{
Point3F pos;
Point3F nor;
F32 s, t;
};
Vector<SphereVertex> tmpVertices;
Vector<F32> vertsVec;
Vector<F32> texCoordVec;
Vector<F32> normsVec;
struct FinalVertexData
{
Point3F pos;
Point3F nor;
F32 s;
F32 t;
};
Vector<FinalVertexData> finalVertData;
struct FogVertex
{
// might need normals for smoothing.
Point3F pos;
ColorI col;
};
Vector<FogVertex> finalFogVertex;
Vector<FogVertex> tempFogVertex;
Vector<ColorI> colVec;
Vector<F32> fogVerts;
protected:
// Material
DECLARE_MATERIALASSET(SkySphere, Material);
DECLARE_ASSET_NET_SETGET(SkySphere, Material, -1);
BaseMatInstance* mMatInstance;
SkyMatParams mMatParamHandle;
GFXVertexBufferHandle<GFXVertexPNT> mVB;
GFXVertexBufferHandle<GFXVertexPC> mFogBandVB;
Material* mFogBandMat;
BaseMatInstance* mFogBandMatInst;
LinearColorF mLastFogColor;
bool mIsVBDirty;
U32 mPrimCount;
MatrixSet* mMatrixSet;
F32 mFogBandHeight;
U32 mFogPrimCount;
void _updateMaterial();
void _initMaterial();
BaseMatInstance* _getMaterialInstance();
};
#endif

View file

@ -197,4 +197,78 @@ DefineEngineMethod( ForestBrush, containsItemData, bool, ( const char * obj ), ,
}
return object->containsItemData( data );
}
}
//-------------------------------------------------------------------------
// ForestBrushGroupSet
//-------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(ForestBrushGroup);
ConsoleDocClass(ForestBrushGroup,
"@brief Container class for ForestBrushes\n\n"
"Editor use only.\n\n"
"@internal"
);
ForestBrushGroup::ForestBrushGroup()
{
}
bool ForestBrushGroup::onAdd()
{
if (!Parent::onAdd())
return false;
SimSet* forestBrushSet;
if (!Sim::findObject("ForestBrushSet", forestBrushSet))
{
Con::errorf("ForestBrushGroup::onAdd() - failed to find ForestBrushSet to add new ForestBrushGroup to!");
}
forestBrushSet->addObject(this);
return true;
}
void ForestBrushGroup::addObject(SimObject* inObj)
{
ForestBrush* ele = dynamic_cast<ForestBrush*>(inObj);
if (!ele)
return;
//if ( containsItemData( ele->mData ) )
// return;
Parent::addObject(inObj);
}
bool ForestBrushGroup::containsBrushData(const ForestBrush* inData)
{
SimObjectList::iterator iter = mObjectList.begin();
for (; iter != mObjectList.end(); iter++)
{
ForestBrush* pElement = dynamic_cast<ForestBrush*>(*iter);
if (!pElement)
continue;
if (pElement == inData)
return true;
}
return false;
}
DefineEngineMethod(ForestBrushGroup, containsBrushData, bool, (const char* obj), , "( ForestBrush obj )")
{
ForestBrush* data = NULL;
if (!Sim::findObject(obj, data))
{
Con::warnf("ForestBrush::containsBrushData - invalid object passed");
return false;
}
return object->containsBrushData(data);
}

View file

@ -121,5 +121,28 @@ protected:
static SimObjectPtr<SimGroup> smGroup;
};
//-------------------------------------------------------------------------
// ForestBrushGroup
//-------------------------------------------------------------------------
#endif // _FOREST_EDITOR_BRUSHELEMENT_H_
class ForestBrushGroup : public SimGroup
{
typedef SimGroup Parent;
public:
ForestBrushGroup();
DECLARE_CONOBJECT(ForestBrushGroup);
virtual bool onAdd();
virtual void addObject(SimObject*);
bool containsBrushData(const ForestBrush* inData);
protected:
static SimObjectPtr<SimGroup> smGroup;
};
#endif // _FOREST_EDITOR_BRUSHELEMENT_H_

View file

@ -610,9 +610,14 @@ void ForestBrushTool::_collectElements()
}
// Find all ForestBrushElements that are directly or indirectly selected.
SimSet* brushSet;
if (!Sim::findObject("ForestBrushSet", brushSet))
{
Con::errorf("ForestBrushTool::_collectElements() - could not find ForestBrushSet!");
return;
}
SimGroup *brushGroup = ForestBrush::getGroup();
brushGroup->findObjectByCallback( findSelectedElements, mElements );
brushSet->findObjectByCallback( findSelectedElements, mElements );
// We just needed to flag these objects as selected for the benefit of our
// findSelectedElements callback, we can now mark them un-selected again.

View file

@ -328,10 +328,16 @@ void ForestEditorCtrl::deleteMeshSafe( ForestItemData *mesh )
}
// Find ForestBrushElement(s) referencing this datablock.
SimGroup *brushGroup = ForestBrush::getGroup();
SimSet* brushSet;
if (!Sim::findObject("ForestBrushSet", brushSet))
{
Con::errorf("ForestBrushTool::_collectElements() - could not find ForestBrushSet!");
return;
}
sKey = mesh;
Vector<SimObject*> foundElements;
brushGroup->findObjectByCallback( &findMeshReferences, foundElements );
brushSet->findObjectByCallback( &findMeshReferences, foundElements );
// Add UndoAction to delete the ForestBrushElement(s) and the ForestItemData.
MEDeleteUndoAction *elementAction = new MEDeleteUndoAction();
@ -408,4 +414,4 @@ DefineEngineMethod(ForestEditorCtrl, setActiveForest, void, (const char * obj),
return;
object->setActiveForest(forestObject);
}
}

View file

@ -32,6 +32,7 @@
#include "console/console.h"
#include "platform/profiler.h"
#include "console/engineAPI.h"
#include "gfx/bitmap/ddsFile.h"
using namespace Torque;
@ -1361,44 +1362,78 @@ DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),,
image->getFormat());
}
DefineEngineFunction(saveScaledImage, bool, (const char* bitmapSource, const char* bitmapDest, S32 resolutionSize), ("", "", 512),
"Returns image info in the following format: width TAB height TAB bytesPerPixel TAB format. "
"It will return an empty string if the file is not found.\n"
"@ingroup Rendering\n")
DefineEngineFunction(saveScaledImage, bool, (const char* bitmapSource, const char* bitmapDest, S32 resolutionSize), ("", "", 256),
"Loads an image from the source path, and scales it down to the target resolution before"
"Saving it out to the destination path.\n")
{
Resource<GBitmap> image = GBitmap::load(bitmapSource);
if (!image)
return false;
bool isDDS = false;
Torque::Path sourcePath = Torque::Path(bitmapSource);
/*if (String("dds").equal(sourcePath.getExtension(), String::NoCase))
if (bitmapSource == 0 || bitmapSource[0] == '\0' || bitmapDest == 0 || bitmapDest[0] == '\0')
{
dds = DDSFile::load(correctPath, scalePower);
return false;
}
if (!Platform::isFile(bitmapSource))
{
return false;
}
//First, gotta check the extension, as we have some extra work to do if it's
//a DDS file
const char* ret = dStrrchr(bitmapSource, '.');
if (ret)
{
if (String::ToLower(ret) == String(".dds"))
isDDS = true;
}
else
{
return false; //no extension? bail out
}
GBitmap* image = NULL;
if (isDDS)
{
Resource<DDSFile> dds = DDSFile::load(bitmapSource, 0);
if (dds != NULL)
{
image = new GBitmap();
if (!dds->decompressToGBitmap(image))
{
delete image;
image = NULL;
return false;
}
}
}*/
if (isPow2(image->getWidth())&& isPow2(image->getHeight()))
}
else
{
Resource<GBitmap> resImage = GBitmap::load(bitmapSource);
image = new GBitmap(*resImage);
}
if (!image)
return false;
Torque::Path sourcePath = Torque::Path(bitmapSource);
if (isPow2(image->getWidth()) && isPow2(image->getHeight()))
image->extrudeMipLevels();
U32 mipCount = image->getNumMipLevels();
U32 targetMips = mFloor(mLog2((F32)resolutionSize)) + 1;
U32 targetMips = mFloor(mLog2((F32)(resolutionSize ? resolutionSize : 256))) + 1;
if (mipCount > targetMips)
{
image->chopTopMips(mipCount - targetMips);
}
//TODO: support different format targets, for now we just force
//to png for simplicity
Torque::Path destinationPath = Torque::Path(bitmapDest);
destinationPath.setExtension("png");
// Open up the file on disk.
FileStream fs;
if (!fs.open(bitmapDest, Torque::FS::File::Write))
if (!fs.open(destinationPath.getFullPath(), Torque::FS::File::Write))
{
Con::errorf("saveScaledImage() - Failed to open output file '%s'!", bitmapDest);
return false;

View file

@ -46,7 +46,7 @@ void GFXCardProfiler::loadProfileScript(const char* aScriptName)
if(data == NULL)
{
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
Con::warnf(" - No card profile %s exists", scriptName.c_str());
#endif
return;
@ -54,7 +54,7 @@ void GFXCardProfiler::loadProfileScript(const char* aScriptName)
const char *script = static_cast<const char *>(data);
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
Con::printf(" - Loaded card profile %s", scriptName.c_str());
#endif

View file

@ -46,8 +46,6 @@ S32 GFXTextureManager::smTextureReductionLevel = 0;
String GFXTextureManager::smMissingTexturePath(Con::getVariable("$Core::MissingTexturePath"));
String GFXTextureManager::smUnavailableTexturePath(Con::getVariable("$Core::UnAvailableTexturePath"));
String GFXTextureManager::smWarningTexturePath(Con::getVariable("$Core::WarningTexturePath"));
String GFXTextureManager::smDefaultIrradianceCubemapPath(Con::getVariable("$Core::DefaultIrradianceCubemap"));
String GFXTextureManager::smDefaultPrefilterCubemapPath(Con::getVariable("$Core::DefaultPrefilterCubemap"));
String GFXTextureManager::smBRDFTexturePath(Con::getVariable("$Core::BRDFTexture"));
GFXTextureManager::EventSignal GFXTextureManager::smEventSignal;
@ -75,14 +73,6 @@ void GFXTextureManager::init()
"The file path of the texture used to warn the developer.\n"
"@ingroup GFX\n" );
Con::addVariable("$Core::DefaultIrradianceCubemap", TypeRealString, &smDefaultIrradianceCubemapPath,
"The file path of the texture used as the default irradiance cubemap for PBR.\n"
"@ingroup GFX\n");
Con::addVariable("$Core::DefaultPrefilterCubemap", TypeRealString, &smDefaultPrefilterCubemapPath,
"The file path of the texture used as the default specular cubemap for PBR.\n"
"@ingroup GFX\n");
Con::addVariable("$Core::BRDFTexture", TypeRealString, &smBRDFTexturePath,
"The file path of the texture used as the default irradiance cubemap for PBR.\n"
"@ingroup GFX\n");
@ -1248,7 +1238,7 @@ GFXTextureObject *GFXTextureManager::createCompositeTexture(GBitmap*bmp[4], U32
if (bmp[2])
bChan = bmp[2]->getChanelValueAt(x, y, inputKey[2]);
else
bChan = 255;
bChan = 0;
if (bmp[3])
aChan = bmp[3]->getChanelValueAt(x, y, inputKey[3]);

View file

@ -75,9 +75,6 @@ public:
/// Provide the path to the texture used to warn the developer
static const String& getWarningTexturePath() { return smWarningTexturePath; }
static const String& getDefaultIrradianceCubemapPath() { return smDefaultIrradianceCubemapPath; }
static const String& getDefaultPrefilterCubemapPath() { return smDefaultPrefilterCubemapPath; }
static const String& getBRDFTexturePath() { return smBRDFTexturePath; }
/// Update width and height based on available resources.
@ -217,8 +214,6 @@ protected:
/// File path to the warning texture
static String smWarningTexturePath;
static String smDefaultIrradianceCubemapPath;
static String smDefaultPrefilterCubemapPath;
static String smBRDFTexturePath;
GFXTextureObject *mListHead;

View file

@ -45,7 +45,7 @@ GFXGLTextureObject::GFXGLTextureObject(GFXDevice * aDevice, GFXTextureProfile *p
mFrameAllocatorPtr(NULL)
{
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
mFrameAllocatorMarkGuard = FrameAllocator::getWaterMark();
#endif
@ -90,7 +90,7 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
mFrameAllocatorMark = FrameAllocator::getWaterMark();
mFrameAllocatorPtr = (U8*)FrameAllocator::alloc( size );
mLockedRect.bits = mFrameAllocatorPtr;
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
mFrameAllocatorMarkGuard = FrameAllocator::getWaterMark();
#endif

View file

@ -102,10 +102,10 @@ private:
//FrameAllocator
U32 mFrameAllocatorMark;
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
U32 mFrameAllocatorMarkGuard;
#endif
U8 *mFrameAllocatorPtr;
};
#endif
#endif

View file

@ -208,7 +208,7 @@ GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_READ_FRAMEBUFFER, GL
GFXGLPreserveInteger TORQUE_CONCAT(preserve2_, __LINE__) (GL_DRAW_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER_BINDING, (GFXGLPreserveInteger::BindFn)glBindFramebuffer)
#if TORQUE_DEBUG
#ifdef TORQUE_DEBUG
// Handy macro for checking the status of a framebuffer. Framebuffers can fail in
// all sorts of interesting ways, these are just the most common. Further, no existing GL profiling

View file

@ -138,10 +138,15 @@ void GuiBitmapButtonCtrl::initPersistFields()
{
addGroup( "Bitmap" );
INITPERSISTFIELD_IMAGEASSET(Bitmap, GuiBitmapButtonCtrl, "Texture file to display on this button.\n"
addProtectedField("Bitmap", TypeImageFilename, Offset(mBitmapName, GuiBitmapButtonCtrl), _setBitmapFieldData, &defaultProtectedGetFn, "Texture file to display on this button.\n"
"If useStates is false, this will be the file that renders on the control. Otherwise, this will "
"specify the default texture name to which the various state and modifier suffixes are appended "
"to find the per-state and per-modifier (if enabled) textures.", AbstractClassRep::FIELD_HideInInspectors); \
addProtectedField("BitmapAsset", TypeImageAssetId, Offset(mBitmapAssetId, GuiBitmapButtonCtrl), _setBitmapFieldData, &defaultProtectedGetFn, "Texture file to display on this button.\n"
"If useStates is false, this will be the file that renders on the control. Otherwise, this will "
"specify the default texture name to which the various state and modifier suffixes are appended "
"to find the per-state and per-modifier (if enabled) textures.");
addField("color", TypeColorI, Offset(mColor, GuiBitmapButtonCtrl), "color mul");
addField( "bitmapMode", TYPEID< BitmapMode >(), Offset( mBitmapMode, GuiBitmapButtonCtrl ),
@ -196,6 +201,9 @@ void GuiBitmapButtonCtrl::onSleep()
mTextures[ i ].mTextureInactive = NULL;
}
if (mBitmapAsset.notNull())
mBitmap = NULL;
Parent::onSleep();
}

View file

@ -138,7 +138,7 @@ class GuiBitmapButtonCtrl : public GuiButtonCtrl
if( mActive )
{
if( mDepressed || mStateOn ) return DEPRESSED;
if( mMouseOver ) return HILIGHT;
if( mHighlighted ) return HILIGHT;
return NORMAL;
}
else
@ -185,6 +185,14 @@ class GuiBitmapButtonCtrl : public GuiButtonCtrl
DECLARE_CONOBJECT(GuiBitmapButtonCtrl);
DECLARE_DESCRIPTION( "A button control rendered entirely from bitmaps.\n"
"The individual button states are represented with separate bitmaps." );
//Basically a wrapper function to do our special state handling setup when the fields change
static bool _setBitmapFieldData(void* obj, const char* index, const char* data)
{
GuiBitmapButtonCtrl* object = static_cast<GuiBitmapButtonCtrl*>(obj);
object->setBitmap(StringTable->insert(data));
return false;
}
};
typedef GuiBitmapButtonCtrl::BitmapMode GuiBitmapMode;

View file

@ -79,7 +79,7 @@ void GuiBorderButtonCtrl::onRender(Point2I offset, const RectI &updateRect)
}
}
if ( mMouseOver )
if ( mHighlighted )
{
RectI bounds( offset, getExtent() );
for ( S32 i=0; i < mProfile->mBorderThickness; i++ )

View file

@ -98,7 +98,7 @@ EndImplementEnumType;
GuiButtonBaseCtrl::GuiButtonBaseCtrl()
{
mDepressed = false;
mMouseOver = false;
mHighlighted = false;
mActive = true;
static StringTableEntry sButton = StringTable->insert( "Button" );
mButtonText = sButton;
@ -288,14 +288,14 @@ void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
if(isMouseLocked())
{
mDepressed = true;
mMouseOver = true;
mHighlighted = true;
}
else
{
if ( mActive && mProfile->mSoundButtonOver )
SFX->playOnce(mProfile->mSoundButtonOver);
mMouseOver = true;
mHighlighted = true;
}
}
@ -309,7 +309,7 @@ void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)
onMouseLeave_callback();
if( isMouseLocked() )
mDepressed = false;
mMouseOver = false;
mHighlighted = false;
}
//-----------------------------------------------------------------------------
@ -542,3 +542,17 @@ DefineEngineMethod( GuiButtonBaseCtrl, resetState, void, (),,
{
object->resetState();
}
DefineEngineMethod(GuiButtonBaseCtrl, setHighlighted, void, (bool highlighted), (false),
"Reset the mousing state of the button.\n\n"
"This method should not generally be called.")
{
object->setHighlighted(highlighted);
}
DefineEngineMethod(GuiButtonBaseCtrl, isHighlighted, bool, (),,
"Reset the mousing state of the button.\n\n"
"This method should not generally be called.")
{
return object->isHighlighted();
}

View file

@ -49,7 +49,7 @@ class GuiButtonBaseCtrl : public GuiControl
StringTableEntry mButtonText;
StringTableEntry mButtonTextID;
bool mDepressed;
bool mMouseOver;
bool mHighlighted;
bool mStateOn;
S32 mButtonType;
S32 mRadioGroup;
@ -95,7 +95,10 @@ class GuiButtonBaseCtrl : public GuiControl
bool getStateOn() const { return mStateOn; }
void setDepressed( bool depressed ) { mDepressed = depressed; }
void resetState() {mDepressed = false; mMouseOver = false;}
void resetState() {mDepressed = false; mHighlighted = false;}
void setHighlighted(bool highlighted) { mHighlighted = highlighted; }
bool isHighlighted() { return mHighlighted; }
void acceleratorKeyPress(U32 index);
void acceleratorKeyRelease(U32 index);

View file

@ -83,7 +83,7 @@ bool GuiButtonCtrl::onWake()
void GuiButtonCtrl::onRender(Point2I offset,
const RectI& updateRect)
{
bool highlight = mMouseOver;
bool highlight = mHighlighted;
bool depressed = mDepressed;
ColorI fontColor = mActive ? ( highlight ? mProfile->mFontColorHL : mProfile->mFontColor ) : mProfile->mFontColorNA;
@ -107,7 +107,7 @@ void GuiButtonCtrl::onRender(Point2I offset,
indexMultiplier = 4;
else if ( mDepressed || mStateOn )
indexMultiplier = 2;
else if ( mMouseOver )
else if ( mHighlighted )
indexMultiplier = 3;
renderSizableBitmapBordersFilled( boundsRect, indexMultiplier, mProfile );
@ -123,3 +123,4 @@ void GuiButtonCtrl::onRender(Point2I offset,
//render the children
renderChildControls( offset, updateRect);
}

View file

@ -106,7 +106,7 @@ void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect)
}
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
ColorI fontColor = mActive ? (mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA;
ColorI fontColor = mActive ? (mHighlighted ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA;
ColorI insideBorderColor = isFirstResponder() ? mProfile->mBorderColorHL : mProfile->mBorderColor;
// just draw the check box and the text:

View file

@ -218,7 +218,7 @@ void GuiIconButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
{
bool highlight = mMouseOver;
bool highlight = mHighlighted;
bool depressed = mDepressed;
ColorI fontColor = mActive ? (highlight ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA;
@ -236,14 +236,19 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
else
renderSlightlyLoweredBox(boundsRect, mProfile);
}
else if(mMouseOver && mActive)
else if(mHighlighted && mActive)
{
// If there is a bitmap array then render using it.
// Otherwise use a standard fill.
if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
if (mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
{
renderBitmapArray(boundsRect, stateMouseOver);
}
else
renderSlightlyRaisedBox(boundsRect, mProfile);
{
drawer->drawRectFill(boundsRect, mProfile->mFillColorHL);
drawer->drawRect(boundsRect, mProfile->mBorderColorHL);
}
}
else
{
@ -258,8 +263,16 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
}
else
{
drawer->drawRectFill(boundsRect, mProfile->mFillColorNA);
drawer->drawRect(boundsRect, mProfile->mBorderColorNA);
if (mActive)
{
drawer->drawRectFill(boundsRect, mProfile->mFillColor);
drawer->drawRect(boundsRect, mProfile->mBorderColor);
}
else
{
drawer->drawRectFill(boundsRect, mProfile->mFillColorNA);
drawer->drawRect(boundsRect, mProfile->mBorderColorNA);
}
}
}
@ -302,7 +315,7 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
}
else
{
iconRect.set( offset + mButtonMargin, getExtent() - (mButtonMargin * 2) );
iconRect.set( offset + mButtonMargin, getExtent() - (Point2I(mAbs(mButtonMargin.x), mAbs(mButtonMargin.y)) * 2) );
if ( mMakeIconSquare )
{
@ -313,6 +326,20 @@ void GuiIconButtonCtrl::renderButton( Point2I &offset, const RectI& updateRect )
iconRect.extent.x = iconRect.extent.y;
}
if (mIconLocation == IconLocRight)
{
iconRect.point.x = (offset.x + getWidth()) - iconRect.extent.x + mButtonMargin.x;
}
else if (mIconLocation == IconLocLeft)
{
//default state presumes left positioning
}
else if (mIconLocation == IconLocCenter)
{
iconRect.point.x = offset.x + (getWidth() / 2) - (iconRect.extent.x / 2) + mButtonMargin.x;
iconRect.point.y = offset.y + (getHeight() / 2) - (iconRect.extent.y / 2) + mButtonMargin.y;
}
drawer->drawBitmapStretch( mBitmap, iconRect );
}
}

View file

@ -90,7 +90,7 @@ bool GuiSwatchButtonCtrl::onWake()
void GuiSwatchButtonCtrl::onRender( Point2I offset, const RectI &updateRect )
{
bool highlight = mMouseOver;
bool highlight = mHighlighted;
ColorI borderColor = mActive ? ( highlight ? mProfile->mBorderColorHL : mProfile->mBorderColor ) : mProfile->mBorderColorNA;

View file

@ -66,7 +66,7 @@ void GuiToggleButtonCtrl::onPreRender()
void GuiToggleButtonCtrl::onRender(Point2I offset,
const RectI& updateRect)
{
bool highlight = mMouseOver;
bool highlight = mHighlighted;
bool depressed = mDepressed;
ColorI fontColor = mActive ? ( highlight ? mProfile->mFontColorHL : mProfile->mFontColor ) : mProfile->mFontColorNA;
@ -89,7 +89,7 @@ void GuiToggleButtonCtrl::onRender(Point2I offset,
indexMultiplier = 4;
else if ( mDepressed || mStateOn )
indexMultiplier = 2;
else if ( mMouseOver )
else if ( mHighlighted )
indexMultiplier = 3;

View file

@ -144,7 +144,7 @@ void GuiToolboxButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
RectI r(offset, getExtent());
if ( mDepressed || mStateOn )
renderStateRect( mLoweredBitmap , r );
else if ( mMouseOver )
else if ( mHighlighted )
renderStateRect( mHoverBitmap , r );
}

View file

@ -66,6 +66,9 @@ IMPLEMENT_CALLBACK( GuiWindowCtrl, onCollapse, void, (), (),
"Called when the window is collapsed by clicking its title bar." );
IMPLEMENT_CALLBACK( GuiWindowCtrl, onRestore, void, (), (),
"Called when the window is restored from minimized, maximized, or collapsed state." );
IMPLEMENT_CALLBACK(GuiWindowCtrl, onResize, void, (S32 posX, S32 posY, S32 width, S32 height), (0, 0, 0, 0),
"Called when the window is resized in a regular manner by mouse manipulation.");
//-----------------------------------------------------------------------------
@ -1557,6 +1560,8 @@ bool GuiWindowCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
// Set the button coords
positionButtons();
onResize_callback(newPosition.x, newPosition.y, newExtent.x, newExtent.y);
return true;
}

View file

@ -201,6 +201,7 @@ class GuiWindowCtrl : public GuiContainer
DECLARE_CALLBACK( void, onMaximize, () );
DECLARE_CALLBACK( void, onCollapse, () );
DECLARE_CALLBACK( void, onRestore, () );
DECLARE_CALLBACK(void, onResize, (S32 posX, S32 posY, S32 width, S32 height));
/// @}

View file

@ -98,7 +98,8 @@ bool GuiBitmapCtrl::onWake()
return false;
setActive(true);
setBitmap(getBitmap());
if (mBitmapName != StringTable->insert("texhandle"))
setBitmap(getBitmap());
return true;
}
@ -152,7 +153,7 @@ void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize)
{
mBitmap = handle;
mBitmapName = String("texhandle");
mBitmapName = StringTable->insert("texhandle");
// Resize the control to fit the bitmap
if (resize)

View file

@ -146,12 +146,14 @@ void GuiDecoyCtrl::onMouseMove(const GuiEvent &event)
GuiControl *tempControl = parent->findHitControl(localPoint);
//the decoy control has the responsibility of keeping track of the decoyed controls status
if(mMouseOverDecoy == false && mDecoyReference != NULL)
if(mMouseOverDecoy == false && mDecoyReference != NULL &&
!mDecoyReference->isDeleted() && !mDecoyReference->isRemoved())
{
tempControl->onMouseEnter(event);
mMouseOverDecoy = true;
}
else if(tempControl != mDecoyReference && mDecoyReference != NULL)
else if(tempControl != mDecoyReference && mDecoyReference != NULL &&
!mDecoyReference->isDeleted() && !mDecoyReference->isRemoved())
{
mDecoyReference->onMouseLeave(event);
mMouseOverDecoy = false;

File diff suppressed because it is too large Load diff

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