diff --git a/Engine/source/T3D/assets/GameObjectAsset.cpp b/Engine/source/T3D/assets/GameObjectAsset.cpp index 514d6da20..2ae40ab0d 100644 --- a/Engine/source/T3D/assets/GameObjectAsset.cpp +++ b/Engine/source/T3D/assets/GameObjectAsset.cpp @@ -262,8 +262,8 @@ GuiControl* GuiInspectorTypeGameObjectAssetPtr::constructEditControl() dSprintf(szBuffer, sizeof(szBuffer), "%d.onClick(%s);", this->getId(), mCaption); mGameObjectEditButton->setField("Command", szBuffer); - mGameObjectEditButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile"); - mGameObjectEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile"); + mGameObjectEditButton->setDataField(StringTable->insert("Profile"), NULL, "ToolsGuiButtonProfile"); + mGameObjectEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "ToolsGuiToolTipProfile"); mGameObjectEditButton->setDataField(StringTable->insert("hovertime"), NULL, "1000"); const char* assetId = getData(); diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index ceea28bfc..55130a92e 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -366,7 +366,7 @@ GuiControl* GuiInspectorTypeShapeAssetPtr::constructEditControl() // Change filespec char szBuffer[512]; - dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %d, %s);", + dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %s, %s);", mInspector->getInspectObject()->getIdString(), mCaption); mBrowseButton->setField("Command", szBuffer); diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index 16a3f49e6..b81e2f555 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -171,8 +171,10 @@ void TSStatic::initPersistFields() &TSStatic::_setShapeAsset, &defaultProtectedGetFn, "The source shape asset."); +#ifdef TORQUE_ALLOW_DIRECT_FILENAMES addField("shapeName", TypeShapeFilename, Offset( mShapeName, TSStatic ), "%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic." ); +#endif addProtectedField( "skin", TypeRealString, Offset( mAppliedSkinName, TSStatic ), &_setFieldSkin, &_getFieldSkin, "@brief The skin applied to the shape.\n\n" @@ -289,7 +291,7 @@ void TSStatic::inspectPostApply() if(isServerObject()) { - setMaskBits(AdvancedStaticOptionsMask); + setMaskBits(-1); prepCollision(); } @@ -463,9 +465,74 @@ bool TSStatic::_createShape() Sim::findObject( cubeDescId, reflectorDesc ); } + //Set up the material slot vars for easy manipulation + S32 materialCount = mShape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount(); + + if (isServerObject()) + { + char matFieldName[128]; + + for (U32 i = 0; i < materialCount; i++) + { + StringTableEntry materialname = StringTable->insert(mShape->materialList->getMaterialName(i).c_str()); + + dSprintf(matFieldName, 128, "MaterialSlot%d", i); + StringTableEntry matFld = StringTable->insert(matFieldName); + + setDataField(matFld, NULL, materialname); + } + } + return true; } +void TSStatic::onDynamicModified(const char* slotName, const char* newValue) +{ + bool isSrv = isServerObject(); + + if (FindMatch::isMatch("materialslot*", slotName, false)) + { + if (!getShape()) + return; + + S32 slot = -1; + String outStr(String::GetTrailingNumber(slotName, slot)); + + if (slot == -1) + return; + + //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name + MaterialAsset* matAsset = AssetDatabase.acquireAsset(newValue); + if (!matAsset) + return; + + bool found = false; + for (U32 i = 0; i < mChangingMaterials.size(); i++) + { + if (mChangingMaterials[i].slot == slot) + { + mChangingMaterials[i].matAsset = matAsset; + mChangingMaterials[i].assetId = newValue; + found = true; + } + } + + if (!found) + { + matMap newMatMap; + newMatMap.slot = slot; + newMatMap.matAsset = matAsset; + newMatMap.assetId = newValue; + + mChangingMaterials.push_back(newMatMap); + } + + setMaskBits(MaterialMask); + } + + Parent::onDynamicModified(slotName, newValue); +} + void TSStatic::prepCollision() { // Let the client know that the collision was updated @@ -918,6 +985,22 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream) } stream->write(mOverrideColor); + + if (stream->writeFlag(mask & MaterialMask)) + { + stream->writeInt(mChangingMaterials.size(), 16); + + for (U32 i = 0; i < mChangingMaterials.size(); i++) + { + stream->writeInt(mChangingMaterials[i].slot, 16); + + NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str(); + con->packNetStringHandleU(stream, matNameStr); + } + + mChangingMaterials.clear(); + } + return retMask; } @@ -1019,6 +1102,26 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream) stream->read(&mOverrideColor); + if (stream->readFlag()) + { + mChangingMaterials.clear(); + U32 materialCount = stream->readInt(16); + + for (U32 i = 0; i < materialCount; i++) + { + matMap newMatMap; + newMatMap.slot = stream->readInt(16); + newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString()); + + //do the lookup, now + newMatMap.matAsset = AssetDatabase.acquireAsset(newMatMap.assetId); + + mChangingMaterials.push_back(newMatMap); + } + + updateMaterials(); + } + if ( isProperlyAdded() ) _updateShouldTick(); set_special_typing(); @@ -1458,6 +1561,46 @@ U32 TSStatic::getNumDetails() return 0; }; +void TSStatic::updateMaterials() +{ + if (mChangingMaterials.empty() || !mShape) + return; + + TSMaterialList* pMatList = mShapeInstance->getMaterialList(); + + String path; + if (mShapeAsset->isAssetValid()) + path = mShapeAsset->getShapeFilename(); + else + path = mShapeName; + + pMatList->setTextureLookupPath(path); + + bool found = false; + const Vector& materialNames = pMatList->getMaterialNameList(); + for (S32 i = 0; i < materialNames.size(); i++) + { + if (found) + break; + + for (U32 m = 0; m < mChangingMaterials.size(); m++) + { + if (mChangingMaterials[m].slot == i) + { + //Fetch the actual material asset + pMatList->renameMaterial(i, mChangingMaterials[m].matAsset->getMaterialDefinitionName()); + found = true; + break; + } + } + } + + mChangingMaterials.clear(); + + // Initialize the material instances + mShapeInstance->initMaterialList(); +} + //------------------------------------------------------------------------ //These functions are duplicated in tsStatic and shapeBase. //They each function a little differently; but achieve the same purpose of gathering diff --git a/Engine/source/T3D/tsStatic.h b/Engine/source/T3D/tsStatic.h index bcfdba9ad..0881a4257 100644 --- a/Engine/source/T3D/tsStatic.h +++ b/Engine/source/T3D/tsStatic.h @@ -108,8 +108,9 @@ class TSStatic : public SceneObject TransformMask = Parent::NextFreeMask << 0, AdvancedStaticOptionsMask = Parent::NextFreeMask << 1, UpdateCollisionMask = Parent::NextFreeMask << 2, - SkinMask = Parent::NextFreeFlag << 3, - NextFreeMask = Parent::NextFreeMask << 4 + SkinMask = Parent::NextFreeMask << 3, + MaterialMask = Parent::NextFreeMask << 4, + NextFreeMask = Parent::NextFreeMask << 5 }; public: @@ -137,6 +138,16 @@ protected: F32 mAlphaFade; bool mInvertAlphaFade; + struct matMap + { + MaterialAsset* matAsset; + String assetId; + U32 slot; + }; + + Vector mChangingMaterials; + Vector mMaterials; + bool onAdd(); void onRemove(); @@ -163,6 +174,8 @@ protected: virtual void interpolateTick( F32 delta ); virtual void advanceTime( F32 dt ); + virtual void onDynamicModified(const char* slotName, const char* newValue); + /// Start or stop processing ticks depending on our state. void _updateShouldTick(); @@ -261,6 +274,8 @@ public: virtual void onInspect(GuiInspector*); + void updateMaterials(); + private: virtual void onStaticModified(const char* slotName, const char*newValue = NULL); protected: diff --git a/Engine/source/environment/VolumetricFog.cpp b/Engine/source/environment/VolumetricFog.cpp index d8b3be5db..3fc6389a0 100644 --- a/Engine/source/environment/VolumetricFog.cpp +++ b/Engine/source/environment/VolumetricFog.cpp @@ -138,6 +138,9 @@ VolumetricFog::VolumetricFog() mTexTiles = 1.0f; mSpeed1.set(0.5f, 0.0f); mSpeed2.set(0.1f, 0.1f); + + mShapeAsset = StringTable->EmptyString(); + mShapeAssetId = StringTable->EmptyString(); } VolumetricFog::~VolumetricFog() @@ -165,8 +168,14 @@ VolumetricFog::~VolumetricFog() void VolumetricFog::initPersistFields() { addGroup("VolumetricFogData"); + addProtectedField("shapeAsset", TypeShapeAssetPtr, Offset(mShapeAsset, VolumetricFog), + &VolumetricFog::_setShapeAsset, &defaultProtectedGetFn, "The source shape asset."); + +#ifdef TORQUE_ALLOW_DIRECT_FILENAMES addField("shapeName", TypeShapeFilename, Offset(mShapeName, VolumetricFog), "Path and filename of the model file (.DTS, .DAE) to use for this Volume."); +#endif + addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog), "Fog color RGBA (Alpha is ignored)"); addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), @@ -212,6 +221,15 @@ void VolumetricFog::initPersistFields() Parent::initPersistFields(); } +bool VolumetricFog::_setShapeAsset(void* obj, const char* index, const char* data) +{ + VolumetricFog* fog = static_cast(obj);// ->setFile(FileName(data)); + + fog->setShapeAsset(StringTable->insert(data)); + + return false; +} + void VolumetricFog::inspectPostApply() { Parent::inspectPostApply(); @@ -328,19 +346,49 @@ void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize) // Loadshape extracted from TSMesh and TSShapeInstance //----------------------------------------------------------------------------- +bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId) +{ + mShapeAssetId = shapeAssetId; + + LoadShape(); + return true; +} + bool VolumetricFog::LoadShape() { GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip }; - if (!mShapeName || mShapeName[0] == '\0') - { - Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!"); - return false; - } - - // Load shape, server side only reads bounds and radius Resource mShape; - mShape = ResourceManager::get().load(mShapeName); + if (mShapeAssetId != StringTable->EmptyString()) + { + mShapeAsset = mShapeAssetId; + + if (mShapeAsset.isNull()) + { + Con::errorf("[TSStatic] Failed to load shape asset."); + return false; + } + + mShape = mShapeAsset->getShapeResource(); + + if (!mShape) + { + Con::errorf("TSStatic::_createShape() - Shape Asset had no valid shape!"); + return false; + } + } + else + { + if (!mShapeName || mShapeName[0] == '\0') + { + Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!"); + return false; + } + + // Load shape, server side only reads bounds and radius + mShape = ResourceManager::get().load(mShapeName); + } + if (bool(mShape) == false) { Con::errorf("VolumetricFog::LoadShape() - Unable to load shape: %s", mShapeName); @@ -551,15 +599,25 @@ U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream) } if (stream->writeFlag(mask & FogShapeMask)) { + stream->writeString(mShapeAssetId); stream->writeString(mShapeName); mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); - if (!mShapeName || mShapeName[0] == '\0') - return retMask; + Resource mShape; - mShape = ResourceManager::get().load(mShapeName); + + if (mShapeAssetId != StringTable->EmptyString()) + { + mShape = mShape = mShapeAsset->getShapeResource(); + } + else if (mShapeName && mShapeName[0] != '\0') + { + mShape = ResourceManager::get().load(mShapeName); + } + if (bool(mShape) == false) return retMask; + mObjBox = mShape->mBounds; mRadius = mShape->mRadius; resetWorldBox(); @@ -577,6 +635,7 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) VectorF scale; VectorF mOldScale = getScale(); String oldTextureName = mTextureName; + StringTableEntry oldShapeAsset = mShapeAssetId; StringTableEntry oldShape = mShapeName; if (stream->readFlag())// Fog color @@ -647,10 +706,14 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) } if (stream->readFlag())//Fog shape { + char buffer[256]; + stream->readString(buffer); + mShapeAssetId = StringTable->insert(buffer); + mShapeName = stream->readSTString(); mathRead(*stream, &mat); mathRead(*stream, &scale); - if (strcmp(oldShape, mShapeName) != 0) + if (strcmp(oldShapeAsset, mShapeAssetId) != 0 || strcmp(oldShape, mShapeName) != 0) { mIsVBDirty = true; mShapeLoaded = LoadShape(); diff --git a/Engine/source/environment/VolumetricFog.h b/Engine/source/environment/VolumetricFog.h index 92da5aa14..1b2361610 100644 --- a/Engine/source/environment/VolumetricFog.h +++ b/Engine/source/environment/VolumetricFog.h @@ -46,6 +46,13 @@ #endif #include "gui/core/guiCanvas.h" + +#ifndef _ASSET_PTR_H_ +#include "assets/assetPtr.h" +#endif +#ifndef SHAPEASSET_H +#include "T3D/assets/ShapeAsset.h" +#endif class VolumetricFogRTManager; @@ -136,6 +143,9 @@ class VolumetricFog : public SceneObject GFXPrimitiveBufferHandle mPB; // Fog volume data; + AssetPtr mShapeAsset; + StringTableEntry mShapeAssetId; + StringTableEntry mShapeName; ColorI mFogColor; F32 mFogDensity; @@ -209,6 +219,8 @@ class VolumetricFog : public SceneObject void processTick(const Move *move); void _enterFog(ShapeBase *control); void _leaveFog(ShapeBase *control); + + static bool _setShapeAsset(void* obj, const char* index, const char* data); public: // Public methods @@ -234,6 +246,8 @@ class VolumetricFog : public SceneObject void setFogGlow(bool on_off, F32 strength); void setFogLightray(bool on_off, F32 strength); bool isInsideFog(); + + bool setShapeAsset(const StringTableEntry shapeAssetId); DECLARE_CONOBJECT(VolumetricFog); diff --git a/Engine/source/gui/controls/guiTextEditCtrl.cpp b/Engine/source/gui/controls/guiTextEditCtrl.cpp index 076eddc90..84ec02c78 100644 --- a/Engine/source/gui/controls/guiTextEditCtrl.cpp +++ b/Engine/source/gui/controls/guiTextEditCtrl.cpp @@ -138,6 +138,9 @@ GuiTextEditCtrl::GuiTextEditCtrl() mHistoryIndex = 0; mHistoryBuf = NULL; + mDoubleClickTimeMS = 50; + mMouseUpTime = 0; + #if defined(__MACOSX__) UTF8 bullet[4] = { 0xE2, 0x80, 0xA2, 0 }; @@ -382,7 +385,7 @@ void GuiTextEditCtrl::onMouseDown( const GuiEvent &event ) // If we have a double click, select all text. Otherwise // act as before by clearing any selection. - bool doubleClick = (event.mouseClickCount > 1); + bool doubleClick = (event.mouseClickCount > 1 && Platform::getRealMilliseconds() - mMouseUpTime > mDoubleClickTimeMS); if(doubleClick) { selectAllText(); @@ -451,6 +454,8 @@ void GuiTextEditCtrl::onMouseUp(const GuiEvent &event) TORQUE_UNUSED(event); mDragHit = false; mScrollDir = 0; + + mMouseUpTime = Platform::getRealMilliseconds(); mouseUnlock(); } diff --git a/Engine/source/gui/controls/guiTextEditCtrl.h b/Engine/source/gui/controls/guiTextEditCtrl.h index 15021ea5e..cc4faf92e 100644 --- a/Engine/source/gui/controls/guiTextEditCtrl.h +++ b/Engine/source/gui/controls/guiTextEditCtrl.h @@ -85,6 +85,9 @@ protected: bool mPasswordText; StringTableEntry mPasswordMask; + S32 mDoubleClickTimeMS; + S32 mMouseUpTime; + /// If set, any non-ESC key is handled here or not at all bool mSinkAllKeyEvents; UTF16 **mHistoryBuf; diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 532052bfa..44d31f4ac 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -48,6 +48,9 @@ const String AdvancedLightBinManager::smBufferName( "specularLighting" ); ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality; bool AdvancedLightBinManager::smPSSMDebugRender = false; bool AdvancedLightBinManager::smUseSSAOMask = false; +bool AdvancedLightBinManager::smDiffuseLightViz = false; +bool AdvancedLightBinManager::smSpecularLightViz = false; +bool AdvancedLightBinManager::smDetailLightingViz = false; ImplementEnumType( ShadowFilterMode, "The shadow filtering modes for Advanced Lighting shadows.\n" @@ -127,6 +130,9 @@ AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = Con::addVariableNotify( "$pref::Shadows::filterMode", callback ); Con::addVariableNotify( "$AL::PSSMDebugRender", callback ); Con::addVariableNotify( "$AL::UseSSAOMask", callback ); + Con::addVariableNotify( "$AL::DiffuseLightViz", callback); + Con::addVariableNotify( "$AL::SpecularLightViz", callback); + Con::addVariableNotify( "$AL::DetailLightingViz", callback); } @@ -137,7 +143,10 @@ AdvancedLightBinManager::~AdvancedLightBinManager() Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials ); Con::removeVariableNotify( "$pref::shadows::filterMode", callback ); Con::removeVariableNotify( "$AL::PSSMDebugRender", callback ); - Con::removeVariableNotify( "$AL::UseSSAOMask", callback ); + Con::removeVariableNotify( "$AL::UseSSAOMask", callback ); + Con::removeVariableNotify( "$AL::DiffuseLightViz", callback); + Con::removeVariableNotify( "$AL::SpecularLightViz", callback); + Con::removeVariableNotify( "$AL::DetailLightingViz", callback); } void AdvancedLightBinManager::consoleInit() @@ -157,6 +166,18 @@ void AdvancedLightBinManager::consoleInit() Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender, "Enables debug rendering of the PSSM shadows.\n" "@ingroup AdvancedLighting\n" ); + + Con::addVariable("$AL::DiffuseLightViz", TypeBool, &smDiffuseLightViz, + "Enables debug rendering of the PSSM shadows.\n" + "@ingroup AdvancedLighting\n"); + + Con::addVariable("$AL::SpecularLightViz", TypeBool, &smSpecularLightViz, + "Enables debug rendering of the PSSM shadows.\n" + "@ingroup AdvancedLighting\n"); + + Con::addVariable("$AL::DetailLightingViz", TypeBool, &smDetailLightingViz, + "Enables debug rendering of the PSSM shadows.\n" + "@ingroup AdvancedLighting\n"); } bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize) @@ -447,6 +468,13 @@ AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMa if ( smPSSMDebugRender ) shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) ); + if( smDiffuseLightViz ) + shadowMacros.push_back(GFXShaderMacro("DIFFUSE_LIGHT_VIZ")); + else if (smSpecularLightViz) + shadowMacros.push_back(GFXShaderMacro("SPECULAR_LIGHT_VIZ")); + else if (smDetailLightingViz) + shadowMacros.push_back(GFXShaderMacro("DETAIL_LIGHTING_VIZ")); + // Now create the material info object. info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros ); } diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index 5267391e0..7e26891e1 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -103,6 +103,11 @@ public: /// light to compile in the SSAO mask. static bool smUseSSAOMask; + //Used to toggle the visualization of diffuse and specular light contribution + static bool smDiffuseLightViz; + static bool smSpecularLightViz; + static bool smDetailLightingViz; + // Used for console init AdvancedLightBinManager( AdvancedLightManager *lm = NULL, ShadowMapManager *sm = NULL, diff --git a/Engine/source/scene/sceneContainer.cpp b/Engine/source/scene/sceneContainer.cpp index b08456b15..7d75d46b6 100644 --- a/Engine/source/scene/sceneContainer.cpp +++ b/Engine/source/scene/sceneContainer.cpp @@ -1654,4 +1654,57 @@ DefineEngineFunction( containerRayCast, const char*, return(returnBuffer); } +DefineEngineFunction(materialRayCast, const char*, +(Point3F start, Point3F end, U32 mask, SceneObject* pExempt, bool useClientContainer), (nullAsType(), false), +"@brief Cast a ray from start to end, checking for collision against items matching mask.\n\n" + +"If pExempt is specified, then it is temporarily excluded from collision checks (For " +"instance, you might want to exclude the player if said player was firing a weapon.)\n" + +"@param start An XYZ vector containing the tail position of the ray.\n" +"@param end An XYZ vector containing the head position of the ray\n" +"@param mask A bitmask corresponding to the type of objects to check for\n" +"@param pExempt An optional ID for a single object that ignored for this raycast\n" +"@param useClientContainer Optionally indicates the search should be within the " +"client container.\n" + +"@returns A string containing either null, if nothing was struck, or these fields:\n" +"
  • The ID of the object that was struck.
  • " +"
  • The x, y, z position that it was struck.
  • " +"
  • The x, y, z of the normal of the face that was struck.
  • " +"
  • The distance between the start point and the position we hit.
" + +"@ingroup Game") +{ + if (pExempt) + pExempt->disableCollision(); + + SceneContainer* pContainer = useClientContainer ? &gClientContainer : &gServerContainer; + + RayInfo rinfo; + S32 ret = 0; + if (pContainer->castRayRendered(start, end, mask, &rinfo) == true) + ret = rinfo.object->getId(); + + if (pExempt) + pExempt->enableCollision(); + + // add the hit position and normal? + static const U32 bufSize = 512; + char* returnBuffer = Con::getReturnBuffer(bufSize); + if (ret) + { + dSprintf(returnBuffer, bufSize, "%d %g %g %g %g %g %g %g %g %g %s", + ret, rinfo.point.x, rinfo.point.y, rinfo.point.z, + rinfo.normal.x, rinfo.normal.y, rinfo.normal.z, rinfo.distance, rinfo.texCoord.x, rinfo.texCoord.y, rinfo.material ? rinfo.material->getMaterial()->getName() : ""); + } + else + { + returnBuffer[0] = '0'; + returnBuffer[1] = '\0'; + } + + return(returnBuffer); +} + ConsoleFunctionGroupEnd( Containers ); diff --git a/Engine/source/scene/sceneObject.cpp b/Engine/source/scene/sceneObject.cpp index 354440fd2..8a0aa4589 100644 --- a/Engine/source/scene/sceneObject.cpp +++ b/Engine/source/scene/sceneObject.cpp @@ -154,6 +154,10 @@ SceneObject::SceneObject() mAccuTex = NULL; mSelectionFlags = 0; mPathfindingIgnore = false; + + mGameObjectAssetId = StringTable->insert(""); + + mDirtyGameObject = false; } //----------------------------------------------------------------------------- @@ -611,6 +615,13 @@ void SceneObject::setHidden( bool hidden ) void SceneObject::initPersistFields() { + addGroup("GameObject"); + addField("GameObject", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, SceneObject), "The asset Id used for the game object this entity is based on."); + + addField("dirtyGameObject", TypeBool, Offset(mDirtyGameObject, SceneObject), "If this entity is a GameObject, it flags if this instance delinates from the template.", + AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + endGroup("GameObject"); + addGroup( "Transform" ); addProtectedField( "position", TypeMatrixPosition, Offset( mObjToWorld, SceneObject ), @@ -654,6 +665,14 @@ void SceneObject::initPersistFields() Parent::initPersistFields(); } +bool SceneObject::_setGameObject(void* object, const char* index, const char* data) +{ + // Sanity! + AssertFatal(data != NULL, "Cannot use a NULL asset Id."); + + return true; //rbI->setMeshAsset(data); +} + //----------------------------------------------------------------------------- bool SceneObject::_setFieldPosition( void *object, const char *index, const char *data ) @@ -1532,4 +1551,4 @@ DefineEngineMethod(SceneObject, setForwardVector, void, (VectorF newForward, Vec "@param (Optional) The up vector to use to help orient the rotation.") { object->setForwardVector(newForward, upVector); -} \ No newline at end of file +} diff --git a/Engine/source/scene/sceneObject.h b/Engine/source/scene/sceneObject.h index 660d709bb..1bafc3b83 100644 --- a/Engine/source/scene/sceneObject.h +++ b/Engine/source/scene/sceneObject.h @@ -67,6 +67,13 @@ #include "ts/collada/colladaUtils.h" #endif +#ifndef _ASSET_PTR_H_ +#include "assets/assetPtr.h" +#endif +#ifndef GAME_OBJECT_ASSET_H +#include "T3D/assets/GameObjectAsset.h" +#endif + class SceneManager; class SceneRenderState; class SceneTraversalState; @@ -204,6 +211,12 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce /// SimPersistID* mMountPID; + StringTableEntry mGameObjectAssetId; + AssetPtr mGameObjectAsset; + + //Marked if this entity is a GameObject and deliniates from the parent GO asset + bool mDirtyGameObject; + /// @} /// @name Zoning @@ -778,6 +791,8 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce static void initPersistFields(); + static bool _setGameObject(void* object, const char* index, const char* data); + DECLARE_CONOBJECT( SceneObject ); private: diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl index aff2221d2..870756628 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl @@ -189,6 +189,38 @@ float3 BRDF_GetDiffuse(in Surface surface, in SurfaceToLight surfaceToLight) return diffuse; } +float3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight) +{ + float3 neutralColor = float3(0.5,0.5,0.5); + + float3 f0 = lerp(0.04.xxx, neutralColor, surface.metalness); + float f90 = saturate(50.0 * dot(f0, 0.33)); + float3 F = F_Schlick(f0, f90, surfaceToLight.HdotV); + float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness_brdf); + float D = D_GGX(surfaceToLight.NdotH, surface.roughness_brdf); + float3 Fr = D * F * Vis / M_PI_F; + return Fr; +} + +float3 BRDF_GetDebugDiffuse(in Surface surface, in SurfaceToLight surfaceToLight) +{ + float3 neutralColor = float3(0.5,0.5,0.5); + + //getting some banding with disney method, using lambert instead - todo futher testing + float Fd = 1.0 / M_PI_F; + + float3 f0 = lerp(0.04.xxx, neutralColor, surface.metalness); + + float f90 = saturate(50.0 * dot(f0, 0.33)); + float3 F = F_Schlick(f0, f90, surface.NdotV); + + //energy conservation - remove this if reverting back to disney method + float3 kD = 1.0.xxx - F; + kD *= 1.0 - surface.metalness; + float3 diffuse = kD * neutralColor * Fd; + return diffuse; +} + //attenuations functions from "moving frostbite to pbr paper" //https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf float smoothDistanceAtt ( float squaredDistance , float invSqrAttRadius ) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl index 53fbed9a3..4b1fa862c 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl @@ -230,6 +230,31 @@ float4 main(FarFrustumQuadConnectP IN) : SV_TARGET #endif //NO_SHADOW + #ifdef DIFFUSE_LIGHT_VIZ + float3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + float3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + + float3 final = max(0.0f, diffuse); + return float4(final, 0); + #endif + + #ifdef SPECULAR_LIGHT_VIZ + float3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + float3 spec = BRDF_GetDebugSpecular(surface, surfaceToLight) * factor; + + float3 final = max(0.0f, factor); + return float4(final, 0); + #endif + + #ifdef DETAIL_LIGHTING_VIZ + float3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + float3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + float3 spec = BRDF_GetDebugSpecular(surface,surfaceToLight) * factor; + + float3 final = max(0.0f, diffuse + spec); + return float4(final,0); + #endif + //get directional light contribution float3 lighting = getDirectionalLight(surface, surfaceToLight, lightingColor.rgb, lightBrightness, shadow); diff --git a/Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui b/Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui index b49d2fb4d..6ade66e95 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui +++ b/Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui @@ -59,7 +59,6 @@ profile = "ToolsGuiButtonProfile"; visible = "1"; active = "1"; - command = "AssetBrowser_importAssetWindow.ImportAssets();"; tooltipProfile = "ToolsGuiToolTipProfile"; hovertime = "1000"; isContainer = "0"; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.cs b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.cs index ca795d4e8..cb642518e 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.cs +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.cs @@ -123,6 +123,34 @@ function AssetBrowser::dragAndDropGameObjectAsset(%this, %assetDef, %dropTarget) } } +function AssetBrowser::onGameObjectAssetEditorDropped(%this, %assetDef, %position) +{ + //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); + + %targetPosition = EWorldEditor.unproject(%position SPC 1000); + %camPos = LocalClientConnection.camera.getPosition(); + %rayResult = containerRayCast(%camPos, %targetPosition, -1); + + %pos = EWCreatorWindow.getCreateObjectPosition(); + + if(%rayResult != 0) + { + %pos = getWords(%rayResult, 1, 3); + } + + %gameObject = %assetDef.createObject(); + + getScene(0).add(%gameObject); + + %gameObject.position = %pos; + + EWorldEditor.clearSelection(); + EWorldEditor.selectObject(%gameObject); + + EWorldEditor.isDirty = true; + +} + function AssetBrowser::renameGameObjectAsset(%this, %assetDef, %newAssetId, %originalName, %newName) { %oldScriptFilePath = %assetDef.scriptFile; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.cs b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.cs index aebf07a64..e8dee98a1 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.cs +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.cs @@ -452,6 +452,32 @@ function AssetBrowser::buildMaterialAssetPreview(%this, %assetDef, %previewData) %previewData.tooltip = %assetDef.friendlyName @ "\n" @ %assetDef; } +function AssetBrowser::onMaterialAssetEditorDropped(%this, %assetDef, %position) +{ + //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); + //first, see if we hit a static shape + %mask = $TypeMasks::StaticObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TerrainObjectType; + + %targetPosition = EWorldEditor.unproject(%position SPC 1000); + %camPos = LocalClientConnection.camera.getPosition(); + %rayResult = materialRayCast(%camPos, %targetPosition, -1, 0, false); + + %validTarget = false; + if(%rayResult != 0) + { + %obj = getWord(%rayResult, 0); + if(%obj.isMemberOfClass("TSStatic")) + { + //oh, cool a valid target! + %obj.materialSlot0 = %assetDef.getAssetId(); + echo("MaterialSlot0 set to " @ %assetDef.getAssetId()); + } + } + + EWorldEditor.isDirty = true; + +} + function GuiInspectorTypeMaterialAssetPtr::onControlDropped( %this, %payload, %position ) { Canvas.popDialog(EditorDragAndDropLayer); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.cs b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.cs index a31069a63..ebf04f9a0 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.cs +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.cs @@ -307,7 +307,7 @@ function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData) %previewData.assetName = %assetDef.assetName; %previewData.assetPath = %assetDef.fileName; - %previewData.previewImage = fileName; + %previewData.previewImage = %assetDef.fileName; %previewData.assetFriendlyName = %assetDef.assetName; %previewData.assetDesc = %assetDef.description; @@ -317,11 +317,20 @@ function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData) function AssetBrowser::onShapeAssetEditorDropped(%this, %assetDef, %position) { //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); - - %assetId = %assetDef.getAssetId(); - + + %targetPosition = EWorldEditor.unproject(%position SPC 1000); + %camPos = LocalClientConnection.camera.getPosition(); + %rayResult = containerRayCast(%camPos, %targetPosition, -1); + %pos = EWCreatorWindow.getCreateObjectPosition(); - + + if(%rayResult != 0) + { + %pos = getWords(%rayResult, 1, 3); + } + + %assetId = %assetDef.getAssetId(); + %newStatic = new TSStatic() { position = %pos; @@ -332,8 +341,9 @@ function AssetBrowser::onShapeAssetEditorDropped(%this, %assetDef, %position) EWorldEditor.clearSelection(); EWorldEditor.selectObject(%newStatic); - + EWorldEditor.isDirty = true; + } function GuiInspectorTypeShapeAssetPtr::onControlDropped( %this, %payload, %position ) diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/WorldEditorInspectorWindow.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/WorldEditorInspectorWindow.ed.gui index 0063c9d01..9abe8f9e3 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/WorldEditorInspectorWindow.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/WorldEditorInspectorWindow.ed.gui @@ -126,7 +126,7 @@ Profile = "GuiInspectorFieldInfoMLTextProfile"; HorizSizing = "width"; VertSizing = "top"; - Position = "6 205"; + Position = 5 SPC EWInspectorWindow.extent.y - 40; Extent = "197 35"; MinExtent = "8 2"; canSave = "1"; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs index 66f95c23c..e84c08472 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -63,6 +63,7 @@ function EditorGui::init(%this) { EWTreeWindow.position = %this.extent.x - EWTreeWindow.Extent.x SPC EditorGuiToolbar.extent.y; EWTreeWindow.extent = EWTreeWindow.extent.x SPC %this.extent.y - EditorGuiToolbar.extent.y - EditorGuiStatusBar.extent.y - 25; + FieldInfoControl.position = 5 SPC EWInspectorWindow.extent.y - 40; } } } @@ -81,6 +82,7 @@ function EditorGui::init(%this) { EWInspectorWindow.position = EWTreeWindow.position.x SPC EWTreeWindow.extent.y; EWInspectorWindow.extent = EWTreeWindow.extent.x SPC EWTreeWindow.extent.y; + FieldInfoControl.position = 5 SPC EWInspectorWindow.extent.y - 40; } } } @@ -1455,6 +1457,8 @@ function EWorldEditor::onResize(%this, %newPosition, %newExtent) EWInspectorWindow.resize(%inspPos.x, %inspPos.y, %inspExt.x, %inspExt.y); } + + FieldInfoControl.position = 5 SPC EWInspectorWindow.extent.y - 40; } //----------------------------------------------------------------------------- diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/lightViz.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/lightViz.cs index 9031526e5..0f2e51f20 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/lightViz.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/lightViz.cs @@ -379,7 +379,7 @@ function setLightingMode(%mode) $Shadows::disable = true; EVisibilityLightingModesOptions.checkItem(2, true); case "DetailLighting": - //$Viz_ColorblindnessModeVar = "0"; + $AL::DetailLightingViz = true; EVisibilityLightingModesOptions.checkItem(3, true); case "LightingOnly": $Light::renderReflectionProbes = false; @@ -388,6 +388,8 @@ function setLightingMode(%mode) $Light::disableLights = true; EVisibilityLightingModesOptions.checkItem(5, true); } + + reInitMaterials(); } function resetLightingMode() @@ -400,6 +402,7 @@ function resetLightingMode() $Light::renderReflectionProbes = true; $Light::disableLights = false; $Shadows::disable = false; + $AL::DetailLightingViz = false; EVisibilityLightingModesOptions.checkItem(0, true); } @@ -427,6 +430,48 @@ function disableLightFrustumViz() $Light::renderLightFrustums = false; } +function toggleLightViz(%mode) +{ + setLightingMode("Lit"); + + if($AL::DiffuseLightViz == 1) + %lastMode = "Diffuse"; + else if($AL::SpecularLightViz == 1) + %lastMode = "Specular"; + + $AL::DiffuseLightViz = 0; + $AL::SpecularLightViz = 0; + + EVisibilityLightsOptions.checkItem(2, false); + EVisibilityLightsOptions.checkItem(3, false); + + if(%mode $= %lastMode) + { + //forces the forward materials to get dis viz properly + reInitMaterials(); + + return; + } + + switch$(%mode) + { + case "Diffuse": + $AL::DiffuseLightViz = 1; + EVisibilityLightsOptions.checkItem(2, true); + case "Specular": + $AL::SpecularLightViz = 1; + EVisibilityLightsOptions.checkItem(3, true); + } + + //forces the forward materials to get dis viz properly + reInitMaterials(); +} + +function disableLightViz() +{ + toggleLightViz(-1); +} + //Lighting Viz singleton Material( Viz_DetailLightingMat ) { diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/probeViz.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/probeViz.cs index 3a9e43174..cd92c11d3 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/probeViz.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/probeViz.cs @@ -31,6 +31,7 @@ function toggleProbeViz(%mode) else { setLightingMode("ReflectionsOnly"); + toggleLightViz(-1); } switch$(%mode) diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/visibilityLayer.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/visibilityLayer.ed.cs index 8f4b93462..42d87b07e 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/visibilityLayer.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/visibility/visibilityLayer.ed.cs @@ -132,13 +132,10 @@ function setupEditorVisibilityMenu() item[ 0 ] = "Show Light Frustums" TAB "" TAB "toggleLightFrustumViz();"; item[ 1 ] = "Show Shadowmap Cascades" TAB "" TAB "togglePSSMDebugViz();"; - item[ 2 ] = "Show Specular Light" TAB "" TAB ""; - item[ 3 ] = "Show Diffuse Light" TAB "" TAB ""; + item[ 2 ] = "Show Diffuse Light" TAB "" TAB "toggleLightViz(\"Diffuse\");"; + item[ 3 ] = "Show Specular Light" TAB "" TAB "toggleLightViz(\"Specular\");"; }; - %lightspopup.enableItem(2, false); - %lightspopup.enableItem(3, false); - // //Probes %probespopup = new PopupMenu(EVisibilityProbesOptions) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index b6a8d5cef..4e6777562 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -135,6 +135,13 @@ mark_as_advanced(TORQUE_HIFI) option(TORQUE_EXTENDED_MOVE "Extended move support" OFF) mark_as_advanced(TORQUE_EXTENDED_MOVE) +option(TORQUE_ALLOW_DIRECT_FILENAMES "Allows gameclasses to use direct filenames instead of assets" OFF) +mark_as_advanced(TORQUE_ALLOW_DIRECT_FILENAMES) + +if(TORQUE_ALLOW_DIRECT_FILENAMES) + addDef(TORQUE_ALLOW_DIRECT_FILENAMES) +endif() + set(TORQUE_SDL ON) # we need sdl to do our platform interop if(WIN32)