From 47b68f482e5992b0ecc9353c877e5b08eec1112b Mon Sep 17 00:00:00 2001 From: OTHGMars Date: Fri, 18 Mar 2016 00:35:37 -0400 Subject: [PATCH 01/71] This commits adds the testSpacials() and setSpacials() functions to test for overlaps and update the controllers capsule dimensions when the player pose changes. --- .../source/T3D/physics/physx3/px3Player.cpp | 30 +++++++++++++++++++ Engine/source/T3D/physics/physx3/px3Player.h | 4 +-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/physics/physx3/px3Player.cpp b/Engine/source/T3D/physics/physx3/px3Player.cpp index e831c939c..10dc65e86 100644 --- a/Engine/source/T3D/physics/physx3/px3Player.cpp +++ b/Engine/source/T3D/physics/physx3/px3Player.cpp @@ -329,3 +329,33 @@ Box3F Px3Player::getWorldBounds() return px3Cast( bounds ); } +bool Px3Player::testSpacials(const Point3F &nPos, const Point3F &nSize) const +{ + F32 offset = nSize.z * 0.5f; + F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth; + F32 height = (nSize.z - (radius * 2.0f)) * 0.5f; + height -= mSkinWidth * 2.0f; + physx::PxCapsuleGeometry geom(radius, height); + + physx::PxVec3 pos(nPos.x, nPos.y, nPos.z + offset); + physx::PxQuat orientation(Float_HalfPi, physx::PxVec3(0.0f, 1.0f, 0.0f)); + + physx::PxOverlapBuffer hit; + physx::PxQueryFilterData queryFilter(physx::PxQueryFlag::eANY_HIT | physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC); + queryFilter.data.word0 = PX3_DEFAULT; + bool hasHit = mWorld->getScene()->overlap(geom, physx::PxTransform(pos, orientation), hit, queryFilter); + + return !hasHit; // Return true if there are no overlapping objects +} + +void Px3Player::setSpacials(const Point3F &nPos, const Point3F &nSize) +{ + mOriginOffset = nSize.z * 0.5f; + F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth; + F32 height = nSize.z - (radius * 2.0f); + height -= mSkinWidth * 2.0f; + + mWorld->releaseWriteLock(); + mController->resize(height); + px3GetFirstShape(mController->getActor())->getCapsuleGeometry(mGeometry); +} \ No newline at end of file diff --git a/Engine/source/T3D/physics/physx3/px3Player.h b/Engine/source/T3D/physics/physx3/px3Player.h index 55a1409cd..bd0546663 100644 --- a/Engine/source/T3D/physics/physx3/px3Player.h +++ b/Engine/source/T3D/physics/physx3/px3Player.h @@ -94,8 +94,8 @@ public: PhysicsWorld *world ); virtual Point3F move( const VectorF &displacement, CollisionList &outCol ); virtual void findContact( SceneObject **contactObject, VectorF *contactNormal, Vector *outOverlapObjects ) const; - virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const { return true; } - virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) {} + virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const; + virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ); virtual void enableCollision(); virtual void disableCollision(); }; From bac14875f4e4c38f66999ac473005a1f10835336 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 4 Apr 2016 09:38:24 -0500 Subject: [PATCH 02/71] allows navmeshes to generate for most scene objects, and adds a NavMeshIgnore method for object-instances to filter them out. --- Engine/source/navigation/navMesh.cpp | 14 +++++++++++++- Engine/source/scene/sceneObject.cpp | 1 + Engine/source/scene/sceneObject.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Engine/source/navigation/navMesh.cpp b/Engine/source/navigation/navMesh.cpp index f029c5deb..db70d1cc3 100644 --- a/Engine/source/navigation/navMesh.cpp +++ b/Engine/source/navigation/navMesh.cpp @@ -145,6 +145,17 @@ DefineConsoleFunction(NavMeshUpdateAroundObject, void, (S32 objid, bool remove), obj->enableCollision(); } + +DefineConsoleFunction(NavMeshIgnore, void, (S32 objid, bool _ignore), (0, true), + "@brief Flag this object as not generating a navmesh result.") +{ + SceneObject *obj; + if(!Sim::findObject(objid, obj)) + return; + + obj->mPathfindingIgnore = _ignore; +} + DefineConsoleFunction(NavMeshUpdateOne, void, (S32 meshid, S32 objid, bool remove), (0, 0, false), "@brief Update all tiles in a given NavMesh that intersect the given object's world box.") { @@ -839,6 +850,7 @@ void NavMesh::buildNextTile() static void buildCallback(SceneObject* object,void *key) { SceneContainer::CallbackInfo* info = reinterpret_cast(key); + if (!object->mPathfindingIgnore) object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere); } @@ -861,7 +873,7 @@ unsigned char *NavMesh::buildTileData(const Tile &tile, TileData &data, U32 &dat data.geom.clear(); info.polyList = &data.geom; info.key = this; - getContainer()->findObjects(box, StaticShapeObjectType | TerrainObjectType, buildCallback, &info); + getContainer()->findObjects(box, StaticObjectType | DynamicShapeObjectType, buildCallback, &info); // Parse water objects into the same list, but remember how much geometry was /not/ water. U32 nonWaterVertCount = data.geom.getVertCount(); diff --git a/Engine/source/scene/sceneObject.cpp b/Engine/source/scene/sceneObject.cpp index 1420bac11..1d16377af 100644 --- a/Engine/source/scene/sceneObject.cpp +++ b/Engine/source/scene/sceneObject.cpp @@ -144,6 +144,7 @@ SceneObject::SceneObject() mIsScopeAlways = false; mAccuTex = NULL; + mPathfindingIgnore = false; } //----------------------------------------------------------------------------- diff --git a/Engine/source/scene/sceneObject.h b/Engine/source/scene/sceneObject.h index 42c3c53ed..3985d372c 100644 --- a/Engine/source/scene/sceneObject.h +++ b/Engine/source/scene/sceneObject.h @@ -371,6 +371,7 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce SceneObject(); virtual ~SceneObject(); + bool mPathfindingIgnore; /// Triggered when a SceneObject onAdd is called. static Signal< void( SceneObject* ) > smSceneObjectAdd; From 00cc94901179d8405179b45dc559692219401a5e Mon Sep 17 00:00:00 2001 From: Azaezel Date: Fri, 15 Apr 2016 00:20:55 -0500 Subject: [PATCH 03/71] reimplements a form of subsurface scattering --- .../materials/processedShaderMaterial.cpp | 3 ++- .../lighting/advanced/vectorLightP.hlsl | 13 +++++++++-- .../gui/guiMaterialPropertiesWindow.ed.gui | 23 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index 6ff609ebe..cd230ef53 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -1153,7 +1153,8 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons // Deferred Shading: Determine Material Info Flags S32 matInfoFlags = - (mMaterial->mEmissive[stageNum] ? 1 : 0); + (mMaterial->mEmissive[stageNum] ? 1 : 0) | //emissive + (mMaterial->mSubSurface[stageNum] ? 2 : 0); //subsurface mMaterial->mMatInfoFlags[stageNum] = matInfoFlags / 255.0f; shaderConsts->setSafe(handles->mMatInfoFlagsSC, mMaterial->mMatInfoFlags[stageNum]); if( handles->mAccuScaleSC->isValid() ) diff --git a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl index 1a9726171..e6ec5afb9 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl @@ -202,6 +202,16 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0 return float4(1.0, 1.0, 1.0, 0.0); } + float4 colorSample = TORQUE_TEX2D( colorBuffer, IN.uv0 ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface =colorSample; + if (colorSample.r>colorSample.g) + subsurface.r*=2; + else + subsurface.g*=2; + } // Sample/unpack the normal/z data float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, IN.uv0 ); float3 normal = prepassSample.rgb; @@ -314,6 +324,5 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0 lightColorOut = debugColor; #endif - float4 colorSample = TORQUE_TEX2D( colorBuffer, IN.uv0 ); - return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + return AL_DeferredOutput(lightColorOut+subsurface*(2.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui b/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui index 63ce28e2a..1e3b98189 100644 --- a/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui +++ b/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui @@ -2240,6 +2240,29 @@ useMouseEvents = "0"; useInactiveState = "0"; }; + new GuiCheckBoxCtrl() { + canSaveDynamicFields = "0"; + internalName = "subSurfaceCheckbox"; + Enabled = "1"; + isContainer = "0"; + Profile = "ToolsGuiCheckBoxProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "8 46"; + Extent = "79 16"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + Command = "MaterialEditorGui.updateActiveMaterial(\"subSurface[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());"; + tooltipprofile = "ToolsGuiDefaultProfile"; + ToolTip = "Enables the use of subsurface scattering for this layer."; + hovertime = "1000"; + text = "Sub Surface"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + useInactiveState = "0"; + }; }; }; }; From 88356ae37f23ef97ac46607a85a7a42873d4cbec Mon Sep 17 00:00:00 2001 From: Azaezel Date: Fri, 15 Apr 2016 16:06:10 -0500 Subject: [PATCH 04/71] subsurface followup: cleanups and corrections for vectorlightP, fillins for spot, point, and opengl equivalents --- .../common/lighting/advanced/gl/pointLightP.glsl | 14 ++++++++++++-- .../common/lighting/advanced/gl/spotLightP.glsl | 14 ++++++++++++-- .../common/lighting/advanced/gl/vectorLightP.glsl | 14 ++++++++++++-- .../common/lighting/advanced/pointLightP.hlsl | 13 +++++++++++-- .../common/lighting/advanced/spotLightP.hlsl | 14 ++++++++++++-- .../common/lighting/advanced/vectorLightP.hlsl | 8 ++++---- 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl index 8a1aae3ca..8fe127e04 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl @@ -147,6 +147,17 @@ void main() return; } + vec4 colorSample = texture( colorBuffer, uvScene ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); vec3 normal = prepassSample.rgb; @@ -258,6 +269,5 @@ void main() addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); } - vec4 colorSample = texture( colorBuffer, uvScene ); - OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl index e7f3e88a7..c6ffa02a0 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl @@ -89,6 +89,17 @@ void main() return; } + vec4 colorSample = texture( colorBuffer, uvScene ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); vec3 normal = prepassSample.rgb; @@ -195,6 +206,5 @@ void main() addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); } - vec4 colorSample = texture( colorBuffer, uvScene ); - OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl index 608524a5a..15e0bf477 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl @@ -202,6 +202,17 @@ void main() return; } + vec4 colorSample = texture( colorBuffer, uv0 ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 ); vec3 normal = prepassSample.rgb; @@ -312,6 +323,5 @@ void main() lightColorOut = debugColor; #endif - vec4 colorSample = texture( colorBuffer, uv0 ); - OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl index 540fd65c7..a8c0ea105 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl @@ -149,6 +149,16 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 { return float4(0.0, 0.0, 0.0, 0.0); } + float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = float3(0.772549, 0.337255, 0.262745); + else + subsurface = float3(0.337255, 0.772549, 0.262745); + } // Sample/unpack the normal/z data float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, uvScene ); @@ -263,6 +273,5 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); } - float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); - return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl index e1f3baf93..5040b15e2 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl @@ -87,6 +87,17 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 return float4(0.0, 0.0, 0.0, 0.0); } + float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = float3(0.772549, 0.337255, 0.262745); + else + subsurface = float3(0.337255, 0.772549, 0.262745); + } + // Sample/unpack the normal/z data float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, uvScene ); float3 normal = prepassSample.rgb; @@ -194,6 +205,5 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); } - float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); - return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl index e6ec5afb9..956227909 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl @@ -206,11 +206,11 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0 float3 subsurface = float3(0.0,0.0,0.0); if (getFlag( matInfo.r, 1 )) { - subsurface =colorSample; + subsurface = colorSample.rgb; if (colorSample.r>colorSample.g) - subsurface.r*=2; + subsurface = float3(0.772549, 0.337255, 0.262745); else - subsurface.g*=2; + subsurface = float3(0.337255, 0.772549, 0.262745); } // Sample/unpack the normal/z data float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, IN.uv0 ); @@ -324,5 +324,5 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0 lightColorOut = debugColor; #endif - return AL_DeferredOutput(lightColorOut+subsurface*(2.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); } From 587ab6a39eed09709a01aefd4ae1fbd40a083151 Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 20 Apr 2016 00:46:41 -0500 Subject: [PATCH 05/71] Adds 2 fields to expose the net simulation functionality more readily to the NetGraph GUI. Also added a Tools option to the World Editor menubar, with the NetGraph as the first option to make it easier to activate the NetGraph in the editor. --- .../Full/game/core/art/gui/netGraphGui.gui | 425 +++++++++++++++--- .../worldEditor/scripts/menuHandlers.ed.cs | 9 + .../tools/worldEditor/scripts/menus.ed.cs | 12 + 3 files changed, 393 insertions(+), 53 deletions(-) diff --git a/Templates/Full/game/core/art/gui/netGraphGui.gui b/Templates/Full/game/core/art/gui/netGraphGui.gui index b62e8ea23..b034a447e 100644 --- a/Templates/Full/game/core/art/gui/netGraphGui.gui +++ b/Templates/Full/game/core/art/gui/netGraphGui.gui @@ -73,100 +73,380 @@ new GuiControlProfile (NetGraphPacketLossProfile) }; //--- OBJECT WRITE BEGIN --- -new GuiControl(NetGraphGui) { - profile = "NetGraphProfile"; +%guiContent = new GuiControl(NetGraphGui) { + position = "0 0"; + extent = "1024 768"; + minExtent = "8 2"; horizSizing = "left"; vertSizing = "bottom"; - position = "0 0"; - extent = "640 480"; - minExtent = "8 2"; + profile = "NetGraphProfile"; visible = "1"; - noCursor = "1"; - + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "1"; + noCursor = "1"; + new GuiGraphCtrl(NetGraph) { - profile = "NetGraphKeyContainerProfile"; - horizSizing = "left"; - vertSizing = "bottom"; - position = "432 5"; + centerY = "1"; + plotColor[0] = "1 1 1 1"; + plotColor[1] = "1 0 0 1"; + plotColor[2] = "0 1 0 1"; + plotColor[3] = "0 0 1 1"; + plotColor[4] = "0 1 1 1"; + plotColor[5] = "0 0 0 1"; + plotType[0] = "PolyLine"; + plotType[1] = "PolyLine"; + plotType[2] = "PolyLine"; + plotType[3] = "PolyLine"; + plotType[4] = "PolyLine"; + plotType[5] = "PolyLine"; + plotInterval[0] = "0"; + plotInterval[1] = "0"; + plotInterval[2] = "0"; + plotInterval[3] = "0"; + plotInterval[4] = "0"; + plotInterval[5] = "0"; + position = "816 5"; extent = "200 200"; minExtent = "8 2"; - visible = "1"; - }; - - new GuiControl() { - profile = "NetGraphKeyContainerProfile"; horizSizing = "left"; vertSizing = "bottom"; - position = "432 205"; - extent = "200 52"; - minExtent = "8 2"; + profile = "NetGraphKeyContainerProfile"; visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiControl() { + position = "816 205"; + extent = "200 104"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphKeyContainerProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; new GuiTextCtrl(GhostsActive) { - profile = "NetGraphGhostsActiveProfile"; - horizSizing = "left"; - vertSizing = "bottom"; + text = "Ghosts Active"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; position = "0 0"; extent = "100 18"; minExtent = "8 2"; - visible = "1"; - text = "Ghosts Active"; - maxLength = "255"; - }; - new GuiTextCtrl(GhostUpdates) { - profile = "NetGraphGhostUpdatesProfile"; horizSizing = "left"; vertSizing = "bottom"; + profile = "NetGraphGhostsActiveProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(GhostUpdates) { + text = "Ghost Updates"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; position = "100 0"; extent = "100 18"; minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphGhostUpdatesProfile"; visible = "1"; - text = "Ghost Updates"; - maxLength = "255"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; }; new GuiTextCtrl(BitsSent) { - profile = "NetGraphBitsSentProfile"; - horizSizing = "left"; - vertSizing = "bottom"; - position = "0 18 "; - extent = "100 18"; - minExtent = "8 2"; - visible = "1"; text = "Bytes Sent"; maxLength = "255"; - }; - new GuiTextCtrl(BitsReceived) { - profile = "NetGraphBitsReceivedProfile"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "0 18"; + extent = "100 18"; + minExtent = "8 2"; horizSizing = "left"; vertSizing = "bottom"; + profile = "NetGraphBitsSentProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(BitsReceived) { + text = "Bytes Received"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; position = "100 18"; extent = "100 18"; minExtent = "8 2"; - visible = "1"; - text = "Bytes Received"; - maxLength = "255"; - }; - new GuiTextCtrl(Latency) { - profile = "NetGraphLatencyProfile"; horizSizing = "left"; vertSizing = "bottom"; + profile = "NetGraphBitsReceivedProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(Latency) { + text = "Latency"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; position = "0 36"; extent = "100 18"; minExtent = "8 2"; - visible = "1"; - text = "Latency"; - maxLength = "255"; - }; - new GuiTextCtrl(PacketLoss) { - profile = "NetGraphPacketLossProfile"; horizSizing = "left"; vertSizing = "bottom"; + profile = "NetGraphLatencyProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(PacketLoss) { + text = "Packet Loss"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; position = "100 36"; extent = "59 18"; minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; visible = "1"; - text = "Packet Loss"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "Network Simulation:"; maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "0 52"; + extent = "97 18"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "Simulated Latency:"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "0 68"; + extent = "91 18"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "ms"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "179 68"; + extent = "20 18"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextEditCtrl(NetGraphSimLatency) { + historySize = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + password = "0"; + passwordMask = "*"; + text = "0"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "112 67"; + extent = "64 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextEditProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "Simulated Packet Loss:"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "0 83"; + extent = "111 18"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "%"; + maxLength = "255"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "179 84"; + extent = "20 18"; + minExtent = "8 2"; + horizSizing = "left"; + vertSizing = "bottom"; + profile = "NetGraphPacketLossProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextEditCtrl(NetGraphSimPacket) { + historySize = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + password = "0"; + passwordMask = "*"; + text = "0"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "112 85"; + extent = "64 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextEditProfile"; + visible = "1"; + active = "1"; + command = "if(NetGraphSimLatency.text $= \"\" || NetGraphSimLatency.text < 0)\n{\n NetGraphSimLatency.text = 0;\n}\n\nif(NetGraphSimPacket.text $= \"\" || NetGraphSimPacket.text < 0)\n{\n NetGraphSimLatency.text = 0;\n}\nelse if(NetGraphSimPacket.text > 100)\n{\n NetGraphSimPacket.text = 100;\n}\n\nnetSimulateLag( NetGraphSimLatency.text, NetGraphSimPacket.text );"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; }; }; }; @@ -186,7 +466,10 @@ function toggleNetGraph() Canvas.add(NetGraphGui); } else + { Canvas.remove(NetGraphGui); + netSimulateLag( 0, 0 ); + } } function NetGraph::updateStats() @@ -236,3 +519,39 @@ function NetGraph::toggleKey() PacketLoss.visible = 0; } } + +function NetGraphSimLatency::onReturn(%this) +{ + NetGraph.updateNetworkSimulation(); +} + +function NetGraphSimPacket::onReturn(%this) +{ + NetGraph.updateNetworkSimulation(); +} + +function NetGraph::updateNetworkSimulation(%this) +{ + %latency = NetGraphSimLatency.getText(); + + if(%latency $= "" || %latency < 0) + { + NetGraphSimLatency.text = 0; + %latency = 0; + } + + %packetLoss = NetGraphSimPacket.getText(); + + if(%packetLoss $= "" || %packetLoss < 0) + { + NetGraphSimLatency.text = 0; + %packetLoss = 0; + } + else if(%packetLoss > 100) + { + NetGraphSimPacket.text = 100; + %packetLoss = 100; + } + + netSimulateLag( %latency, %packetLoss ); +} \ No newline at end of file diff --git a/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs index b2a2f209e..61f214151 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs @@ -770,6 +770,15 @@ function EditorCameraSpeedMenu::setupGuiControls(%this) // Set up min/max camera slider range eval("CameraSpeedDropdownCtrlContainer-->Slider.range = \"" @ %minSpeed @ " " @ %maxSpeed @ "\";"); } + +////////////////////////////////////////////////////////////////////////// +// Tools Menu Handler +////////////////////////////////////////////////////////////////////////// +function EditorUtilitiesMenu::onSelectItem(%this, %id, %text) +{ + return Parent::onSelectItem(%this, %id, %text); +} + ////////////////////////////////////////////////////////////////////////// // World Menu Handler Object Menu ////////////////////////////////////////////////////////////////////////// diff --git a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs index 1e378ae11..102931dec 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs @@ -252,6 +252,18 @@ function EditorGui::buildMenus(%this) // last menu items in EditorLightingMenu::onAdd(). }; %this.menuBar.insert(%lightingMenu, %this.menuBar.getCount()); + + // Tools Menu + %toolsMenu = new PopupMenu() + { + superClass = "MenuBuilder"; + class = "EditorUtilitiesMenu"; + + barTitle = "Tools"; + + item[0] = "Network Graph" TAB "n" TAB "toggleNetGraph();"; + }; + %this.menuBar.insert(%toolsMenu, %this.menuBar.getCount()); // Help Menu %helpMenu = new PopupMenu() From 25d2fd877b0c7076c98cd2019106b8d373ab32a3 Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 20 Apr 2016 01:06:31 -0500 Subject: [PATCH 06/71] Makes the profiler pop-up act on a toggle, and also adds an entry into the World Editor's Tool menu to easily activate it. --- Templates/Full/game/scripts/client/default.bind.cs | 7 ++++++- Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Templates/Full/game/scripts/client/default.bind.cs b/Templates/Full/game/scripts/client/default.bind.cs index d2ca23730..9dcbca96b 100644 --- a/Templates/Full/game/scripts/client/default.bind.cs +++ b/Templates/Full/game/scripts/client/default.bind.cs @@ -618,7 +618,12 @@ GlobalActionMap.bind(keyboard, "ctrl o", bringUpOptions); function showMetrics(%val) { if(%val) - metrics("fps gfx shadow sfx terrain groundcover forest net"); + { + if(!Canvas.isMember(FrameOverlayGui)) + metrics("fps gfx shadow sfx terrain groundcover forest net"); + else + metrics(""); + } } GlobalActionMap.bind(keyboard, "ctrl F2", showMetrics); diff --git a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs index 102931dec..0916a0065 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs @@ -262,6 +262,7 @@ function EditorGui::buildMenus(%this) barTitle = "Tools"; item[0] = "Network Graph" TAB "n" TAB "toggleNetGraph();"; + item[1] = "Profiler" TAB "ctrl F2" TAB "showMetrics(true);"; }; %this.menuBar.insert(%toolsMenu, %this.menuBar.getCount()); From 3d6803865c46a4ea29e5f8ac1704fe13a00bba60 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 25 Apr 2016 11:36:23 -0500 Subject: [PATCH 07/71] missing samplerstate configurations --- .../scripts/client/lighting/advanced/shaders.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs index eaf7f70b8..22d1bdbdf 100644 --- a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs @@ -39,9 +39,11 @@ new GFXStateBlockData( AL_VectorLightState ) mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) mSamplerNames[1] = "shadowMap"; - samplerStates[2] = SamplerClampLinear; // SSAO Mask - mSamplerNames[2] = "ssaoMask"; - samplerStates[3] = SamplerWrapPoint; // Random Direction Map + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // SSAO Mask + mSamplerNames[3] = "ssaoMask"; + samplerStates[4] = SamplerWrapPoint; // Random Direction Map cullDefined = true; cullMode = GFXCullNone; @@ -114,8 +116,10 @@ new GFXStateBlockData( AL_ConvexLightState ) mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) mSamplerNames[1] = "shadowMap"; - samplerStates[2] = SamplerClampLinear; // Cookie Map - samplerStates[3] = SamplerWrapPoint; // Random Direction Map + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // Cookie Map + samplerStates[4] = SamplerWrapPoint; // Random Direction Map cullDefined = true; cullMode = GFXCullCW; From 86dd8a8cf71a5d66050119672ce301154e5905a0 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 30 Apr 2016 23:32:10 -0500 Subject: [PATCH 08/71] Adds a onPostAdd callback to simObject so we can do handling AFTER the object and it's children have been added successfully. --- Engine/source/console/compiledEval.cpp | 4 ++++ Engine/source/console/simObject.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index bd4a7a5d9..a989826b4 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -994,6 +994,7 @@ breakContinue: // This error is usually caused by failing to call Parent::initPersistFields in the class' initPersistFields(). Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip), currentNewObject->getName(), currentNewObject->getClassName()); delete currentNewObject; + currentNewObject = NULL; ip = failJump; // Prevent stack value corruption CSTK.popFrame(); @@ -1094,6 +1095,9 @@ breakContinue: case OP_FINISH_OBJECT: { + if (currentNewObject) + currentNewObject->onPostAdd(); + //Assert( objectCreationStackIndex >= 0 ); // Restore the object info from the stack [7/9/2007 Black] currentNewObject = objectCreationStack[ --objectCreationStackIndex ].newObject; diff --git a/Engine/source/console/simObject.h b/Engine/source/console/simObject.h index eb6f3f0e0..8a38e8675 100644 --- a/Engine/source/console/simObject.h +++ b/Engine/source/console/simObject.h @@ -606,6 +606,10 @@ class SimObject: public ConsoleObject, public TamlCallbacks /// Called when the object's name is changed. virtual void onNameChange(const char *name); + /// Called when the adding of the object to the sim is complete, all sub-objects have been processed as well + // This is a special-case function that only really gets used with Entities/BehaviorObjects. + virtual void onPostAdd() {} + /// /// Specifically, these are called by setDataField /// when a static or dynamic field is modified, see From de0fe06bc89e045d02ab5ec06f5520d5b854bdbb Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 30 Apr 2016 23:34:54 -0500 Subject: [PATCH 09/71] Makes netObjects inherit off simGroup as opposed to simObject so that just about any object can function as a parent with children. --- Engine/source/sim/netObject.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/sim/netObject.h b/Engine/source/sim/netObject.h index c6a9ca99e..ced8a2cf3 100644 --- a/Engine/source/sim/netObject.h +++ b/Engine/source/sim/netObject.h @@ -217,7 +217,7 @@ struct GhostInfo; /// the documentation on AbstractClassRep for more details. /// /// @nosubgrouping -class NetObject: public SimObject +class NetObject : public SimGroup { // The Ghost Manager needs read/write access friend class NetConnection; @@ -228,7 +228,7 @@ class NetObject: public SimObject friend class GhostAlwaysObjectEvent; private: - typedef SimObject Parent; + typedef SimGroup Parent; /// Mask indicating which states are dirty and need to be retransmitted on this /// object. From b3bc199975ae4c0eb59a8677071702ca8a25186f Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 30 Apr 2016 23:38:35 -0500 Subject: [PATCH 10/71] Adds a TypeSimObjectPtr type for easy reference to other objects as a field. --- Engine/source/console/consoleTypes.cpp | 25 +++++++++++++++++++++++++ Engine/source/console/consoleTypes.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/Engine/source/console/consoleTypes.cpp b/Engine/source/console/consoleTypes.cpp index 6c993c446..09765bf34 100644 --- a/Engine/source/console/consoleTypes.cpp +++ b/Engine/source/console/consoleTypes.cpp @@ -710,6 +710,31 @@ ConsoleSetType( TypeColorI ) Con::printf("Color must be set as { r, g, b [,a] }, { r g b [b] } or { stockColorName }"); } +//----------------------------------------------------------------------------- +// TypeSimObjectPtr +//----------------------------------------------------------------------------- +ConsoleType(SimObject, TypeSimObjectPtr, SimObject*, "") + +ConsoleSetType(TypeSimObjectPtr) +{ + if (argc == 1) + { + SimObject **obj = (SimObject **)dptr; + *obj = Sim::findObject(argv[0]); + } + else + Con::printf("(TypeSimObjectPtr) Cannot set multiple args to a single S32."); +} + +ConsoleGetType(TypeSimObjectPtr) +{ + SimObject **obj = (SimObject**)dptr; + static const U32 bufSize = 128; + char* returnBuffer = Con::getReturnBuffer(bufSize); + dSprintf(returnBuffer, bufSize, "%s", *obj ? (*obj)->getName() ? (*obj)->getName() : (*obj)->getIdString() : ""); + return returnBuffer; +} + //----------------------------------------------------------------------------- // TypeSimObjectName //----------------------------------------------------------------------------- diff --git a/Engine/source/console/consoleTypes.h b/Engine/source/console/consoleTypes.h index c026b8e1a..ce5e7134a 100644 --- a/Engine/source/console/consoleTypes.h +++ b/Engine/source/console/consoleTypes.h @@ -123,6 +123,8 @@ DefineConsoleType( TypeColorF, ColorF ) DefineConsoleType( TypeSimObjectName, SimObject* ) DefineConsoleType( TypeShader, GFXShader * ) +DefineConsoleType(TypeSimObjectPtr, SimObject*) + /// A persistent reference to an object. This reference indirectly goes /// through the referenced object's persistent ID. DefineConsoleType( TypeSimPersistId, SimPersistID* ) From bc9033da2e51cbeb7722157d6c4da03cd29f002e Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 6 May 2016 16:45:18 -0500 Subject: [PATCH 11/71] Rolls back OGL Projection correction. Epoxy looks to handle the projection depth range so it behaves more like D3D, so this change was doubling up and causing problems. --- Engine/source/math/mathUtils.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Engine/source/math/mathUtils.cpp b/Engine/source/math/mathUtils.cpp index ea57d93c3..dba228fde 100644 --- a/Engine/source/math/mathUtils.cpp +++ b/Engine/source/math/mathUtils.cpp @@ -30,7 +30,6 @@ #include "platform/profiler.h" #include "core/tAlgorithm.h" -#include "gfx/gfxDevice.h" namespace MathUtils { @@ -1450,8 +1449,6 @@ void makeProjection( MatrixF *outMatrix, F32 farPlane, bool gfxRotate ) { - bool isGL = GFX->getAdapterType() == OpenGL; - Point4F row; row.x = 2.0*nearPlane / (right-left); row.y = 0.0; @@ -1467,13 +1464,13 @@ void makeProjection( MatrixF *outMatrix, row.x = (left+right) / (right-left); row.y = (top+bottom) / (top-bottom); - row.z = isGL ? -(farPlane + nearPlane) / (farPlane - nearPlane) : farPlane / (nearPlane - farPlane); + row.z = farPlane / (nearPlane - farPlane); row.w = -1.0; outMatrix->setRow( 2, row ); row.x = 0.0; row.y = 0.0; - row.z = isGL ? 2 * nearPlane * farPlane / (nearPlane - farPlane) : nearPlane * farPlane / (nearPlane - farPlane); + row.z = nearPlane * farPlane / (nearPlane - farPlane); row.w = 0.0; outMatrix->setRow( 3, row ); @@ -1494,8 +1491,6 @@ void makeOrthoProjection( MatrixF *outMatrix, F32 farPlane, bool gfxRotate ) { - bool isGL = GFX->getAdapterType() == OpenGL; - Point4F row; row.x = 2.0f / (right - left); row.y = 0.0f; @@ -1513,15 +1508,15 @@ void makeOrthoProjection( MatrixF *outMatrix, row.y = 0.0f; row.w = 0.0f; - // This needs to be modified to work with OpenGL (d3d has 0..1 - // projection for z, vs -1..1 in OpenGL) - row.z = isGL ? 2.0f / (nearPlane - farPlane) : 1.0f / (nearPlane - farPlane); + //Unlike D3D, which has a 0-1 range, OpenGL uses a -1-1 range. + //However, epoxy internally handles the swap, so the math here is the same for both APIs + row.z = 1.0f / (nearPlane - farPlane); outMatrix->setRow( 2, row ); row.x = (left + right) / (left - right); row.y = (top + bottom) / (bottom - top); - row.z = isGL ? (nearPlane + farPlane) / (nearPlane - farPlane) : nearPlane / (nearPlane - farPlane); + row.z = nearPlane / (nearPlane - farPlane); row.w = 1.0f; outMatrix->setRow( 3, row ); From a216b4515ba83ef259163cb4f2b90d467dd6a329 Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Fri, 6 May 2016 21:24:52 -0400 Subject: [PATCH 12/71] remove old legacy extensions that aren't being used. --- Engine/source/gfx/gl/gfxGLCardProfiler.cpp | 38 +------------------- Engine/source/gfx/gl/gfxGLDevice.cpp | 2 +- Engine/source/gfx/gl/gfxGLTextureManager.cpp | 3 +- Engine/source/gfx/gl/gfxGLTextureObject.cpp | 4 +-- 4 files changed, 5 insertions(+), 42 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp index 46119253b..bc40d30a9 100644 --- a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp +++ b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp @@ -65,45 +65,9 @@ void GFXGLCardProfiler::setupCardCapabilities() setCapability("maxTextureHeight", maxTexSize); setCapability("maxTextureSize", maxTexSize); - // If extensions haven't been inited, we're in trouble here. - bool suppVBO = (gglHasExtension(ARB_vertex_buffer_object) || glVersion >= 1.499f); - setCapability("GL::suppVertexBufferObject", suppVBO); - - // check if render to texture supported is available - bool suppRTT = gglHasExtension(EXT_framebuffer_object); - setCapability("GL::suppRenderTexture", suppRTT); - - bool suppBlit = gglHasExtension(EXT_framebuffer_blit); - setCapability("GL::suppRTBlit", suppBlit); - - bool suppFloatTex = gglHasExtension(ARB_texture_float); - setCapability("GL::suppFloatTexture", suppFloatTex); - // Check for anisotropic filtering support. bool suppAnisotropic = gglHasExtension( EXT_texture_filter_anisotropic ); - setCapability( "GL::suppAnisotropic", suppAnisotropic ); - - // check to see if we have the fragment shader extension or the gl version is high enough for glsl to be core - // also check to see if the language version is high enough - F32 glslVersion = dAtof(reinterpret_cast(glGetString( GL_SHADING_LANGUAGE_VERSION))); - bool suppSPU = (gglHasExtension(ARB_fragment_shader) || glVersion >= 1.999f) && glslVersion >= 1.0999; - setCapability("GL::suppFragmentShader", suppSPU); - - bool suppAppleFence = gglHasExtension(APPLE_fence); - setCapability("GL::APPLE::suppFence", suppAppleFence); - - // When enabled, call glGenerateMipmapEXT() to generate mipmaps instead of relying on GL_GENERATE_MIPMAP - setCapability("GL::Workaround::needsExplicitGenerateMipmap", false); - // When enabled, binds and unbinds a texture target before doing the depth buffer copy. Failure to do - // so will cause a hard freeze on Mac OS 10.4 with a Radeon X1600 - setCapability("GL::Workaround::X1600DepthBufferCopy", false); - // When enabled, does not copy the last column and row of the depth buffer in a depth buffer copy. Failure - // to do so will cause a kernel panic on Mac OS 10.5(.1) with a Radeon HD 2600 (fixed in 10.5.2) - setCapability("GL::Workaround::HD2600DepthBufferCopy", false); - - // Certain Intel drivers have a divide by 0 crash if mipmaps are specified with - // glTexSubImage2D. - setCapability("GL::Workaround::noManualMips", false); + setCapability( "GL_EXT_TEXTURE_FILTER_ANISOTROPIC", suppAnisotropic ); } bool GFXGLCardProfiler::_queryCardCap(const String& query, U32& foundResult) diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index f59e8ac92..18aa0822b 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -143,7 +143,7 @@ void GFXGLDevice::initGLState() // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. mPixelShaderVersion = 3.0; - mSupportsAnisotropic = mCardProfiler->queryProfile( "GL::suppAnisotropic" ); + mSupportsAnisotropic = mCardProfiler->queryProfile( "GL_EXT_TEXTURE_FILTER_ANISOTROPIC" ); String vendorStr = (const char*)glGetString( GL_VENDOR ); if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos) diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index 70a5e4303..8966da806 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -304,8 +304,7 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) glBindTexture(texture->getBinding(), texture->getHandle()); texture->mFormat = dds->mFormat; U32 numMips = dds->mSurfaces[0]->mMips.size(); - if(GFX->getCardProfiler()->queryProfile("GL::Workaround::noManualMips")) - numMips = 1; + for(U32 i = 0; i < numMips; i++) { if(isCompressedFormat(dds->mFormat)) diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index ed229e5d9..b4f43a7d5 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -298,8 +298,8 @@ void GFXGLTextureObject::reloadFromCache() else if(mBinding == GL_TEXTURE_1D) glTexSubImage1D(mBinding, 0, 0, (mTextureSize.x > 1 ? mTextureSize.x : mTextureSize.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); - if(GFX->getCardProfiler()->queryProfile("GL::Workaround::needsExplicitGenerateMipmap") && mMipLevels != 1) - glGenerateMipmapEXT(mBinding); + if(mMipLevels != 1) + glGenerateMipmap(mBinding); delete[] mZombieCache; mZombieCache = NULL; From f9b2aa397f3a180c2cf14e215aa356a99f382c7c Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Fri, 6 May 2016 21:50:11 -0400 Subject: [PATCH 13/71] cache OpenGL extensions that are not part of the 3.3 core profile, and that run more than initialization setup. --- Engine/source/gfx/gl/gfxGLCardProfiler.cpp | 24 +++++++++++++++---- .../gfx/gl/gfxGLCircularVolatileBuffer.h | 6 ++--- Engine/source/gfx/gl/gfxGLDevice.cpp | 13 +++++++++- Engine/source/gfx/gl/gfxGLDevice.h | 12 ++++++++++ Engine/source/gfx/gl/gfxGLShader.cpp | 3 ++- Engine/source/gfx/gl/gfxGLStateBlock.cpp | 4 ++-- Engine/source/gfx/gl/gfxGLTextureManager.cpp | 2 +- Engine/source/gfx/gl/gfxGLTextureObject.cpp | 2 +- Engine/source/gfx/gl/gfxGLTextureTarget.cpp | 2 +- Engine/source/gfx/gl/gfxGLVertexBuffer.cpp | 4 ++-- Engine/source/gfx/gl/gfxGLVertexDecl.cpp | 4 ++-- Engine/source/gfx/gl/gfxGLWindowTarget.cpp | 2 +- 12 files changed, 58 insertions(+), 20 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp index bc40d30a9..766f06bb2 100644 --- a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp +++ b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp @@ -56,9 +56,6 @@ void GFXGLCardProfiler::setupCardCapabilities() { GLint maxTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); - - const char* versionString = reinterpret_cast(glGetString(GL_VERSION)); - F32 glVersion = dAtof(versionString); // OpenGL doesn't have separate maximum width/height. setCapability("maxTextureWidth", maxTexSize); @@ -66,8 +63,25 @@ void GFXGLCardProfiler::setupCardCapabilities() setCapability("maxTextureSize", maxTexSize); // Check for anisotropic filtering support. - bool suppAnisotropic = gglHasExtension( EXT_texture_filter_anisotropic ); - setCapability( "GL_EXT_TEXTURE_FILTER_ANISOTROPIC", suppAnisotropic ); + setCapability("GL_EXT_texture_filter_anisotropic", gglHasExtension(EXT_texture_filter_anisotropic)); + + // Check for buffer storage + setCapability("GL_ARB_buffer_storage", gglHasExtension(ARB_buffer_storage)); + + // Check for shader model 5.0 + setCapability("GL_ARB_gpu_shader5", gglHasExtension(ARB_gpu_shader5)); + + // Check for texture storage + setCapability("GL_ARB_texture_storage", gglHasExtension(ARB_texture_storage)); + + // Check for sampler objects + setCapability("GL_ARB_sampler_objects", gglHasExtension(ARB_sampler_objects)); + + // Check for copy image support + setCapability("GL_ARB_copy_image", gglHasExtension(ARB_copy_image)); + + // Check for vertex attrib binding + setCapability("GL_ARB_vertex_attrib_binding", gglHasExtension(ARB_vertex_attrib_binding)); } bool GFXGLCardProfiler::_queryCardCap(const String& query, U32& foundResult) diff --git a/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h index 6d7d0e4b1..6047255eb 100644 --- a/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h +++ b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h @@ -158,7 +158,7 @@ public: const U32 cSizeInMB = 10; mBufferSize = (cSizeInMB << 20); - if( gglHasExtension(ARB_buffer_storage) ) + if( GFXGL->mCapabilities.bufferStorage ) { const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; glBufferStorage(mBinding, mBufferSize, NULL, flags); @@ -198,7 +198,7 @@ public: outOffset = mBufferFreePos; - if( gglHasExtension(ARB_buffer_storage) ) + if( GFXGL->mCapabilities.bufferStorage ) { outPtr = (U8*)(mBufferPtr) + mBufferFreePos; } @@ -227,7 +227,7 @@ public: void unlock() { - if( gglHasExtension(ARB_buffer_storage) ) + if( GFXGL->mCapabilities.bufferStorage ) { return; } diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 18aa0822b..9e5df8886 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -140,10 +140,18 @@ void GFXGLDevice::initGLState() glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0 // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. mPixelShaderVersion = 3.0; - mSupportsAnisotropic = mCardProfiler->queryProfile( "GL_EXT_TEXTURE_FILTER_ANISOTROPIC" ); + // Set capability extensions. + mCapabilities.anisotropicFiltering = mCardProfiler->queryProfile("GL_EXT_texture_filter_anisotropic"); + mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage"); + mCapabilities.shaderModel5 = mCardProfiler->queryProfile("GL_ARB_gpu_shader5"); + mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage"); + mCapabilities.samplerObjects = mCardProfiler->queryProfile("GL_ARB_sampler_objects"); + mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image"); + mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding"); String vendorStr = (const char*)glGetString( GL_VENDOR ); if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos) @@ -216,6 +224,9 @@ GFXGLDevice::GFXGLDevice(U32 adapterIndex) : mCurrentVB_Divisor[i] = 0; } + // Initiailize capabilities to false. + memset(&mCapabilities, 0, sizeof(GLCapabilities)); + loadGLCore(); GFXGLEnumTranslate::init(); diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index 902bfb3f6..e7649c643 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -45,6 +45,18 @@ class GFXGLVertexDecl; class GFXGLDevice : public GFXDevice { public: + struct GLCapabilities + { + bool anisotropicFiltering; + bool bufferStorage; + bool shaderModel5; + bool textureStorage; + bool samplerObjects; + bool copyImage; + bool vertexAttributeBinding; + }; + GLCapabilities mCapabilities; + void zombify(); void resurrect(); GFXGLDevice(U32 adapterIndex); diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index 2e63c61fe..50578cb5b 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -23,6 +23,7 @@ #include "platform/platform.h" #include "gfx/gl/gfxGLShader.h" #include "gfx/gl/gfxGLVertexAttribLocation.h" +#include "gfx/gl/gfxGLDevice.h" #include "core/frameAllocator.h" #include "core/stream/fileStream.h" @@ -956,7 +957,7 @@ bool GFXGLShader::_loadShaderFromStream( GLuint shader, buffers.push_back( dStrdup( versionDecl ) ); lengths.push_back( dStrlen( versionDecl ) ); - if(gglHasExtension(ARB_gpu_shader5)) + if(GFXGL->mCapabilities.shaderModel5) { const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n"; buffers.push_back( dStrdup( extension ) ); diff --git a/Engine/source/gfx/gl/gfxGLStateBlock.cpp b/Engine/source/gfx/gl/gfxGLStateBlock.cpp index 34f816dc9..1d23e4b2c 100644 --- a/Engine/source/gfx/gl/gfxGLStateBlock.cpp +++ b/Engine/source/gfx/gl/gfxGLStateBlock.cpp @@ -39,7 +39,7 @@ GFXGLStateBlock::GFXGLStateBlock(const GFXStateBlockDesc& desc) : mDesc(desc), mCachedHashValue(desc.getHashValue()) { - if( !gglHasExtension(ARB_sampler_objects) ) + if( !GFXGL->mCapabilities.samplerObjects ) return; static Map mSamplersMap; @@ -165,7 +165,7 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) #undef CHECK_TOGGLE_STATE //sampler objects - if( gglHasExtension(ARB_sampler_objects) ) + if( GFXGL->mCapabilities.samplerObjects ) { for (U32 i = 0; i < getMin(getOwningDevice()->getNumSamplers(), (U32) TEXTURE_STAGE_COUNT); i++) { diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index 8966da806..c0d43087a 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -146,7 +146,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex, glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 ); - if( gglHasExtension(ARB_texture_storage) ) + if( GFXGL->mCapabilities.textureStorage ) { if(binding == GL_TEXTURE_2D) glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height ); diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index b4f43a7d5..219343b5f 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -211,7 +211,7 @@ void GFXGLTextureObject::bind(U32 textureUnit) glBindTexture(mBinding, mHandle); GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); - if( gglHasExtension(ARB_sampler_objects) ) + if(GFXGL->mCapabilities.samplerObjects) return; GFXGLStateBlockRef sb = mGLDevice->getCurrentStateBlock(); diff --git a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp index 202265107..384871dd9 100644 --- a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp @@ -410,7 +410,7 @@ void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj) AssertFatal(dynamic_cast(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast(obj); - if( gglHasExtension(ARB_copy_image) && mTargets[Color0]->isCompatible(glTexture) ) + if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) ) { GLenum binding = mTargets[Color0]->getBinding(); binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding; diff --git a/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp b/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp index 132172c1a..2cf4cb625 100644 --- a/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp +++ b/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp @@ -78,7 +78,7 @@ void GFXGLVertexBuffer::lock( U32 vertexStart, U32 vertexEnd, void **vertexPtr ) if( mBufferType == GFXBufferTypeVolatile ) { AssertFatal(vertexStart == 0, ""); - if( gglHasExtension(ARB_vertex_attrib_binding) ) + if( GFXGL->mCapabilities.vertexAttributeBinding ) { getCircularVolatileVertexBuffer()->lock( mNumVerts * mVertexSize, 0, mBufferOffset, *vertexPtr ); } @@ -136,7 +136,7 @@ void GFXGLVertexBuffer::prepare() void GFXGLVertexBuffer::prepare(U32 stream, U32 divisor) { - if( gglHasExtension(ARB_vertex_attrib_binding) ) + if( GFXGL->mCapabilities.vertexAttributeBinding ) { glBindVertexBuffer( stream, mBuffer, mBufferOffset, mVertexSize ); glVertexBindingDivisor( stream, divisor ); diff --git a/Engine/source/gfx/gl/gfxGLVertexDecl.cpp b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp index 10eda4401..948a2b2de 100644 --- a/Engine/source/gfx/gl/gfxGLVertexDecl.cpp +++ b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp @@ -15,7 +15,7 @@ void GFXGLVertexDecl::init(const GFXVertexFormat *format) void GFXGLVertexDecl::prepareVertexFormat() const { AssertFatal(mFormat, "GFXGLVertexDecl - Not inited"); - if( gglHasExtension(ARB_vertex_attrib_binding) ) + if( GFXGL->mCapabilities.vertexAttributeBinding ) { for ( U32 i=0; i < glVerticesFormat.size(); i++ ) { @@ -36,7 +36,7 @@ void GFXGLVertexDecl::prepareBuffer_old(U32 stream, GLint mBuffer, GLint mDiviso PROFILE_SCOPE(GFXGLVertexDecl_prepare); AssertFatal(mFormat, "GFXGLVertexDecl - Not inited"); - if( gglHasExtension(ARB_vertex_attrib_binding) ) + if( GFXGL->mCapabilities.vertexAttributeBinding ) return; // Bind the buffer... diff --git a/Engine/source/gfx/gl/gfxGLWindowTarget.cpp b/Engine/source/gfx/gl/gfxGLWindowTarget.cpp index 5f8808cae..116ad75e3 100644 --- a/Engine/source/gfx/gl/gfxGLWindowTarget.cpp +++ b/Engine/source/gfx/gl/gfxGLWindowTarget.cpp @@ -78,7 +78,7 @@ void GFXGLWindowTarget::resolveTo(GFXTextureObject* obj) AssertFatal(dynamic_cast(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast(obj); - if( gglHasExtension(ARB_copy_image) ) + if( GFXGL->mCapabilities.copyImage ) { if(mBackBufferColorTex.getWidth() == glTexture->getWidth() && mBackBufferColorTex.getHeight() == glTexture->getHeight() From a50600afaa4865b9b6edca3a6ab136b6a418921b Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Fri, 6 May 2016 22:57:35 -0400 Subject: [PATCH 14/71] tabs->spaces for TRON :) --- Engine/source/gfx/gl/gfxGLCardProfiler.cpp | 24 +++++++++++----------- Engine/source/gfx/gl/gfxGLDevice.cpp | 18 ++++++++-------- Engine/source/gfx/gl/gfxGLDevice.h | 22 ++++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp index 766f06bb2..760a0d5ed 100644 --- a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp +++ b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp @@ -65,23 +65,23 @@ void GFXGLCardProfiler::setupCardCapabilities() // Check for anisotropic filtering support. setCapability("GL_EXT_texture_filter_anisotropic", gglHasExtension(EXT_texture_filter_anisotropic)); - // Check for buffer storage - setCapability("GL_ARB_buffer_storage", gglHasExtension(ARB_buffer_storage)); + // Check for buffer storage + setCapability("GL_ARB_buffer_storage", gglHasExtension(ARB_buffer_storage)); - // Check for shader model 5.0 - setCapability("GL_ARB_gpu_shader5", gglHasExtension(ARB_gpu_shader5)); + // Check for shader model 5.0 + setCapability("GL_ARB_gpu_shader5", gglHasExtension(ARB_gpu_shader5)); - // Check for texture storage - setCapability("GL_ARB_texture_storage", gglHasExtension(ARB_texture_storage)); + // Check for texture storage + setCapability("GL_ARB_texture_storage", gglHasExtension(ARB_texture_storage)); - // Check for sampler objects - setCapability("GL_ARB_sampler_objects", gglHasExtension(ARB_sampler_objects)); + // Check for sampler objects + setCapability("GL_ARB_sampler_objects", gglHasExtension(ARB_sampler_objects)); - // Check for copy image support - setCapability("GL_ARB_copy_image", gglHasExtension(ARB_copy_image)); + // Check for copy image support + setCapability("GL_ARB_copy_image", gglHasExtension(ARB_copy_image)); - // Check for vertex attrib binding - setCapability("GL_ARB_vertex_attrib_binding", gglHasExtension(ARB_vertex_attrib_binding)); + // Check for vertex attrib binding + setCapability("GL_ARB_vertex_attrib_binding", gglHasExtension(ARB_vertex_attrib_binding)); } bool GFXGLCardProfiler::_queryCardCap(const String& query, U32& foundResult) diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 9e5df8886..b5881dd2a 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -140,18 +140,18 @@ void GFXGLDevice::initGLState() glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0 + // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0 // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. mPixelShaderVersion = 3.0; // Set capability extensions. mCapabilities.anisotropicFiltering = mCardProfiler->queryProfile("GL_EXT_texture_filter_anisotropic"); - mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage"); - mCapabilities.shaderModel5 = mCardProfiler->queryProfile("GL_ARB_gpu_shader5"); - mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage"); - mCapabilities.samplerObjects = mCardProfiler->queryProfile("GL_ARB_sampler_objects"); - mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image"); - mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding"); + mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage"); + mCapabilities.shaderModel5 = mCardProfiler->queryProfile("GL_ARB_gpu_shader5"); + mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage"); + mCapabilities.samplerObjects = mCardProfiler->queryProfile("GL_ARB_sampler_objects"); + mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image"); + mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding"); String vendorStr = (const char*)glGetString( GL_VENDOR ); if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos) @@ -224,8 +224,8 @@ GFXGLDevice::GFXGLDevice(U32 adapterIndex) : mCurrentVB_Divisor[i] = 0; } - // Initiailize capabilities to false. - memset(&mCapabilities, 0, sizeof(GLCapabilities)); + // Initiailize capabilities to false. + memset(&mCapabilities, 0, sizeof(GLCapabilities)); loadGLCore(); diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index e7649c643..fc37d3220 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -45,17 +45,17 @@ class GFXGLVertexDecl; class GFXGLDevice : public GFXDevice { public: - struct GLCapabilities - { - bool anisotropicFiltering; - bool bufferStorage; - bool shaderModel5; - bool textureStorage; - bool samplerObjects; - bool copyImage; - bool vertexAttributeBinding; - }; - GLCapabilities mCapabilities; + struct GLCapabilities + { + bool anisotropicFiltering; + bool bufferStorage; + bool shaderModel5; + bool textureStorage; + bool samplerObjects; + bool copyImage; + bool vertexAttributeBinding; + }; + GLCapabilities mCapabilities; void zombify(); void resurrect(); From db6d91925d74427be4fae97dd5f80845898c58ee Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Fri, 6 May 2016 23:44:41 -0400 Subject: [PATCH 15/71] Added profile blocks for GL. --- Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h | 6 ++++-- Engine/source/gfx/gl/gfxGLDevice.cpp | 5 +++++ Engine/source/gfx/gl/gfxGLShader.cpp | 4 ++++ Engine/source/gfx/gl/gfxGLStateBlock.cpp | 1 + Engine/source/gfx/gl/gfxGLTextureManager.cpp | 8 ++++++++ Engine/source/gfx/gl/gfxGLTextureObject.cpp | 7 +++++++ 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h index 6d7d0e4b1..dd25255c2 100644 --- a/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h +++ b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h @@ -20,7 +20,8 @@ public: } void init(U32 start, U32 end) - { + { + PROFILE_SCOPE(GFXGLQueryFence_issue); mStart = start; mEnd = end; mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -35,7 +36,8 @@ public: } void wait() - { + { + PROFILE_SCOPE(GFXGLQueryFence_block); GLbitfield waitFlags = 0; GLuint64 waitDuration = 0; while( 1 ) diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index f59e8ac92..4974a04e0 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -325,6 +325,7 @@ void GFXGLDevice::resurrect() GFXVertexBuffer* GFXGLDevice::findVolatileVBO(U32 numVerts, const GFXVertexFormat *vertexFormat, U32 vertSize) { + PROFILE_SCOPE(GFXGLDevice_findVBPool); for(U32 i = 0; i < mVolatileVBs.size(); i++) if ( mVolatileVBs[i]->mNumVerts >= numVerts && mVolatileVBs[i]->mVertexFormat.isEqual( *vertexFormat ) && @@ -333,6 +334,7 @@ GFXVertexBuffer* GFXGLDevice::findVolatileVBO(U32 numVerts, const GFXVertexForma return mVolatileVBs[i]; // No existing VB, so create one + PROFILE_SCOPE(GFXGLDevice_createVBPool); StrongRefPtr buf(new GFXGLVertexBuffer(GFX, numVerts, vertexFormat, vertSize, GFXBufferTypeVolatile)); buf->registerResourceWithDevice(this); mVolatileVBs.push_back(buf); @@ -358,6 +360,7 @@ GFXVertexBuffer *GFXGLDevice::allocVertexBuffer( U32 numVerts, GFXBufferType bufferType, void* data ) { + PROFILE_SCOPE(GFXGLDevice_allocVertexBuffer); if(bufferType == GFXBufferTypeVolatile) return findVolatileVBO(numVerts, vertexFormat, vertSize); @@ -523,6 +526,7 @@ inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) { + PROFILE_SCOPE(GFXGLDevice_allocVertexDecl); typedef Map GFXGLVertexDeclMap; static GFXGLVertexDeclMap declMap; GFXGLVertexDeclMap::Iterator itr = declMap.find( (void*)vertexFormat->getDescription().c_str() ); // description string are interned, safe to use c_str() @@ -855,6 +859,7 @@ void GFXGLDevice::setShader(GFXShader *shader, bool force) void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer) { + PROFILE_SCOPE(GFXGLDevice_setShaderConstBufferInternal); static_cast(buffer)->activate(); } diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index 2e63c61fe..960af7bd1 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -344,6 +344,7 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* ma void GFXGLShaderConstBuffer::activate() { + PROFILE_SCOPE(GFXGLShaderConstBuffer_activate); mShader->setConstantsFromBuffer(this); mWasLost = false; } @@ -394,6 +395,7 @@ void GFXGLShader::clearShaders() bool GFXGLShader::_init() { + PROFILE_SCOPE(GFXGLShader_Init); // Don't initialize empty shaders. if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) return false; @@ -1013,6 +1015,7 @@ bool GFXGLShader::initShader( const Torque::Path &file, bool isVertex, const Vector ¯os ) { + PROFILE_SCOPE(GFXGLShader_CompileShader); GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER); if(isVertex) mVertexShader = activeShader; @@ -1072,6 +1075,7 @@ bool GFXGLShader::initShader( const Torque::Path &file, /// Returns our list of shader constants, the material can get this and just set the constants it knows about const Vector& GFXGLShader::getShaderConstDesc() const { + PROFILE_SCOPE(GFXGLShader_GetShaderConstants); return mConstants; } diff --git a/Engine/source/gfx/gl/gfxGLStateBlock.cpp b/Engine/source/gfx/gl/gfxGLStateBlock.cpp index 34f816dc9..f9ad73dba 100644 --- a/Engine/source/gfx/gl/gfxGLStateBlock.cpp +++ b/Engine/source/gfx/gl/gfxGLStateBlock.cpp @@ -88,6 +88,7 @@ const GFXStateBlockDesc& GFXGLStateBlock::getDesc() const /// @param oldState The current state, used to make sure we don't set redundant states on the device. Pass NULL to reset all states. void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) { + PROFILE_SCOPE(GFXGLStateBlock_Activate); // Big scary warning copied from Apple docs // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_performance/chapter_13_section_2.html#//apple_ref/doc/uid/TP40001987-CH213-SW12 // Don't set a state that's already set. Once a feature is enabled, it does not need to be enabled again. diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index 70a5e4303..d9962691d 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -234,6 +234,7 @@ static void _fastTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL) if(pDL->getFormat() == GFXFormatR8G8B8A8 || pDL->getFormat() == GFXFormatR8G8B8X8) { + PROFILE_SCOPE(Swizzle32_Upload); FrameAllocatorMarker mem; U8* pboMemory = (U8*)mem.alloc(bufSize); GFX->getDeviceSwizzle32()->ToBuffer(pboMemory, pDL->getBits(0), bufSize); @@ -241,6 +242,7 @@ static void _fastTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL) } else { + PROFILE_SCOPE(SwizzleNull_Upload); glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, bufSize, pDL->getBits(0) ); } @@ -262,6 +264,7 @@ static void _slowTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL) bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL) { + PROFILE_SCOPE(GFXGLTextureManager_loadTexture); GFXGLTextureObject *texture = static_cast(aTexture); AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D, @@ -291,6 +294,8 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL) bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) { + PROFILE_SCOPE(GFXGLTextureManager_loadTextureDDS); + AssertFatal(!(dds->mFormat == GFXFormatDXT2 || dds->mFormat == GFXFormatDXT4), "GFXGLTextureManager::_loadTexture - OpenGL does not support DXT2 or DXT4 compressed textures"); GFXGLTextureObject* texture = static_cast(aTexture); @@ -308,6 +313,8 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) numMips = 1; for(U32 i = 0; i < numMips; i++) { + PROFILE_SCOPE(GFXGLTexMan_loadSurface); + if(isCompressedFormat(dds->mFormat)) { if((!isPow2(dds->getWidth()) || !isPow2(dds->getHeight())) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures")) @@ -344,6 +351,7 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, void *raw) { + PROFILE_SCOPE(GFXGLTextureManager_loadTextureRaw); if(aTexture->getDepth() < 1) return false; diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index ed229e5d9..36c981415 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -96,6 +96,9 @@ void GFXGLTextureObject::unlock(U32 mipLevel) if(!mLockedRect.bits) return; + // I know this is in unlock, but in GL we actually do our submission in unlock. + PROFILE_SCOPE(GFXGLTextureObject_lockRT); + PRESERVE_TEXTURE(mBinding); glBindTexture(mBinding, mHandle); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, mBuffer); @@ -137,6 +140,8 @@ void GFXGLTextureObject::reInit() bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) { + PROFILE_SCOPE(GFXGLTextureObject_copyToBmp); + if (!bmp) return false; @@ -175,6 +180,7 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig); + PROFILE_START(GFXGLTextureObject_copyToBmp_pixCopy); for(int i = 0; i < srcPixelCount; ++i) { dest[0] = orig[0]; @@ -186,6 +192,7 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) orig += srcBytesPerPixel; dest += dstBytesPerPixel; } + PROFILE_END(); return true; } From 909109713d5fbf6250908b870db2a494f2de6b15 Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Fri, 6 May 2016 23:45:48 -0400 Subject: [PATCH 16/71] redefined the copyToBMP --- Engine/source/gfx/gl/gfxGLTextureObject.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index 36c981415..e22daa1d8 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -140,8 +140,6 @@ void GFXGLTextureObject::reInit() bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) { - PROFILE_SCOPE(GFXGLTextureObject_copyToBmp); - if (!bmp) return false; From c104313f439f7b6bccb113a116e44f58415d375a Mon Sep 17 00:00:00 2001 From: Azaezel Date: Sun, 8 May 2016 21:21:52 -0500 Subject: [PATCH 17/71] updated empty template with stray script files from devhead that had yet to be converted --- .../game/core/scripts/client/defaults.cs | 4 +- .../lighting/advanced/deferredShading.cs | 147 +++++++++++ .../scripts/client/lighting/advanced/init.cs | 7 + .../client/lighting/advanced/lightViz.cs | 21 +- .../client/lighting/advanced/shaders.cs | 24 +- .../core/scripts/client/postFx/GammaPostFX.cs | 6 +- .../core/scripts/client/postFx/caustics.cs | 4 +- .../game/core/scripts/client/postFx/hdr.cs | 18 +- .../core/scripts/client/postFx/turbulence.cs | 2 +- .../game/core/scripts/client/renderManager.cs | 31 +-- .../game/core/scripts/client/scatterSky.cs | 4 +- .../Empty/game/core/scripts/client/shaders.cs | 36 +++ .../advanced/gl/deferredShadingP.glsl | 2 +- .../gui/guiMaterialPropertiesWindow.ed.gui | 228 +----------------- .../Empty/game/tools/worldEditor/main.cs | 3 + .../worldEditor/scripts/menuHandlers.ed.cs | 2 + 16 files changed, 285 insertions(+), 254 deletions(-) create mode 100644 Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs diff --git a/Templates/Empty/game/core/scripts/client/defaults.cs b/Templates/Empty/game/core/scripts/client/defaults.cs index 0142a9410..d1805d337 100644 --- a/Templates/Empty/game/core/scripts/client/defaults.cs +++ b/Templates/Empty/game/core/scripts/client/defaults.cs @@ -73,7 +73,9 @@ $pref::Video::disableCubemapping = false; /// $pref::Video::disableParallaxMapping = false; -$pref::Video::Gamma = 1.0; +$pref::Video::Gamma = 2.2; +$pref::Video::Contrast = 1.0; +$pref::Video::Brightness = 0; // Console-friendly defaults if($platform $= "xenon") diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs new file mode 100644 index 000000000..d53e6965f --- /dev/null +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs @@ -0,0 +1,147 @@ +singleton ShaderData( ClearGBufferShader ) +{ + DXVertexShaderFile = "shaders/common/lighting/advanced/deferredClearGBufferV.hlsl"; + DXPixelShaderFile = "shaders/common/lighting/advanced/deferredClearGBufferP.hlsl"; + + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; + OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/deferredClearGBufferP.glsl"; + + pixVersion = 2.0; +}; + +singleton ShaderData( DeferredColorShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/lighting/advanced/deferredColorShaderP.hlsl"; + + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; + OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/deferredColorShaderP.glsl"; + + pixVersion = 2.0; +}; + +// Primary Deferred Shader +new GFXStateBlockData( AL_DeferredShadingState : PFX_DefaultStateBlock ) +{ + cullMode = GFXCullNone; + + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendSrcAlpha; + blendDest = GFXBlendInvSrcAlpha; + + samplersDefined = true; + samplerStates[0] = SamplerWrapLinear; + samplerStates[1] = SamplerWrapLinear; + samplerStates[2] = SamplerWrapLinear; + samplerStates[3] = SamplerWrapLinear; +}; + +new ShaderData( AL_DeferredShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/lighting/advanced/deferredShadingP.hlsl"; + + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; + OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/deferredShadingP.glsl"; + + samplerNames[0] = "colorBufferTex"; + samplerNames[1] = "lightPrePassTex"; + samplerNames[2] = "matInfoTex"; + samplerNames[3] = "prepassTex"; + + pixVersion = 2.0; +}; + +singleton PostEffect( AL_DeferredShading ) +{ + renderTime = "PFXBeforeBin"; + renderBin = "SkyBin"; + shader = AL_DeferredShader; + stateBlock = AL_DeferredShadingState; + texture[0] = "#color"; + texture[1] = "#lightinfo"; + texture[2] = "#matinfo"; + texture[3] = "#prepass"; + + target = "$backBuffer"; + renderPriority = 10000; + allowReflectPass = true; +}; + +// Debug Shaders. +new ShaderData( AL_ColorBufferShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/lighting/advanced/dbgColorBufferP.hlsl"; + + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; + OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgColorBufferP.glsl"; + + samplerNames[0] = "colorBufferTex"; + pixVersion = 2.0; +}; + +singleton PostEffect( AL_ColorBufferVisualize ) +{ + shader = AL_ColorBufferShader; + stateBlock = AL_DefaultVisualizeState; + texture[0] = "#color"; + target = "$backBuffer"; + renderPriority = 9999; +}; + +/// Toggles the visualization of the AL lighting specular power buffer. +function toggleColorBufferViz( %enable ) +{ + if ( %enable $= "" ) + { + $AL_ColorBufferShaderVar = AL_ColorBufferVisualize.isEnabled() ? false : true; + AL_ColorBufferVisualize.toggle(); + } + else if ( %enable ) + { + AL_DeferredShading.disable(); + AL_ColorBufferVisualize.enable(); + } + else if ( !%enable ) + { + AL_ColorBufferVisualize.disable(); + AL_DeferredShading.enable(); + } +} + +new ShaderData( AL_SpecMapShader ) +{ + DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; + DXPixelShaderFile = "shaders/common/lighting/advanced/dbgSpecMapVisualizeP.hlsl"; + + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; + OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgSpecMapVisualizeP.glsl"; + + samplerNames[0] = "matinfoTex"; + pixVersion = 2.0; +}; + +singleton PostEffect( AL_SpecMapVisualize ) +{ + shader = AL_SpecMapShader; + stateBlock = AL_DefaultVisualizeState; + texture[0] = "#matinfo"; + target = "$backBuffer"; + renderPriority = 9999; +}; + +/// Toggles the visualization of the AL lighting specular power buffer. +function toggleSpecMapViz( %enable ) +{ + if ( %enable $= "" ) + { + $AL_SpecMapShaderVar = AL_SpecMapVisualize.isEnabled() ? false : true; + AL_SpecMapVisualize.toggle(); + } + else if ( %enable ) + AL_SpecMapVisualize.enable(); + else if ( !%enable ) + AL_SpecMapVisualize.disable(); +} \ No newline at end of file diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs index 2c78e9ca4..d74aff69a 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs @@ -43,6 +43,7 @@ exec( "./shaders.cs" ); exec( "./lightViz.cs" ); exec( "./shadowViz.cs" ); exec( "./shadowViz.gui" ); +exec( "./deferredShading.cs" ); function onActivateAdvancedLM() { @@ -58,12 +59,18 @@ function onActivateAdvancedLM() // Enable the offscreen target so that AL will work // with MSAA back buffers and for HDR rendering. AL_FormatToken.enable(); + + // Activate Deferred Shading + AL_DeferredShading.enable(); } function onDeactivateAdvancedLM() { // Disable the offscreen render target. AL_FormatToken.disable(); + + // Deactivate Deferred Shading + AL_DeferredShading.disable(); } function setAdvancedLighting() diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs index 22665120d..fcaf72942 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs @@ -56,7 +56,7 @@ new ShaderData( AL_DepthVisualizeShader ) OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgDepthVisualizeP.glsl"; - samplerNames[0] = "prepassBuffer"; + samplerNames[0] = "prepassTex"; samplerNames[1] = "depthViz"; pixVersion = 2.0; @@ -113,7 +113,7 @@ new ShaderData( AL_NormalsVisualizeShader ) OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgNormalVisualizeP.glsl"; - samplerNames[0] = "prepassBuffer"; + samplerNames[0] = "prepassTex"; pixVersion = 2.0; }; @@ -149,7 +149,7 @@ new ShaderData( AL_LightColorVisualizeShader ) OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgLightColorVisualizeP.glsl"; - samplerNames[0] = "lightInfoBuffer"; + samplerNames[0] = "lightPrePassTex"; pixVersion = 2.0; }; @@ -184,7 +184,7 @@ new ShaderData( AL_LightSpecularVisualizeShader ) OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/dbgLightSpecularVisualizeP.glsl"; - samplerNames[0] = "lightInfoBuffer"; + samplerNames[0] = "lightPrePassTex"; pixVersion = 2.0; }; @@ -280,3 +280,16 @@ function toggleLightSpecularViz( %enable ) AL_LightSpecularVisualize.disable(); } +function toggleBackbufferViz( %enable ) +{ + if ( %enable $= "" ) + { + $AL_BackbufferVisualizeVar = AL_DeferredShading.isEnabled() ? true : false; + AL_DeferredShading.toggle(); + } + else if ( %enable ) + AL_DeferredShading.disable(); + else if ( !%enable ) + AL_DeferredShading.enable(); +} + diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs index 2e73b6569..7e6816db3 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs @@ -36,8 +36,11 @@ new GFXStateBlockData( AL_VectorLightState ) samplersDefined = true; samplerStates[0] = SamplerClampPoint; // G-buffer + mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) + mSamplerNames[1] = "shadowMap"; samplerStates[2] = SamplerClampLinear; // SSAO Mask + mSamplerNames[2] = "ssaoMask"; samplerStates[3] = SamplerWrapPoint; // Random Direction Map cullDefined = true; @@ -66,7 +69,9 @@ new ShaderData( AL_VectorLightShader ) samplerNames[2] = "$dynamicShadowMap"; samplerNames[3] = "$ssaoMask"; samplerNames[4] = "$gTapRotationTex"; - + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; pixVersion = 3.0; }; @@ -79,6 +84,9 @@ new CustomMaterial( AL_VectorLightMaterial ) sampler["shadowMap"] = "$dynamiclight"; sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["ssaoMask"] = "#ssaoMask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; target = "lightinfo"; @@ -103,7 +111,9 @@ new GFXStateBlockData( AL_ConvexLightState ) samplersDefined = true; samplerStates[0] = SamplerClampPoint; // G-buffer + mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) + mSamplerNames[1] = "shadowMap"; samplerStates[2] = SamplerClampLinear; // Cookie Map samplerStates[3] = SamplerWrapPoint; // Random Direction Map @@ -133,6 +143,9 @@ new ShaderData( AL_PointLightShader ) samplerNames[2] = "$dynamicShadowMap"; samplerNames[3] = "$cookieMap"; samplerNames[4] = "$gTapRotationTex"; + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; pixVersion = 3.0; }; @@ -146,6 +159,9 @@ new CustomMaterial( AL_PointLightMaterial ) sampler["shadowMap"] = "$dynamiclight"; sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; target = "lightinfo"; @@ -166,6 +182,9 @@ new ShaderData( AL_SpotLightShader ) samplerNames[2] = "$dynamicShadowMap"; samplerNames[3] = "$cookieMap"; samplerNames[4] = "$gTapRotationTex"; + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; pixVersion = 3.0; }; @@ -179,6 +198,9 @@ new CustomMaterial( AL_SpotLightMaterial ) sampler["shadowMap"] = "$dynamiclight"; sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; target = "lightinfo"; diff --git a/Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs b/Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs index 383a0c8cd..b88f31305 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs @@ -44,7 +44,7 @@ singleton GFXStateBlockData( GammaStateBlock : PFX_DefaultStateBlock ) singleton PostEffect( GammaPostFX ) { isEnabled = true; - allowReflectPass = false; + allowReflectPass = true; renderTime = "PFXBeforeBin"; renderBin = "EditorBin"; @@ -65,6 +65,8 @@ function GammaPostFX::preProcess( %this ) function GammaPostFX::setShaderConsts( %this ) { - %clampedGamma = mClamp( $pref::Video::Gamma, 0.001, 2.2); + %clampedGamma = mClamp( $pref::Video::Gamma, 2.0, 2.5); %this.setShaderConst( "$OneOverGamma", 1 / %clampedGamma ); + %this.setShaderConst( "$Brightness", $pref::Video::Brightness ); + %this.setShaderConst( "$Contrast", $pref::Video::Contrast ); } \ No newline at end of file diff --git a/Templates/Empty/game/core/scripts/client/postFx/caustics.cs b/Templates/Empty/game/core/scripts/client/postFx/caustics.cs index 3e8b14de0..a712ef82a 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/caustics.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/caustics.cs @@ -38,7 +38,7 @@ singleton ShaderData( PFX_CausticsShader ) DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; DXPixelShaderFile = "shaders/common/postFx/caustics/causticsP.hlsl"; - OGLVertexShaderFile = "shaders/common/postFx/gl//postFxV.glsl"; + OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl"; OGLPixelShaderFile = "shaders/common/postFx/caustics/gl/causticsP.glsl"; samplerNames[0] = "$prepassTex"; @@ -51,7 +51,7 @@ singleton ShaderData( PFX_CausticsShader ) singleton PostEffect( CausticsPFX ) { isEnabled = false; - renderTime = "PFXBeforeBin"; + renderTime = "PFXAfterDiffuse"; renderBin = "ObjTranslucentBin"; //renderPriority = 0.1; diff --git a/Templates/Empty/game/core/scripts/client/postFx/hdr.cs b/Templates/Empty/game/core/scripts/client/postFx/hdr.cs index a5c450799..6c8e870d0 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/hdr.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/hdr.cs @@ -172,6 +172,8 @@ singleton ShaderData( HDR_CombineShader ) samplerNames[2] = "$bloomTex"; samplerNames[3] = "$colorCorrectionTex"; + samplerNames[4] = "prepassTex"; + pixVersion = 3.0; }; @@ -253,8 +255,10 @@ function HDRPostFX::setShaderConsts( %this ) %combinePass.setShaderConst( "$g_fEnableBlueShift", $HDRPostFX::enableBlueShift ); %combinePass.setShaderConst( "$g_fBlueShiftColor", $HDRPostFX::blueShiftColor ); - %clampedGamma = mClamp( $pref::Video::Gamma, 0.001, 2.2); + %clampedGamma = mClamp( $pref::Video::Gamma, 2.0, 2.5); %combinePass.setShaderConst( "$g_fOneOverGamma", 1 / %clampedGamma ); + %combinePass.setShaderConst( "$Brightness", $pref::Video::Brightness ); + %combinePass.setShaderConst( "$Contrast", $pref::Video::Contrast ); %whiteCutoff = ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff ) * ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff ); @@ -329,7 +333,7 @@ function HDRPostFX::onDisabled( %this ) singleton PostEffect( HDRPostFX ) { isEnabled = false; - allowReflectPass = false; + allowReflectPass = true; // Resolve the HDR before we render any editor stuff // and before we resolve the scene to the backbuffer. @@ -355,6 +359,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; shader = HDR_DownScale4x4Shader; stateBlock = HDR_DownSampleStateBlock; texture[0] = "$inTex"; @@ -365,6 +370,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; internalName = "bloomH"; shader = HDR_BloomGaussBlurHShader; @@ -376,6 +382,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; internalName = "bloomV"; shader = HDR_BloomGaussBlurVShader; @@ -390,6 +397,7 @@ singleton PostEffect( HDRPostFX ) // Now calculate the adapted luminance. new PostEffect() { + allowReflectPass = true; internalName = "adaptLum"; shader = HDR_SampleLumShader; @@ -401,6 +409,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; shader = HDR_DownSampleLumShader; stateBlock = HDR_DownSampleStateBlock; texture[0] = "$inTex"; @@ -411,6 +420,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; shader = HDR_DownSampleLumShader; stateBlock = HDR_DownSampleStateBlock; texture[0] = "$inTex"; @@ -421,6 +431,7 @@ singleton PostEffect( HDRPostFX ) new PostEffect() { + allowReflectPass = true; shader = HDR_DownSampleLumShader; stateBlock = HDR_DownSampleStateBlock; texture[0] = "$inTex"; @@ -434,6 +445,7 @@ singleton PostEffect( HDRPostFX ) // one... PostEffect takes care to manage that. new PostEffect() { + allowReflectPass = true; internalName = "finalLum"; shader = HDR_CalcAdaptedLumShader; stateBlock = HDR_DownSampleStateBlock; @@ -450,6 +462,7 @@ singleton PostEffect( HDRPostFX ) // version of the scene. new PostEffect() { + allowReflectPass = true; internalName = "combinePass"; shader = HDR_CombineShader; @@ -458,6 +471,7 @@ singleton PostEffect( HDRPostFX ) texture[1] = "#adaptedLum"; texture[2] = "#bloomFinal"; texture[3] = $HDRPostFX::colorCorrectionRamp; + texture[4] = "#prepass"; target = "$backBuffer"; }; }; diff --git a/Templates/Empty/game/core/scripts/client/postFx/turbulence.cs b/Templates/Empty/game/core/scripts/client/postFx/turbulence.cs index c2309f808..dd8c0e2dc 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/turbulence.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/turbulence.cs @@ -47,7 +47,7 @@ singleton PostEffect( TurbulenceFx ) isEnabled = false; allowReflectPass = true; - renderTime = "PFXAfterBin"; + renderTime = "PFXAfterDiffuse"; renderBin = "GlowBin"; renderPriority = 0.5; // Render after the glows themselves diff --git a/Templates/Empty/game/core/scripts/client/renderManager.cs b/Templates/Empty/game/core/scripts/client/renderManager.cs index 5734bbce6..f746c4527 100644 --- a/Templates/Empty/game/core/scripts/client/renderManager.cs +++ b/Templates/Empty/game/core/scripts/client/renderManager.cs @@ -33,7 +33,7 @@ function initRenderManager() { enabled = "false"; - format = "GFXFormatR8G8B8A8"; + format = "GFXFormatR16G16B16A16F"; depthFormat = "GFXFormatD24S8"; aaLevel = 0; // -1 = match backbuffer @@ -49,20 +49,21 @@ function initRenderManager() // We really need to fix the sky to render after all the // meshes... but that causes issues in reflections. - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(SkyBin) { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } ); //DiffuseRenderPassManager.addManager( new RenderVistaMgr() { bintype = "Vista"; renderOrder = 0.15; processAddOrder = 0.15; } ); - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Begin"; renderOrder = 0.2; processAddOrder = 0.2; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(BeginBin) { bintype = "Begin"; renderOrder = 0.2; processAddOrder = 0.2; } ); // Normal mesh rendering. - DiffuseRenderPassManager.addManager( new RenderTerrainMgr() { renderOrder = 0.4; processAddOrder = 0.4; } ); - DiffuseRenderPassManager.addManager( new RenderMeshMgr() { bintype = "Mesh"; renderOrder = 0.5; processAddOrder = 0.5; } ); - DiffuseRenderPassManager.addManager( new RenderImposterMgr() { renderOrder = 0.56; processAddOrder = 0.56; } ); - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Object"; renderOrder = 0.6; processAddOrder = 0.6; } ); + DiffuseRenderPassManager.addManager( new RenderTerrainMgr(TerrainBin) { renderOrder = 0.4; processAddOrder = 0.4; basicOnly = true; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(MeshBin) { bintype = "Mesh"; renderOrder = 0.5; processAddOrder = 0.5; basicOnly = true; } ); + DiffuseRenderPassManager.addManager( new RenderImposterMgr(ImposterBin) { renderOrder = 0.56; processAddOrder = 0.56; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjectBin) { bintype = "Object"; renderOrder = 0.6; processAddOrder = 0.6; } ); - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Shadow"; renderOrder = 0.7; processAddOrder = 0.7; } ); - DiffuseRenderPassManager.addManager( new RenderMeshMgr() { bintype = "Decal"; renderOrder = 0.8; processAddOrder = 0.8; } ); - DiffuseRenderPassManager.addManager( new RenderOcclusionMgr() { bintype = "Occluder"; renderOrder = 0.9; processAddOrder = 0.9; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(ShadowBin) { bintype = "Shadow"; renderOrder = 0.7; processAddOrder = 0.7; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalRoadBin) { bintype = "DecalRoad"; renderOrder = 0.8; processAddOrder = 0.8; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalBin) { bintype = "Decal"; renderOrder = 0.81; processAddOrder = 0.81; } ); + DiffuseRenderPassManager.addManager( new RenderOcclusionMgr(OccluderBin){ bintype = "Occluder"; renderOrder = 0.9; processAddOrder = 0.9; } ); // We now render translucent objects that should handle // their own fogging and lighting. @@ -70,10 +71,10 @@ function initRenderManager() // Note that the fog effect is triggered before this bin. DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjTranslucentBin) { bintype = "ObjectTranslucent"; renderOrder = 1.0; processAddOrder = 1.0; } ); - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Water"; renderOrder = 1.2; processAddOrder = 1.2; } ); - DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Foliage"; renderOrder = 1.3; processAddOrder = 1.3; } ); - DiffuseRenderPassManager.addManager( new RenderParticleMgr() { renderOrder = 1.35; processAddOrder = 1.35; } ); - DiffuseRenderPassManager.addManager( new RenderTranslucentMgr() { renderOrder = 1.4; processAddOrder = 1.4; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(WaterBin) { bintype = "Water"; renderOrder = 1.2; processAddOrder = 1.2; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(FoliageBin) { bintype = "Foliage"; renderOrder = 1.3; processAddOrder = 1.3; } ); + DiffuseRenderPassManager.addManager( new RenderParticleMgr(ParticleBin) { renderOrder = 1.35; processAddOrder = 1.35; } ); + DiffuseRenderPassManager.addManager( new RenderTranslucentMgr(TranslucentBin){ renderOrder = 1.4; processAddOrder = 1.4; } ); DiffuseRenderPassManager.addManager(new RenderObjectMgr(FogBin){ bintype = "ObjectVolumetricFog"; renderOrder = 1.45; processAddOrder = 1.45; } ); @@ -85,7 +86,7 @@ function initRenderManager() DiffuseRenderPassManager.addManager( new RenderObjectMgr(EditorBin) { bintype = "Editor"; renderOrder = 1.6; processAddOrder = 1.6; } ); // Resolve format change token last. - DiffuseRenderPassManager.addManager( new RenderPassStateBin() { renderOrder = 1.7; stateToken = AL_FormatToken; } ); + DiffuseRenderPassManager.addManager( new RenderPassStateBin(FinalBin) { renderOrder = 1.7; stateToken = AL_FormatToken; } ); } /// This post effect is used to copy data from the non-MSAA back-buffer to the diff --git a/Templates/Empty/game/core/scripts/client/scatterSky.cs b/Templates/Empty/game/core/scripts/client/scatterSky.cs index 48a8fdbc7..57a8a9fb1 100644 --- a/Templates/Empty/game/core/scripts/client/scatterSky.cs +++ b/Templates/Empty/game/core/scripts/client/scatterSky.cs @@ -22,13 +22,13 @@ new GFXStateBlockData( ScatterSkySBData ) { - cullDefined = true; + //cullDefined = true; cullMode = "GFXCullNone"; zDefined = true; zEnable = true; zWriteEnable = false; - zFunc = "GFXCmpLessEqual"; + //zFunc = "GFXCmpLessEqual"; samplersDefined = true; samplerStates[0] = SamplerClampLinear; diff --git a/Templates/Empty/game/core/scripts/client/shaders.cs b/Templates/Empty/game/core/scripts/client/shaders.cs index 98d0529eb..002053a1a 100644 --- a/Templates/Empty/game/core/scripts/client/shaders.cs +++ b/Templates/Empty/game/core/scripts/client/shaders.cs @@ -101,4 +101,40 @@ new ShaderData( fxFoliageReplicatorShader ) samplerNames[1] = "$alphaMap"; pixVersion = 1.4; +}; + +singleton ShaderData( VolumetricFogPrePassShader ) +{ + DXVertexShaderFile = "shaders/common/VolumetricFog/VFogPreV.hlsl"; + DXPixelShaderFile = "shaders/common/VolumetricFog/VFogPreP.hlsl"; + + OGLVertexShaderFile = "shaders/common/VolumetricFog/gl/VFogPreV.glsl"; + OGLPixelShaderFile = "shaders/common/VolumetricFog/gl/VFogPreP.glsl"; + + pixVersion = 3.0; +}; +singleton ShaderData( VolumetricFogShader ) +{ + DXVertexShaderFile = "shaders/common/VolumetricFog/VFogV.hlsl"; + DXPixelShaderFile = "shaders/common/VolumetricFog/VFogP.hlsl"; + + OGLVertexShaderFile = "shaders/common/VolumetricFog/gl/VFogV.glsl"; + OGLPixelShaderFile = "shaders/common/VolumetricFog/gl/VFogP.glsl"; + + samplerNames[0] = "$prepassTex"; + samplerNames[1] = "$depthBuffer"; + samplerNames[2] = "$frontBuffer"; + samplerNames[3] = "$density"; + + pixVersion = 3.0; +}; +singleton ShaderData( VolumetricFogReflectionShader ) +{ + DXVertexShaderFile = "shaders/common/VolumetricFog/VFogPreV.hlsl"; + DXPixelShaderFile = "shaders/common/VolumetricFog/VFogRefl.hlsl"; + + OGLVertexShaderFile = "shaders/common/VolumetricFog/gl/VFogPreV.glsl"; + OGLPixelShaderFile = "shaders/common/VolumetricFog/gl/VFogRefl.glsl"; + + pixVersion = 3.0; }; \ No newline at end of file diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl b/Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl index 4ee4b1d81..8af37ef0c 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl @@ -22,7 +22,7 @@ #include "../../../gl/hlslCompat.glsl" #include "shadergen:/autogenConditioners.h" -#include "../../../postfx/gl/postFx.glsl" +#include "../../../postFx/gl/postFX.glsl" #include "../../../gl/torque.glsl" uniform sampler2D colorBufferTex; diff --git a/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui b/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui index 2062f43f3..63ce28e2a 100644 --- a/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui +++ b/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui @@ -1354,132 +1354,6 @@ bitmap = "tools/gui/images/delete"; }; }; - new GuiBitmapCtrl(){ - position="6 357"; - extent ="175 2"; - HorizSizing = "width"; - bitmap ="tools/gui/images/separator-v"; - }; - new GuiContainer(){ // Environment Map - profile="ToolsGuiDefaultProfile"; - isContainer = "1"; - position = "6 359"; - Extent = "185 52"; - HorizSizing = "width"; - - new GuiBitmapCtrl() { - canSaveDynamicFields = "0"; - internalName = "envMapDisplayBitmap"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiDefaultProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "1 1"; - Extent = "48 48"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - hovertime = "1000"; - bitmap = "tools/materialeditor/gui/unknownImage"; - wrap = "0"; - }; - new GuiTextCtrl() { - canSaveDynamicFields = "0"; - Enabled = "1"; - isContainer = "0"; - Profile = "EditorTextProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "56 -3"; - Extent = "72 18"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - hovertime = "1000"; - Margin = "0 0 0 0"; - Padding = "0 0 0 0"; - AnchorTop = "1"; - AnchorBottom = "0"; - AnchorLeft = "1"; - AnchorRight = "0"; - text = "Env Map"; - maxLength = "1024"; - }; - new GuiBitmapButtonCtrl() { - canSaveDynamicFields = "0"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiDefaultProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "1 1"; - Extent = "48 48"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - Command = "MaterialEditorGui.updateTextureMap(\"env\", 1);"; - tooltipprofile = "ToolsGuiDefaultProfile"; - ToolTip = "Change the active Environment Map for this layer."; - hovertime = "1000"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - bitmap = "tools/materialEditor/gui/cubemapBtnBorder"; - }; - new GuiTextCtrl() { - canSaveDynamicFields = "0"; - internalName = "envMapNameText"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiTextProfile"; - HorizSizing = "width"; - VertSizing = "bottom"; - position = "56 16"; - Extent = "143 17"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - hovertime = "1000"; - Margin = "0 0 0 0"; - Padding = "0 0 0 0"; - AnchorTop = "1"; - AnchorBottom = "0"; - AnchorLeft = "1"; - AnchorRight = "0"; - text = "None"; - maxLength = "1024"; - }; - new GuiButtonCtrl(){ - profile="ToolsGuiButtonProfile"; - text ="Edit"; - HorizSizing = "left"; - VertSizing = "bottom"; - position = "134 34"; - Extent = "40 16"; - buttonType = "PushButton"; - command="MaterialEditorGui.updateTextureMap(\"env\", 1);"; - }; - new GuiBitmapButtonCtrl() { - canSaveDynamicFields = "0"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiDefaultProfile"; - HorizSizing = "left"; - VertSizing = "bottom"; - position = "177 34"; - Extent = "16 16"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - Command = "MaterialEditorGui.updateTextureMap(\"env\", 0);"; - hovertime = "1000"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - bitmap = "tools/gui/images/delete"; - }; - }; }; }; new GuiRolloutCtrl() { @@ -1491,6 +1365,7 @@ Position = "0 0"; Extent = "195 0"; Caption = "Accumulation Properties"; + Expanded = false; Margin = "-1 0 0 0"; DragSizable = false; container = true; @@ -1967,6 +1842,7 @@ Position = "0 0"; Extent = "185 0"; Caption = "Lighting Properties"; + Expanded = false; Margin = "-1 0 0 0"; DragSizable = false; container = true; @@ -2364,101 +2240,6 @@ useMouseEvents = "0"; useInactiveState = "0"; }; - new GuiCheckBoxCtrl() { - canSaveDynamicFields = "0"; - internalName = "subSurfaceCheckbox"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiCheckBoxProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "8 46"; - Extent = "79 16"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - Command = "MaterialEditorGui.updateActiveMaterial(\"subSurface[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());"; - tooltipprofile = "ToolsGuiDefaultProfile"; - ToolTip = "Enables the use of subsurface scattering for this layer."; - hovertime = "1000"; - text = "Sub Surface"; - groupNum = "-1"; - buttonType = "ToggleButton"; - useMouseEvents = "0"; - useInactiveState = "0"; - }; - new GuiSwatchButtonCtrl() { - canSaveDynamicFields = "0"; - internalName = "subSurfaceColorSwatch"; - Enabled = "1"; - isContainer = "0"; - Profile = "GuiInspectorSwatchButtonProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "90 46"; - Extent = "16 16"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - Command = "getColorF(materialEd_PreviewMaterial.subSurfaceColor[MaterialEditorGui.currentLayer], \"MaterialEditorGui.updateSubSurfaceColor\");"; - tooltip = "Set the subsurface scattering color"; - hovertime = "1000"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - }; - new GuiTextEditCtrl() { - canSaveDynamicFields = "0"; - internalName = "subSurfaceRolloffTextEdit"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiTextEditProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "114 45"; - Extent = "29 18"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - tooltip = "Set the subsurface rolloff factor"; - Command = "MaterialEditorGui.updateActiveMaterial(\"subSurfaceRolloff[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getText());"; - hovertime = "1000"; - AnchorTop = "1"; - AnchorBottom = "0"; - AnchorLeft = "1"; - AnchorRight = "0"; - text = "32"; - maxLength = "5"; - }; - new GuiTextCtrl() { - HorizSizing = "right"; - VertSizing = "bottom"; - position = "9 65"; - Extent = "89 16"; - text = "Minnaert constant"; - }; - new GuiTextEditCtrl() { - canSaveDynamicFields = "0"; - internalName = "minnaertTextEdit"; - Enabled = "1"; - isContainer = "0"; - Profile = "ToolsGuiTextEditProfile"; - HorizSizing = "right"; - VertSizing = "bottom"; - position = "114 65"; - Extent = "29 18"; - MinExtent = "8 2"; - canSave = "1"; - Visible = "1"; - Command = "MaterialEditorGui.updateActiveMaterial(\"minnaertConstant[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getText());"; - hovertime = "1000"; - AnchorTop = "1"; - AnchorBottom = "0"; - AnchorLeft = "1"; - AnchorRight = "0"; - text = "32"; - maxLength = "3"; - }; }; }; }; @@ -2471,9 +2252,9 @@ Position = "0 0"; Extent = "185 0"; Caption = "Animation Properties"; + Expanded = false; Margin = "-1 0 0 0"; DragSizable = false; - Expanded = false; container = true; parentRollout = %this.rollout; object = %behavior; @@ -3283,6 +3064,7 @@ Position = "0 0"; Extent = "202 0"; Caption = "Advanced (all layers)"; + Expanded = false; Margin = "4 4 4 0"; DragSizable = false; container = true; @@ -3519,7 +3301,7 @@ Profile = "ToolsGuiCheckBoxProfile"; HorizSizing = "right"; VertSizing = "bottom"; - position = "100 56"; + position = "105 55"; Extent = "85 16"; MinExtent = "8 2"; canSave = "1"; diff --git a/Templates/Empty/game/tools/worldEditor/main.cs b/Templates/Empty/game/tools/worldEditor/main.cs index a6ecb2872..59301ea53 100644 --- a/Templates/Empty/game/tools/worldEditor/main.cs +++ b/Templates/Empty/game/tools/worldEditor/main.cs @@ -120,6 +120,9 @@ function initializeWorldEditor() EVisibility.addOption( "AL: Light Specular Viz", "$AL_LightSpecularVisualizeVar", "toggleLightSpecularViz" ); EVisibility.addOption( "AL: Normals Viz", "$AL_NormalsVisualizeVar", "toggleNormalsViz" ); EVisibility.addOption( "AL: Depth Viz", "$AL_DepthVisualizeVar", "toggleDepthViz" ); + EVisibility.addOption( "AL: Color Buffer", "$AL_ColorBufferShaderVar", "toggleColorBufferViz" ); + EVisibility.addOption( "AL: Spec Map", "$AL_SpecMapShaderVar", "toggleSpecMapViz"); + EVisibility.addOption( "AL: Backbuffer", "$AL_BackbufferVisualizeVar", "toggleBackbufferViz" ); EVisibility.addOption( "AL: Glow Buffer", "$AL_GlowVisualizeVar", "toggleGlowViz" ); EVisibility.addOption( "AL: PSSM Cascade Viz", "$AL::PSSMDebugRender", "" ); EVisibility.addOption( "Frustum Lock", "$Scene::lockCull", "" ); diff --git a/Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs b/Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs index 97ae5d2d7..8ee4f27ff 100644 --- a/Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs +++ b/Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs @@ -244,6 +244,8 @@ function EditorSaveMissionMenu() function EditorSaveMission() { + // just save the mission without renaming it + // first check for dirty and read-only files: if((EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) && !isWriteableFileName($Server::MissionFile)) { From ad613f2e825b9d295a192e1f9554cade586f3d15 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Sun, 8 May 2016 21:52:00 -0500 Subject: [PATCH 18/71] alternate to https://github.com/GarageGames/Torque3D/pull/1602 --- Engine/source/T3D/lightAnimData.cpp | 8 +++++--- Engine/source/T3D/lightAnimData.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/lightAnimData.cpp b/Engine/source/T3D/lightAnimData.cpp index b61d2b47d..c5ef93b0f 100644 --- a/Engine/source/T3D/lightAnimData.cpp +++ b/Engine/source/T3D/lightAnimData.cpp @@ -190,13 +190,15 @@ void LightAnimData::AnimValue::updateKey() } template -bool LightAnimData::AnimValue::animate( F32 time, F32 *output ) +bool LightAnimData::AnimValue::animate(F32 time, F32 *output, bool multiply) { F32 scaledTime, lerpFactor, valueRange, keyFrameLerp; U32 posFrom, posTo; S32 keyFrameFrom, keyFrameTo; F32 initialValue = *output; - + if (!multiply) + initialValue = 1; + bool wasAnimated = false; for ( U32 i=0; i < COUNT; i++ ) @@ -305,6 +307,6 @@ void LightAnimData::animate( LightInfo *lightInfo, LightAnimState *state ) lightInfo->setColor( color ); F32 brightness = state->brightness; - mBrightness.animate( time, &brightness ); + mBrightness.animate( time, &brightness, true ); lightInfo->setBrightness( brightness ); } diff --git a/Engine/source/T3D/lightAnimData.h b/Engine/source/T3D/lightAnimData.h index 69b2ff65d..d8c933674 100644 --- a/Engine/source/T3D/lightAnimData.h +++ b/Engine/source/T3D/lightAnimData.h @@ -151,7 +151,7 @@ public: /// Performs the animation returning the results in the output if /// the time scale is greater than zero. /// @return Returns true if the animation was performed. - bool animate( F32 time, F32 *output ); + bool animate(F32 time, F32 *output, bool multiply = false); /// Called when the key string is changed to update the /// key length and time scale. From 5958e86e9af396b604baf4f4554a8ac2f6980544 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Mon, 9 May 2016 06:43:47 -0500 Subject: [PATCH 19/71] corrects native file dialogue return values --- .../source/platform/nativeDialogs/fileDialog.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Engine/source/platform/nativeDialogs/fileDialog.cpp b/Engine/source/platform/nativeDialogs/fileDialog.cpp index 84b367618..f7eb26a53 100644 --- a/Engine/source/platform/nativeDialogs/fileDialog.cpp +++ b/Engine/source/platform/nativeDialogs/fileDialog.cpp @@ -210,14 +210,14 @@ bool FileDialog::Execute() } String strippedFilters = suffix; strippedFilters.replace(";",","); - strippedFilters += String(";") + suffix; + strippedFilters += String(";") + suffix; // Get the current working directory, so we can back up to it once Windows has // done its craziness and messed with it. StringTableEntry cwd = Platform::getCurrentDirectory(); if (mData.mDefaultPath == StringTable->lookup("") || !Platform::isDirectory(mData.mDefaultPath)) mData.mDefaultPath = cwd; - + String rootDir = String(cwd); // Execute Dialog (Blocking Call) nfdchar_t *outPath = NULL; nfdpathset_t pathSet; @@ -226,6 +226,7 @@ bool FileDialog::Execute() String defaultPath = String(mData.mDefaultPath); #if defined(TORQUE_OS_WIN) defaultPath.replace("/", "\\"); + rootDir.replace("/", "\\"); #endif if (mData.mStyle & FileDialogData::FDS_OPEN) @@ -235,6 +236,11 @@ bool FileDialog::Execute() else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES) result = NFD_OpenDialogMultiple(strippedFilters.c_str(), defaultPath.c_str(), &pathSet); + String resultPath = String(outPath).replace(rootDir, String("")); + resultPath = resultPath.replace(0, 1, String("")).c_str(); //kill '\\' prefix + resultPath = resultPath.replace(String("\\"), String("/")); + + // Did we select a file? if (result != NFD_OKAY) { @@ -245,7 +251,7 @@ bool FileDialog::Execute() if (mData.mStyle & FileDialogData::FDS_OPEN || mData.mStyle & FileDialogData::FDS_SAVE) { // Single file selection, do it the easy way - mData.mFile = StringTable->insert(outPath); + mData.mFile = Platform::makeRelativePathName(resultPath.c_str(), NULL); } else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES) { @@ -265,7 +271,7 @@ bool FileDialog::Execute() else { //nope, just one file, so set it as normal - setDataField(StringTable->insert("files"), "0", outPath); + setDataField(StringTable->insert("files"), "0", Platform::makeRelativePathName(resultPath.c_str(), NULL)); setDataField(StringTable->insert("fileCount"), NULL, "1"); } } From 3a995415414c1d07ea7e894aac27838a7e194b7b Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 9 May 2016 13:43:06 -0500 Subject: [PATCH 20/71] Select camera when in material editor crashfix. When attempting to select a camera Object(so going into the editor, going into the freefloating camera and then back to the player camera and selecting the freefloating one) while the material editor was open, it would crash because it attempts to access the shapebase object's shapeInstance - but cameras don't have a shape. This fixes it so it makes sure there's a shapeinstance before trying to get the material data. --- Engine/source/T3D/shapeBase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 52ea070e3..e8e067465 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -4888,7 +4888,8 @@ DefineEngineMethod( ShapeBase, getTargetCount, S32, (),, if ((ShapeBase*)obj->getClientObject()) obj = (ShapeBase*)obj->getClientObject(); - return obj->getShapeInstance()->getTargetCount(); + if (obj->getShapeInstance() != NULL) + return obj->getShapeInstance()->getTargetCount(); } return -1; From 27bb7a712a57c3769e9d3a395e2096908dd30349 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 9 May 2016 13:47:29 -0500 Subject: [PATCH 21/71] Corrects tabs. --- Engine/source/T3D/shapeBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index e8e067465..c33cb7f73 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -4889,7 +4889,7 @@ DefineEngineMethod( ShapeBase, getTargetCount, S32, (),, obj = (ShapeBase*)obj->getClientObject(); if (obj->getShapeInstance() != NULL) - return obj->getShapeInstance()->getTargetCount(); + return obj->getShapeInstance()->getTargetCount(); } return -1; From 8d195f923693dd6012cd388b7250354f81d89c00 Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 10 May 2016 10:58:03 -0500 Subject: [PATCH 22/71] Makes the tab/spaces consistent for the entire console method function rather than mix-n-matching the formatting. --- Engine/source/T3D/shapeBase.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index c33cb7f73..6f40cc134 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -4881,18 +4881,18 @@ DefineEngineMethod( ShapeBase, getTargetCount, S32, (),, "@see getTargetName()\n") { - ShapeBase *obj = dynamic_cast< ShapeBase* > ( object ); - if(obj) - { - // Try to use the client object (so we get the reskinned targets in the Material Editor) - if ((ShapeBase*)obj->getClientObject()) - obj = (ShapeBase*)obj->getClientObject(); + ShapeBase *obj = dynamic_cast< ShapeBase* > ( object ); + if(obj) + { + // Try to use the client object (so we get the reskinned targets in the Material Editor) + if ((ShapeBase*)obj->getClientObject()) + obj = (ShapeBase*)obj->getClientObject(); if (obj->getShapeInstance() != NULL) return obj->getShapeInstance()->getTargetCount(); } - - return -1; + + return -1; } DefineEngineMethod( ShapeBase, changeMaterial, void, ( const char* mapTo, Material* oldMat, Material* newMat ),, From 383d27f2ec8acb5e3005b07af8739170aaf6a3f9 Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 12 May 2016 00:45:16 -0500 Subject: [PATCH 23/71] The class is designed as a general-purpose rotation/orientation class to make it easy to work with rotations and swap between math types as easily as possible. --- Engine/source/console/consoleTypes.h | 2 + Engine/source/gui/editor/inspector/field.cpp | 3 +- Engine/source/math/mRotation.cpp | 299 ++++++++++++ Engine/source/math/mRotation.h | 465 +++++++++++++++++++ Engine/source/math/mathIO.h | 24 + Engine/source/math/mathTypes.cpp | 60 ++- Engine/source/math/mathTypes.h | 5 +- 7 files changed, 853 insertions(+), 5 deletions(-) create mode 100644 Engine/source/math/mRotation.cpp create mode 100644 Engine/source/math/mRotation.h diff --git a/Engine/source/console/consoleTypes.h b/Engine/source/console/consoleTypes.h index c026b8e1a..ab5b97d62 100644 --- a/Engine/source/console/consoleTypes.h +++ b/Engine/source/console/consoleTypes.h @@ -74,6 +74,8 @@ DefineConsoleType( TypeCommand, String ) DefineConsoleType( TypeFilename, const char * ) DefineConsoleType( TypeStringFilename, String ) +DefineConsoleType(TypeRotationF, RotationF) + /// A universally unique identifier. DefineConsoleType( TypeUUID, Torque::UUID ) diff --git a/Engine/source/gui/editor/inspector/field.cpp b/Engine/source/gui/editor/inspector/field.cpp index ac72b2e04..45aa1b2b0 100644 --- a/Engine/source/gui/editor/inspector/field.cpp +++ b/Engine/source/gui/editor/inspector/field.cpp @@ -284,7 +284,8 @@ void GuiInspectorField::setData( const char* data, bool callbacks ) || type == TypeMatrixPosition || type == TypeMatrixRotation || type == TypeBox3F - || type == TypeRectUV ) + || type == TypeRectUV + || type == TypeRotationF) { //TODO: we should actually take strings into account and not chop things up between quotes diff --git a/Engine/source/math/mRotation.cpp b/Engine/source/math/mRotation.cpp new file mode 100644 index 000000000..d915348d6 --- /dev/null +++ b/Engine/source/math/mRotation.cpp @@ -0,0 +1,299 @@ +//----------------------------------------------------------------------------- +// 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 "math/mRotation.h" + +#ifdef TORQUE_TESTS_ENABLED +#include "testing/unitTesting.h" +#endif + +//==================================================================== +//Eulers setup +//==================================================================== +RotationF::RotationF(EulerF _euler, UnitFormat format) +{ + set(_euler.x, _euler.y, _euler.z, format); +} + +RotationF::RotationF(F32 _x, F32 _y, F32 _z, UnitFormat format) +{ + set(_x, _y, _z, format); +} + +void RotationF::set(EulerF _euler, UnitFormat format) +{ + x = format == Degrees ? mDegToRad(_euler.x) : _euler.x; + y = format == Degrees ? mDegToRad(_euler.y) : _euler.y; + z = format == Degrees ? mDegToRad(_euler.z) : _euler.z; + + mRotationType = Euler; +} + +void RotationF::set(F32 _x, F32 _y, F32 _z, UnitFormat format) +{ + EulerF tempEul; + if (format == Degrees) + { + tempEul.set(mDegToRad(_x), mDegToRad(_y), mDegToRad(_z)); + } + else + { + tempEul.set(_x, _y, _z); + } + + set(tempEul); +} + +//==================================================================== +//AxisAngle setup +//==================================================================== +RotationF::RotationF(AngAxisF _aa, UnitFormat format) +{ + set(_aa, format); +} + +void RotationF::set(AngAxisF _aa, UnitFormat format) +{ + x = _aa.axis.x; + y = _aa.axis.y; + z = _aa.axis.z; + + w = format == Degrees ? mDegToRad(_aa.angle) : _aa.angle; + + mRotationType = AxisAngle; +} + +//==================================================================== +//QuatF setup +//==================================================================== +RotationF::RotationF(QuatF _quat) +{ + set(_quat); +} + +void RotationF::set(QuatF _quat) +{ + AngAxisF tmpAA; + tmpAA.set(_quat); + + set(tmpAA); +} + +//==================================================================== +//MatrixF setup +//==================================================================== +RotationF::RotationF(MatrixF _mat) +{ + set(_mat); +} + +void RotationF::set(MatrixF _mat) +{ + set(_mat.toEuler()); +} + +// +inline F32 RotationF::len() const +{ + return asEulerF().len(); +} + +inline void RotationF::interpolate(const RotationF& _from, const RotationF& _to, F32 _factor) +{ + QuatF tmpQuat; + + tmpQuat.interpolate(_from.asQuatF(), _to.asQuatF(), _factor); + + set(tmpQuat); +} + +void RotationF::lookAt(const Point3F& _origin, const Point3F& _target, const Point3F& _up) +{ + MatrixF mat; + + VectorF newForward = _target - _origin; + newForward.normalize(); + + VectorF up(0.0f, 0.0f, 1.0f); + VectorF axisX; + VectorF axisY = newForward; + VectorF axisZ; + + if (_up != VectorF::Zero) + up = _up; + + // Validate and normalize input: + F32 lenSq; + lenSq = axisY.lenSquared(); + if (lenSq < 0.000001f) + { + //degenerate forward vector + axisY.set(0.0f, 1.0f, 0.0f); + } + else + { + axisY /= mSqrt(lenSq); + } + + + lenSq = up.lenSquared(); + if (lenSq < 0.000001f) + { + //degenerate up vector - too small + up.set(0.0f, 0.0f, 1.0f); + } + else + { + up /= mSqrt(lenSq); + } + + if (fabsf(mDot(up, axisY)) > 0.9999f) + { + //degenerate up vector - same as forward + F32 tmp = up.x; + up.x = -up.y; + up.y = up.z; + up.z = tmp; + } + + // construct the remaining axes: + mCross(axisY, up, &axisX); + mCross(axisX, axisY, &axisZ); + + mat.setColumn(0, axisX); + mat.setColumn(1, axisY); + mat.setColumn(2, axisZ); + + set(mat); +} + +//======================================================== +EulerF RotationF::asEulerF(UnitFormat _format) const +{ + if (mRotationType == Euler) + { + if (_format == Degrees) + { + return EulerF(mRadToDeg(x), mRadToDeg(y), mRadToDeg(z)); + } + else + { + return EulerF(x, y, z); + } + } + else + { + EulerF returnEuler = asMatrixF().toEuler(); + + if (_format == Degrees) + { + returnEuler.x = mRadToDeg(returnEuler.x); + returnEuler.y = mRadToDeg(returnEuler.y); + returnEuler.z = mRadToDeg(returnEuler.z); + } + + return returnEuler; + } +} + +AngAxisF RotationF::asAxisAngle(UnitFormat format) const +{ + AngAxisF returnAA; + + if (mRotationType == Euler) + { + returnAA.set(EulerF(x, y, z)); + } + else + { + returnAA.set(Point3F(x, y, z), w); + } + + if (format == Radians) + { + returnAA.angle = mDegToRad(returnAA.angle); + } + + return returnAA; +} + +MatrixF RotationF::asMatrixF() const +{ + MatrixF returnMat; + if (mRotationType == Euler) + { + returnMat.set(EulerF(x, y, z)); + } + else + { + AngAxisF aa; + aa.set(Point3F(x, y, z), w); + + aa.setMatrix(&returnMat); + } + + return returnMat; +} + +QuatF RotationF::asQuatF() const +{ + QuatF returnQuat; + if (mRotationType == Euler) + { + returnQuat.set(EulerF(x, y, z)); + } + else + { + AngAxisF aa; + aa.set(Point3F(x, y, z), w); + + returnQuat.set(aa); + } + + return returnQuat; +} + +void RotationF::normalize() +{ + if (mRotationType == Euler) + { + EulerF eul = EulerF(x, y, z); + eul.normalize(); + set(eul); + } + else + { + QuatF quat; + quat.set(Point3F(x, y, z), w); + + quat.normalize(); + + set(quat); + } +} + +//Testing +#ifdef TORQUE_TESTS_ENABLED +TEST(Maths, RotationF_Calculations) +{ + //TODO: implement unit test +}; +#endif \ No newline at end of file diff --git a/Engine/source/math/mRotation.h b/Engine/source/math/mRotation.h new file mode 100644 index 000000000..a99510b8c --- /dev/null +++ b/Engine/source/math/mRotation.h @@ -0,0 +1,465 @@ +//----------------------------------------------------------------------------- +// 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 MROTATION_H +#define MROTATION_H + +#ifndef _MMATHFN_H_ +#include "math/mMathFn.h" +#endif + +#ifndef _MPOINT3_H_ +#include "math/mPoint3.h" +#endif + +#ifndef _MQUAT_H_ +#include "math/mQuat.h" +#endif + +#ifndef _MMATRIX_H_ +#include "math/mMatrix.h" +#endif + +#ifndef _MANGAXIS_H_ +#include "math/mAngAxis.h" +#endif + +//------------------------------------------------------------------------------ +/// Rotation Interop Utility class +/// +/// Useful for easily handling rotations/orientations in transforms while manipulating or converting between formats. +class RotationF +{ + //-------------------------------------- Public data +public: + F32 x; ///< X co-ordinate. + F32 y; ///< Y co-ordinate. + F32 z; ///< Z co-ordinate. + F32 w; ///< W co-ordinate. + + enum RotationTypes + { + Euler = 0, + AxisAngle + }; + RotationTypes mRotationType; + + enum UnitFormat + { + Radians = 0, + Degrees + }; + + RotationF(); ///< Create an uninitialized point. + RotationF(const RotationF&); ///< Copy constructor. + + // + //Eulers + RotationF(EulerF euler, UnitFormat format = Radians); + RotationF(F32 _x, F32 _y, F32 _z, UnitFormat format = Radians); + + void set(EulerF euler, UnitFormat format = Radians); + void set(F32 _x, F32 _y, F32 _z, UnitFormat format = Radians); + + //As with AxisAngles, we make the assumption here that if not told otherwise, inbound rotations are in Degrees. + RotationF operator=(const EulerF&); + RotationF operator-(const EulerF&) const; + RotationF operator+(const EulerF&) const; + RotationF& operator-=(const EulerF&); + RotationF& operator+=(const EulerF&); + S32 operator==(const EulerF&) const; + S32 operator!=(const EulerF&) const; + + // + //AxisAngle + RotationF(AngAxisF aa, UnitFormat format = Radians); + void set(AngAxisF aa, UnitFormat format = Radians); + + //As with Eulers, we make the assumption here that if not told otherwise, inbound rotations are in Degrees. + RotationF operator=(const AngAxisF&); + RotationF operator-(const AngAxisF&) const; + RotationF operator+(const AngAxisF&) const; + RotationF& operator-=(const AngAxisF&); + RotationF& operator+=(const AngAxisF&); + S32 operator==(const AngAxisF&) const; + S32 operator!=(const AngAxisF&) const; + + // + //Quat + RotationF(QuatF quat); + void set(QuatF _quat); + + RotationF operator=(const QuatF&); + RotationF operator-(const QuatF&) const; + RotationF operator+(const QuatF&) const; + RotationF& operator-=(const QuatF&); + RotationF& operator+=(const QuatF&); + S32 operator==(const QuatF&) const; + S32 operator!=(const QuatF&) const; + + // + //Matrix + RotationF(MatrixF mat); + void set(MatrixF _mat); + + RotationF operator=(const MatrixF&); + RotationF operator-(const MatrixF&) const; + RotationF operator+(const MatrixF&) const; + RotationF& operator-=(const MatrixF&); + RotationF& operator+=(const MatrixF&); + S32 operator==(const MatrixF&) const; + S32 operator!=(const MatrixF&) const; + + // + void interpolate(const RotationF& _pt1, const RotationF& _pt2, F32 _factor); + void lookAt(const Point3F& _origin, const Point3F& _target, const Point3F& _up = Point3F(0, 0, 1)); + + F32 len() const; + + void normalize(); + + //Non-converting operators + S32 operator ==(const RotationF &) const; + S32 operator !=(const RotationF &) const; + + RotationF operator+(const RotationF&) const; + RotationF& operator+=(const RotationF&); + RotationF operator-(const RotationF&) const; + RotationF& operator-=(const RotationF&); + + RotationF& operator=(const RotationF&); + + //Conversion stuffs + EulerF asEulerF(UnitFormat format = Radians) const; + AngAxisF asAxisAngle(UnitFormat format = Radians) const; + MatrixF asMatrixF() const; + QuatF asQuatF() const; +}; + +inline RotationF::RotationF() +{ + x = 0; + y = 0; + z = 0; + w = 0; + + mRotationType = AxisAngle; +} + +inline RotationF::RotationF(const RotationF& _copy) + : x(_copy.x), y(_copy.y), z(_copy.z), w(_copy.w), mRotationType(_copy.mRotationType) +{} + +inline int RotationF::operator ==(const RotationF& _rotation) const +{ + return (x == _rotation.x && y == _rotation.y && z == _rotation.z && w == _rotation.w); +} + +inline int RotationF::operator !=(const RotationF& _rotation) const +{ + return (x != _rotation.x || y != _rotation.y || z != _rotation.z || w != _rotation.w); +} + +//When it comes to actually trying to add rotations, we, in fact, actually multiply their data together. +//Since we're specifically operating on usability for RotationF, we'll operate on this, rather than the literal addition of the values +inline RotationF& RotationF::operator +=(const RotationF& _rotation) +{ + if (mRotationType == Euler) + { + x += _rotation.x; + y += _rotation.y; + z += _rotation.z; + } + else + { + MatrixF tempMat = asMatrixF(); + MatrixF tempMatAdd = _rotation.asMatrixF(); + + tempMat.mul(tempMatAdd); + + this->set(tempMat); + } + + return *this; +} + +inline RotationF RotationF::operator +(const RotationF& _rotation) const +{ + RotationF result = *this; + + if (mRotationType == Euler) + { + result.x += _rotation.x; + result.y += _rotation.y; + result.z += _rotation.z; + } + else + { + MatrixF tempMat = asMatrixF(); + MatrixF tempMatAdd = _rotation.asMatrixF(); + + tempMat.mul(tempMatAdd); + + result.set(tempMat); + } + + return result; +} + +//Much like addition, when subtracting, we're not literally subtracting the values, but infact multiplying the inverse. +//This subtracts the rotation angles to get the difference +inline RotationF& RotationF::operator -=(const RotationF& _rotation) +{ + if (mRotationType == Euler) + { + x -= _rotation.x; + y -= _rotation.y; + z -= _rotation.z; + } + else + { + MatrixF tempMat = asMatrixF(); + MatrixF tempMatAdd = _rotation.asMatrixF(); + + tempMatAdd.inverse(); + + tempMat.mul(tempMatAdd); + + this->set(tempMat); + } + + return *this; +} + +inline RotationF RotationF::operator -(const RotationF& _rotation) const +{ + RotationF result = *this; + + if (mRotationType == Euler) + { + result.x += _rotation.x; + result.y += _rotation.y; + result.z += _rotation.z; + } + else + { + MatrixF tempMat = asMatrixF(); + MatrixF tempMatAdd = _rotation.asMatrixF(); + tempMatAdd.inverse(); + + tempMat.mul(tempMatAdd); + + result.set(tempMat); + } + + return result; +} + +inline RotationF& RotationF::operator =(const RotationF& _rotation) +{ + x = _rotation.x; + y = _rotation.y; + z = _rotation.z; + w = _rotation.w; + + mRotationType = _rotation.mRotationType; + + return *this; +} + +//==================================================================== +// Euler operators +//==================================================================== +inline RotationF RotationF::operator=(const EulerF& _euler) +{ + return RotationF(_euler, Radians); +} + +inline RotationF RotationF::operator-(const EulerF& _euler) const +{ + RotationF temp = *this; + temp -= RotationF(_euler, Radians); + return temp; +} + +inline RotationF RotationF::operator+(const EulerF& _euler) const +{ + RotationF temp = *this; + temp += RotationF(_euler, Radians); + return temp; +} + +inline RotationF& RotationF::operator-=(const EulerF& _euler) +{ + *this -= RotationF(_euler, Radians); + return *this; +} + +inline RotationF& RotationF::operator+=(const EulerF& _euler) +{ + *this += RotationF(_euler, Radians); + return *this; +} + +inline S32 RotationF::operator==(const EulerF& _euler) const +{ + return *this == RotationF(_euler); +} + +inline S32 RotationF::operator!=(const EulerF& _euler) const +{ + return *this != RotationF(_euler); +} + +//==================================================================== +// AxisAngle operators +//==================================================================== +inline RotationF RotationF::operator=(const AngAxisF& _aa) +{ + return RotationF(_aa, Radians); +} + +inline RotationF RotationF::operator-(const AngAxisF& _aa) const +{ + RotationF temp = *this; + temp -= RotationF(_aa, Radians); + return temp; +} + +inline RotationF RotationF::operator+(const AngAxisF& _aa) const +{ + RotationF temp = *this; + temp += RotationF(_aa, Radians); + return temp; +} + +inline RotationF& RotationF::operator-=(const AngAxisF& _aa) +{ + *this -= RotationF(_aa, Radians); + return *this; +} + +inline RotationF& RotationF::operator+=(const AngAxisF& _aa) +{ + *this += RotationF(_aa, Radians); + return *this; +} + +inline S32 RotationF::operator==(const AngAxisF& _aa) const +{ + return *this == RotationF(_aa); +} + +inline S32 RotationF::operator!=(const AngAxisF& _aa) const +{ + return *this != RotationF(_aa); +} + +//==================================================================== +// QuatF operators +//==================================================================== +inline RotationF RotationF::operator=(const QuatF& _quat) +{ + return RotationF(_quat); +} + +inline RotationF RotationF::operator-(const QuatF& _quat) const +{ + RotationF temp = *this; + temp -= RotationF(_quat); + return temp; +} + +inline RotationF RotationF::operator+(const QuatF& _quat) const +{ + RotationF temp = *this; + temp += RotationF(_quat); + return temp; +} + +inline RotationF& RotationF::operator-=(const QuatF& _quat) +{ + *this -= RotationF(_quat); + return *this; +} + +inline RotationF& RotationF::operator+=(const QuatF& _quat) +{ + *this += RotationF(_quat); + return *this; +} + +inline S32 RotationF::operator==(const QuatF& _quat) const +{ + return *this == RotationF(_quat); +} + +inline S32 RotationF::operator!=(const QuatF& _quat) const +{ + return *this != RotationF(_quat); +} + +//==================================================================== +// MatrixF operators +//==================================================================== +inline RotationF RotationF::operator=(const MatrixF& _mat) +{ + return RotationF(_mat); +} + +inline RotationF RotationF::operator-(const MatrixF& _mat) const +{ + RotationF temp = *this; + temp -= RotationF(_mat); + return temp; +} + +inline RotationF RotationF::operator+(const MatrixF& _mat) const +{ + RotationF temp = *this; + temp += RotationF(_mat); + return temp; +} + +inline RotationF& RotationF::operator-=(const MatrixF& _mat) +{ + *this -= RotationF(_mat); + return *this; +} + +inline RotationF& RotationF::operator+=(const MatrixF& _mat) +{ + *this += RotationF(_mat); + return *this; +} + +inline S32 RotationF::operator==(const MatrixF& _mat) const +{ + return *this == RotationF(_mat); +} + +inline S32 RotationF::operator!=(const MatrixF& _mat) const +{ + return *this != RotationF(_mat); +} + +#endif // MROTATION_H diff --git a/Engine/source/math/mathIO.h b/Engine/source/math/mathIO.h index ee2f0dcad..6acbc1b52 100644 --- a/Engine/source/math/mathIO.h +++ b/Engine/source/math/mathIO.h @@ -149,6 +149,20 @@ inline bool mathRead(Stream& stream, EaseF* e) return success; } +inline bool mathRead(Stream& stream, RotationF* e) +{ + bool success = stream.read(&e->x); + success &= stream.read(&e->y); + success &= stream.read(&e->z); + success &= stream.read(&e->w); + + U32 rotType; + success &= stream.read(&rotType); + e->mRotationType = (RotationF::RotationTypes)rotType; + + return success; +} + //------------------------------------------------------------------------------ //-------------------------------------- WRITING // @@ -263,5 +277,15 @@ inline bool mathWrite(Stream& stream, const EaseF& e) return success; } +inline bool mathWrite(Stream& stream, const RotationF& e) +{ + bool success = stream.write(e.x); + success &= stream.write(e.y); + success &= stream.write(e.z); + success &= stream.write(e.w); + success &= stream.write(e.mRotationType); + return success;; +} + #endif //_MATHIO_H_ diff --git a/Engine/source/math/mathTypes.cpp b/Engine/source/math/mathTypes.cpp index 29c500b60..dd018b2a4 100644 --- a/Engine/source/math/mathTypes.cpp +++ b/Engine/source/math/mathTypes.cpp @@ -36,7 +36,7 @@ #include "math/mRandom.h" #include "math/mEase.h" #include "math/mathUtils.h" - +#include "math/mRotation.h" #include "core/strings/stringUnit.h" IMPLEMENT_SCOPE( MathTypes, Math,, "" ); @@ -113,7 +113,14 @@ IMPLEMENT_STRUCT( EaseF, EaseF, MathTypes, "" ) END_IMPLEMENT_STRUCT; - +IMPLEMENT_STRUCT(RotationF, + RotationF, MathTypes, + "") + FIELD(x, x, 1, "X coordinate.") + FIELD(y, y, 1, "Y coordinate.") + FIELD(z, z, 1, "Z coordinate.") + FIELD(w, w, 1, "W coordinate.") +END_IMPLEMENT_STRUCT; //----------------------------------------------------------------------------- // TypePoint2I @@ -572,6 +579,55 @@ ConsoleSetType( TypeEaseF ) } } +//----------------------------------------------------------------------------- +// TypeRotationF +//----------------------------------------------------------------------------- +ConsoleType(RotationF, TypeRotationF, RotationF, "") +//ImplementConsoleTypeCasters( TypeRotationF, RotationF ) + +ConsoleGetType(TypeRotationF) +{ + RotationF *pt = (RotationF *)dptr; + static const U32 bufSize = 256; + char* returnBuffer = Con::getReturnBuffer(bufSize); + + EulerF out = pt->asEulerF(RotationF::Degrees); + dSprintf(returnBuffer, bufSize, "%g %g %g", out.x, out.y, out.z); + + return returnBuffer; +} + +ConsoleSetType(TypeRotationF) +{ + if (argc == 1) + { + U32 elements = StringUnit::getUnitCount(argv[0], " \t\n"); + if (elements == 3) + { + EulerF in; + dSscanf(argv[0], "%g %g %g", &in.x, &in.y, &in.z); + ((RotationF *)dptr)->set(in, RotationF::Degrees); + } + else + { + AngAxisF in; + dSscanf(argv[0], "%g %g %g %g", &in.axis.x, &in.axis.y, &in.axis.z, &in.angle); + ((RotationF *)dptr)->set(in, RotationF::Degrees); + } + } + else if (argc == 3) + { + EulerF in(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])); + ((RotationF *)dptr)->set(in, RotationF::Degrees); + } + else if (argc == 4) + { + AngAxisF in(Point3F(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])), dAtof(argv[3])); + ((RotationF *)dptr)->set(in, RotationF::Degrees); + } + else + Con::printf("RotationF must be set as { x, y, z, w } or \"x y z w\""); +} //----------------------------------------------------------------------------- diff --git a/Engine/source/math/mathTypes.h b/Engine/source/math/mathTypes.h index b17329cf8..043d59e1f 100644 --- a/Engine/source/math/mathTypes.h +++ b/Engine/source/math/mathTypes.h @@ -43,7 +43,7 @@ class Box3F; class EaseF; class AngAxisF; class TransformF; - +class RotationF; DECLARE_SCOPE( MathTypes ); @@ -60,6 +60,7 @@ DECLARE_STRUCT( AngAxisF ); DECLARE_STRUCT( TransformF ); DECLARE_STRUCT( Box3F ); DECLARE_STRUCT( EaseF ); +DECLARE_STRUCT(RotationF); // Legacy console types. @@ -77,6 +78,6 @@ DefineConsoleType( TypeAngAxisF, AngAxisF ) DefineConsoleType( TypeTransformF, TransformF ) DefineConsoleType( TypeBox3F, Box3F ) DefineConsoleType( TypeEaseF, EaseF ) - +DefineConsoleType(TypeRotationF, RotationF) #endif From 95ae0b98631a51551d754c6be3f150e4ff18a95c Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 12 May 2016 23:31:15 -0500 Subject: [PATCH 24/71] Removes the old component code and moves the IProcessInput interface file into platform/input/ directory. --- .../source/component/componentInterface.cpp | 82 ---- Engine/source/component/componentInterface.h | 234 --------- .../dynamicConsoleMethodComponent.cpp | 209 -------- .../component/dynamicConsoleMethodComponent.h | 89 ---- .../component/moreAdvancedComponent.cpp | 60 --- .../source/component/moreAdvancedComponent.h | 55 --- Engine/source/component/simComponent.cpp | 452 ------------------ Engine/source/component/simComponent.h | 256 ---------- Engine/source/component/simpleComponent.cpp | 31 -- Engine/source/component/simpleComponent.h | 159 ------ .../test/moreAdvancedComponentTest.cpp | 68 --- .../component/test/simComponentTest.cpp | 149 ------ .../component/test/simpleComponentTest.cpp | 131 ----- Engine/source/gui/core/guiCanvas.h | 2 +- .../input}/IProcessInput.h | 0 .../windowManager/windowInputGenerator.cpp | 2 +- 16 files changed, 2 insertions(+), 1977 deletions(-) delete mode 100644 Engine/source/component/componentInterface.cpp delete mode 100644 Engine/source/component/componentInterface.h delete mode 100644 Engine/source/component/dynamicConsoleMethodComponent.cpp delete mode 100644 Engine/source/component/dynamicConsoleMethodComponent.h delete mode 100644 Engine/source/component/moreAdvancedComponent.cpp delete mode 100644 Engine/source/component/moreAdvancedComponent.h delete mode 100644 Engine/source/component/simComponent.cpp delete mode 100644 Engine/source/component/simComponent.h delete mode 100644 Engine/source/component/simpleComponent.cpp delete mode 100644 Engine/source/component/simpleComponent.h delete mode 100644 Engine/source/component/test/moreAdvancedComponentTest.cpp delete mode 100644 Engine/source/component/test/simComponentTest.cpp delete mode 100644 Engine/source/component/test/simpleComponentTest.cpp rename Engine/source/{component/interfaces => platform/input}/IProcessInput.h (100%) diff --git a/Engine/source/component/componentInterface.cpp b/Engine/source/component/componentInterface.cpp deleted file mode 100644 index e489ca0f2..000000000 --- a/Engine/source/component/componentInterface.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "component/simComponent.h" -#include "component/componentInterface.h" -#include "core/strings/findMatch.h" -#include "core/stringTable.h" - -bool ComponentInterfaceCache::add( const char *type, const char *name, const SimComponent *owner, ComponentInterface *cinterface ) -{ - if( ( mInterfaceList.size() == 0 ) || ( enumerate( NULL, type, name, owner ) == 0 ) ) - { - mInterfaceList.increment(); - // CodeReview [tom, 3/9/2007] Seems silly to keep calling last(), why not cache the var? Yes, I know I am pedantic. - mInterfaceList.last().type = ( type == NULL ? NULL : StringTable->insert( type ) ); - mInterfaceList.last().name = ( name == NULL ? NULL : StringTable->insert( name ) ); - mInterfaceList.last().owner = owner; - mInterfaceList.last().iface = cinterface; - - return true; - } - - return false; -} - -//------------------------------------------------------------------------------ - -void ComponentInterfaceCache::clear() -{ - mInterfaceList.clear(); -} - -//------------------------------------------------------------------------------ - -U32 ComponentInterfaceCache::enumerate( ComponentInterfaceList *list, const char *type /* = NULL */, - const char *name /* = NULL */, const SimComponent *owner /* = NULL */, bool notOwner /* = false */ ) const -{ - U32 numMatches = 0; - - for( _InterfaceEntryItr i = mInterfaceList.begin(); i != mInterfaceList.end(); i++ ) - { - // Early out if limiting results by component owner - if( owner != NULL && ( - ( (*i).owner == owner && notOwner ) || - ( (*i).owner != owner && !notOwner ) ) ) - continue; - - // Match the type, short circuit if type == NULL - if( type == NULL || FindMatch::isMatch( type, (*i).type ) ) - { - // Match the name - if( name == NULL || FindMatch::isMatch( name, (*i).name ) ) - { - numMatches++; - - if( list != NULL ) - list->push_back( (*i).iface ); - } - } - } - - return numMatches; -} \ No newline at end of file diff --git a/Engine/source/component/componentInterface.h b/Engine/source/component/componentInterface.h deleted file mode 100644 index 311862a1c..000000000 --- a/Engine/source/component/componentInterface.h +++ /dev/null @@ -1,234 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _COMPONENTINTERFACE_H_ -#define _COMPONENTINTERFACE_H_ - -#ifndef _TVECTOR_H_ -#include "core/util/tVector.h" -#endif - -#ifndef _SIMOBJECT_H_ -#include "console/simObject.h" -#endif - -#include "core/util/safeDelete.h" - - -class SimComponent; - - -// CodeReview [patw, 2, 13, 2007] The issue I have not addressed in this class is -// interface locking. I think that we want to do this, for sure, but I also want -// to keep it as light-weight as possible. For the most part, there should only -// ever be one thing doing something with a component at one time, but I can see -// many situations where this wouldn't be the case. When we decide to address -// the issues of locking, I believe it should be done here, at the ComponentInterface -// level. I would like lock functionality to be as centralized as possible, and -// so this is the place for it. The functionality is critical for safe useage of -// the ComponentProperty class, so implementation here would also be ideal. - -// CodeReview [patw, 2, 14, 2007] This really should be a ref-counted object -class ComponentInterface -{ - friend class SimComponent; -private: - SimObjectPtr mOwner; ///< SimComponent will directly modify this value - -public: - /// Default constructor - ComponentInterface() : mOwner(NULL) {}; - - /// Destructor - virtual ~ComponentInterface() - { - mOwner = NULL; - } - - /// This will return true if the interface is valid - virtual bool isValid() const - { - return mOwner != NULL; - } - - /// Get the owner of this interface - SimComponent *getOwner() { return mOwner; } - const SimComponent *getOwner() const { return mOwner; } -}; - -typedef VectorPtr ComponentInterfaceList; -typedef VectorPtr::iterator ComponentInterfaceListIterator; - -// These two asserts I found myself wanting a lot when doing interface methods -#ifdef TORQUE_ENABLE_ASSERTS -# define VALID_INTERFACE_ASSERT(OwningClassType) \ - AssertFatal( isValid(), "Interface validity check failed." ); \ - AssertFatal( dynamic_cast( getOwner() ) != NULL, avar( "Owner is not an instance of %s", #OwningClassType ) ) -#else -# define VALID_INTERFACE_ASSERT(OwningClassType) -#endif - -/// This class is designed to wrap an existing class or type easily to allow -/// a SimComponent to expose a property with custom processing code in an efficient -/// and safe way. Specialized templates could be written which include validation -/// on sets, and processing on gets. -/// -/// This class has a lot of "blow your leg off" potential, if you have bad aim. -/// I think that a lot of very intuitive functionality can be gained from using -/// this properly, however when implementing a specialized template, be mindful -/// of what you are doing, and - -// CodeReview [patw, 2, 13, 2007] I am very interested in making this as thin as -// possible. I really like the possibilities that it exposes as far as exposing -// "properties" to other components. I want it to be performant, however, so -// if anyone has notes on this, mark up the source, e-mail me, whatever. -template -class ComponentProperty : public ComponentInterface -{ - typedef ComponentInterface Parent; - -protected: - T *mValuePtr; - - // ComponentInterface Overrides -public: - - // Override this to add a check for valid memory. - virtual bool isValid() const - { - return ( mValuePtr != NULL ) && Parent::isValid(); - } - - // Operator overloads -public: - /// Dereferencing a value interface will allow get to do any processing and - /// return the reference to that - const T &operator*() - { - return get(); - } - - /// Assignment operator will invoke set. - const T &operator=( const T &lval ) - { - return set( lval ); - } - - // Constructors/Destructors, specialize these if needed -public: - /// Default Constructor. - ComponentProperty() : mValuePtr( NULL ) - { - mValuePtr = new T; - } - - /// Copy constructor - ComponentProperty( const T © ) - { - ComponentProperty(); - - // CodeReview [patw, 2, 13, 2007] So, the reasoning here is that I want to - // use the functionality that a specialized template implements in the set - // method. See the notes on the set method implementation. - set( copy ); - } - - /// Destructor, destroy memory - virtual ~ComponentProperty() - { - SAFE_DELETE( mValuePtr ); - } - - // This is the ComponentProperty interface that specializations of the class - // will be interested in. -public: - - /// Get the value associated with this interface. Processing code can be done - /// here for specialized implementations. - virtual const T &get() // 'const' is intentionally not used as a modifier here - { - return *mValuePtr; - } - - /// Set the value associated with this interface. Validation/processing code - /// can be done here. The copy-constructor uses the set method to do it's copy - /// so be mindful of that, or specialize the copy-constructor. - virtual const T &set( const T &t ) - { - // CodeReview [patw, 2, 13, 2007] So I am using the = operator here. Do you - // guys think that this should be the default behavior? I am trying to keep - // everything as object friendly as possible, so I figured I'd use this. - *mValuePtr = t; - return *mValuePtr; - } -}; - -/// This class is just designed to isolate the functionality of querying for, and -/// managing interfaces. -class ComponentInterfaceCache -{ - // CodeReview [patw, 2, 14, 2007] When we move this whole system to Juggernaught - // we may want to consider making safe pointers for ComponentInterfaces. Not - // sure why I put this note here. -private: - struct _InterfaceEntry - { - ComponentInterface *iface; - StringTableEntry type; - StringTableEntry name; - const SimComponent *owner; - }; - - Vector<_InterfaceEntry> mInterfaceList; - typedef Vector<_InterfaceEntry>::const_iterator _InterfaceEntryItr; - -public: - /// Add an interface to the cache. This function will return true if the interface - /// is added successfully. An interface will not be added successfully if an entry - /// in the list with the same values for 'type' and 'name' is present in the list. - /// - /// @param type Type of the interface being added. If NULL is passed, it will match any type string queried. - /// @param name Name of interface being added. If NULL is passed, it will match any name string queried. - /// @param owner The owner of the ComponentInterface being cached - /// @param cinterface The ComponentInterface being cached - virtual bool add( const char *type, const char *name, const SimComponent *owner, ComponentInterface *cinterface ); - - /// Clear the interface cache. This does not perform any operations on the contents - /// of the list. - virtual void clear(); - - /// Query the list for all of the interfaces it stores references to that match - /// the 'type' and 'name' parameters. The results of the query will be appended - /// to the list specified. Pattern matching is done using core/findMatch.h; for - /// more information on matching, see that code/header pair. Passing NULL for - /// one of these fields will match all values for that field. The return value - /// for the method will be the number of interfaces which match the query. - /// - /// @param list The list that this method will append search results on to. It is possible to pass NULL here and just receive the return value. - /// @param type An expression which the 'type' field on an added object must match to be included in results - /// @param name An expression which the 'name' field on an added object must match to be included in results - /// @param owner Limit results to components owned/not-owned by this SimComponent (see next param) - /// @param notOwner If set to true, this will enumerate only interfaces NOT owned by 'owner' - virtual U32 enumerate( ComponentInterfaceList *list, const char *type = NULL, const char *name = NULL, const SimComponent *owner = NULL, bool notOwner = false ) const; -}; - -#endif \ No newline at end of file diff --git a/Engine/source/component/dynamicConsoleMethodComponent.cpp b/Engine/source/component/dynamicConsoleMethodComponent.cpp deleted file mode 100644 index 75a88930c..000000000 --- a/Engine/source/component/dynamicConsoleMethodComponent.cpp +++ /dev/null @@ -1,209 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "component/dynamicConsoleMethodComponent.h" -#include "console/stringStack.h" - -extern StringStack STR; -extern ConsoleValueStack CSTK; - -IMPLEMENT_CO_NETOBJECT_V1(DynamicConsoleMethodComponent); - -ConsoleDocClass( DynamicConsoleMethodComponent, - "@brief Console object used for calling methods defined in script, from within other classes.\n\n" - "Not intended for game development, for editors or internal use only.\n\n " - "@internal"); - -//----------------------------------------------------------- -// Function name: SimComponent::handlesConsoleMethod -// Summary: -//----------------------------------------------------------- -bool DynamicConsoleMethodComponent::handlesConsoleMethod( const char *fname, S32 *routingId ) -{ - // CodeReview: Host object is now given priority over components for method - // redirection. [6/23/2007 Pat] - - // On this object? - if( isMethod( fname ) ) - { - *routingId = -1; // -1 denotes method on object -#ifdef TORQUE_DEBUG - // Inject Method. - injectMethodCall( fname ); -#endif - return true; - } - - // on this objects components? - S32 nI = 0; - VectorPtr &componentList = lockComponentList(); - for( SimComponentIterator nItr = componentList.begin(); nItr != componentList.end(); nItr++, nI++ ) - { - SimObject *pComponent = dynamic_cast(*nItr); - if( pComponent != NULL && pComponent->isMethod( fname ) ) - { - *routingId = -2; // -2 denotes method on component - unlockComponentList(); - -#ifdef TORQUE_DEBUG - // Inject Method. - injectMethodCall( fname ); -#endif - return true; - } - } - unlockComponentList(); - - return false; -} - -const char *DynamicConsoleMethodComponent::callMethod( S32 argc, const char* methodName, ... ) -{ - const char *argv[128]; - methodName = StringTable->insert( methodName ); - - argc++; - - va_list args; - va_start(args, methodName); - for(S32 i = 0; i < argc; i++) - argv[i+2] = va_arg(args, const char *); - va_end(args); - - // FIXME: the following seems a little excessive. I wonder why it's needed? - argv[0] = methodName; - argv[1] = methodName; - argv[2] = methodName; - - StringStackConsoleWrapper argsw(argc, argv); - - return callMethodArgList( argsw.count() , argsw ); -} - -#ifdef TORQUE_DEBUG -/// Inject Method Call. -void DynamicConsoleMethodComponent::injectMethodCall( const char* method ) -{ - // Get Call Method. - StringTableEntry callMethod = StringTable->insert( method ); - - // Find Call Method Metric. - callMethodMetricType::Iterator itr = mCallMethodMetrics.find( callMethod ); - - // Did we find the method? - if ( itr == mCallMethodMetrics.end() ) - { - // No, so set the call count to initially be 1. - itr = mCallMethodMetrics.insert( callMethod, 1 ); - } - else - { - // Increment Call Count. - itr->value++; - } -} -#endif - -const char* DynamicConsoleMethodComponent::callMethodArgList( U32 argc, ConsoleValueRef argv[], bool callThis /* = true */ ) -{ -#ifdef TORQUE_DEBUG - injectMethodCall( argv[0] ); -#endif - - return _callMethod( argc, argv, callThis ); -} - -// Call all components that implement methodName giving them a chance to operate -// Components are called in reverse order of addition -const char *DynamicConsoleMethodComponent::_callMethod( U32 argc, ConsoleValueRef argv[], bool callThis /* = true */ ) -{ - // Set Owner - SimObject *pThis = dynamic_cast( this ); - AssertFatal( pThis, "DynamicConsoleMethodComponent::callMethod : this should always exist!" ); - - const char *cbName = StringTable->insert(argv[0]); - - if( getComponentCount() > 0 ) - { - lockComponentList(); - for( S32 i = getComponentCount() - 1; i >= 0; i-- ) - //for( SimComponentIterator nItr = componentList.end(); nItr != componentList.begin(); nItr-- ) - { - argv[0] = cbName; - - SimComponent *pComponent = dynamic_cast( getComponent( i ) ); - AssertFatal( pComponent, "DynamicConsoleMethodComponent::callMethod - NULL component in list!" ); - - DynamicConsoleMethodComponent *pThisComponent = dynamic_cast( pComponent ); - AssertFatal( pThisComponent, "DynamicConsoleMethodComponent::callMethod - Non DynamicConsoleMethodComponent component attempting to callback!"); - - // Prevent stack corruption - STR.pushFrame(); - CSTK.pushFrame(); - // -- - - // Only call on first depth components - // Should isMethod check these calls? [11/22/2006 justind] - if(pComponent->isEnabled()) - Con::execute( pThisComponent, argc, argv ); - - // Prevent stack corruption - STR.popFrame(); - CSTK.popFrame(); - // -- - - // Bail if this was the first element - //if( nItr == componentList.begin() ) - // break; - } - unlockComponentList(); - } - - // Prevent stack corruption - STR.pushFrame(); - CSTK.pushFrame(); - // -- - - // Set Owner Field - const char* result = ""; - if(callThis) - result = Con::execute( pThis, argc, argv, true ); // true - exec method onThisOnly, not on DCMCs - - // Prevent stack corruption - STR.popFrame(); - CSTK.popFrame(); - // -- - return result; -} - -ConsoleMethod( DynamicConsoleMethodComponent, callMethod, void, 3, 64 , "(methodName, argi) Calls script defined method\n" - "@param methodName The method's name as a string\n" - "@param argi Any arguments to pass to the method\n" - "@return No return value" - "@note %obj.callMethod( %methodName, %arg1, %arg2, ... );\n") - -{ - object->callMethodArgList( argc - 1, argv + 2 ); -} - -////////////////////////////////////////////////////////////////////////// - diff --git a/Engine/source/component/dynamicConsoleMethodComponent.h b/Engine/source/component/dynamicConsoleMethodComponent.h deleted file mode 100644 index 32e594cd6..000000000 --- a/Engine/source/component/dynamicConsoleMethodComponent.h +++ /dev/null @@ -1,89 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _DYNAMIC_CONSOLEMETHOD_COMPONENT_H_ -#define _DYNAMIC_CONSOLEMETHOD_COMPONENT_H_ - -#ifndef _SIMCOMPONENT_H_ -#include "component/simComponent.h" -#endif - -#ifndef _CONSOLEINTERNAL_H_ -#include "console/consoleInternal.h" -#endif - -#ifndef _ICALLMETHOD_H_ -#include "console/ICallMethod.h" -#endif - -#ifdef TORQUE_DEBUG -#ifndef _TDICTIONARY_H_ -#include "core/util/tDictionary.h" -#endif -#endif - -//----------------------------------------------------------------------------- - -class DynamicConsoleMethodComponent : public SimComponent, public ICallMethod -{ -#ifdef TORQUE_DEBUG -public: - typedef Map callMethodMetricType; -#endif - -private: - typedef SimComponent Parent; - -#ifdef TORQUE_DEBUG - // Call Method Debug Stat. - callMethodMetricType mCallMethodMetrics; -#endif - -protected: - /// Internal callMethod : Actually does component notification and script method execution - /// @attention This method does some magic to the argc argv to make Con::execute act properly - /// as such it's internal and should not be exposed or used except by this class - virtual const char* _callMethod( U32 argc, ConsoleValueRef argv[], bool callThis = true ); - -public: - -#ifdef TORQUE_DEBUG - /// Call Method Metrics. - const callMethodMetricType& getCallMethodMetrics( void ) const { return mCallMethodMetrics; }; - - /// Inject Method Call. - void injectMethodCall( const char* method ); -#endif - - /// Call Method - virtual const char* callMethodArgList( U32 argc, ConsoleValueRef argv[], bool callThis = true ); - - /// Call Method format string - const char* callMethod( S32 argc, const char* methodName, ... ); - - // query for console method data - virtual bool handlesConsoleMethod(const char * fname, S32 * routingId); - - DECLARE_CONOBJECT(DynamicConsoleMethodComponent); -}; - -#endif \ No newline at end of file diff --git a/Engine/source/component/moreAdvancedComponent.cpp b/Engine/source/component/moreAdvancedComponent.cpp deleted file mode 100644 index 7ddfac688..000000000 --- a/Engine/source/component/moreAdvancedComponent.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "component/moreAdvancedComponent.h" - -// unitTest_runTests("Component/MoreAdvancedComponent"); - -////////////////////////////////////////////////////////////////////////// - -IMPLEMENT_CONOBJECT(MoreAdvancedComponent); - -ConsoleDocClass( MoreAdvancedComponent, - "@brief This is a slightly more advanced component which will be used to demonstrate " - "components which are dependent on other components.\n\n" - "Not intended for game development, for editors or internal use only.\n\n " - "@internal"); - -bool MoreAdvancedComponent::onComponentRegister( SimComponent *owner ) -{ - if( !Parent::onComponentRegister( owner ) ) - return false; - - // This will return the first interface of type SimpleComponent that is cached - // on the parent object. - mSCInterface = owner->getInterface(); - - // If we can't find this interface, our component can't function, so false - // will be returned, and this will signify, to the top-level component, that it - // should fail the onAdd call. - return ( mSCInterface != NULL ); -} - -bool MoreAdvancedComponent::testDependentInterface() -{ - // These two requirements must be met in order for the test to proceed, so - // lets check them. - if( mSCInterface == NULL || !mSCInterface->isValid() ) - return false; - - return mSCInterface->isFortyTwo( 42 ); -} \ No newline at end of file diff --git a/Engine/source/component/moreAdvancedComponent.h b/Engine/source/component/moreAdvancedComponent.h deleted file mode 100644 index d4891202d..000000000 --- a/Engine/source/component/moreAdvancedComponent.h +++ /dev/null @@ -1,55 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _MOREADVANCEDCOMPONENT_H_ -#define _MOREADVANCEDCOMPONENT_H_ - -#ifndef _SIMPLECOMPONENT_H_ -#include "component/simpleComponent.h" -#endif - -/// This is a slightly more advanced component which will be used to demonstrate -/// components which are dependent on other components. -class MoreAdvancedComponent : public SimComponent -{ - typedef SimComponent Parent; - -protected: - // This component is going to be dependent on a SimpleComponentInterface being - // queried off of it's parent object. This will store that interface that - // will get queried during onComponentRegister() - SimpleComponentInterface *mSCInterface; - -public: - DECLARE_CONOBJECT(MoreAdvancedComponent); - - // Firstly, take a look at the documentation for this function in simComponent.h. - // We will be overloading this method to query the component heirarchy for our - // dependent interface, as noted above. - virtual bool onComponentRegister( SimComponent *owner ); - - // This function will try to execute a function through the interface that this - // component is dependent on. - virtual bool testDependentInterface(); -}; - -#endif \ No newline at end of file diff --git a/Engine/source/component/simComponent.cpp b/Engine/source/component/simComponent.cpp deleted file mode 100644 index 49cbef22e..000000000 --- a/Engine/source/component/simComponent.cpp +++ /dev/null @@ -1,452 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "console/simObject.h" -#include "console/consoleTypes.h" -#include "component/simComponent.h" -#include "core/stream/stream.h" -#include "console/engineAPI.h" - -SimComponent::SimComponent() : mOwner( NULL ) -{ - mComponentList.clear(); - mMutex = Mutex::createMutex(); - - mEnabled = true; - mTemplate = false; -} - -SimComponent::~SimComponent() -{ - Mutex::destroyMutex( mMutex ); - mMutex = NULL; -} - -IMPLEMENT_CO_NETOBJECT_V1(SimComponent); - -ConsoleDocClass( SimComponent, - "@brief Legacy component system, soon to be deprecated.\n\n" - "Not intended for game development, for editors or internal use only.\n\n " - "@internal"); - -bool SimComponent::onAdd() -{ - if( !Parent::onAdd() ) - return false; - - // Register - _registerInterfaces( this ); - - if( !_registerComponents( this ) ) - return false; - - //Con::executef( this, 1, "onAdd" ); - - return true; -} - -void SimComponent::_registerInterfaces( SimComponent *owner ) -{ - // First call this to expose the interfaces that this component will cache - // before examining the list of subcomponents - registerInterfaces( owner ); - - // Early out to avoid mutex lock and such - if( !hasComponents() ) - return; - - VectorPtr &components = lockComponentList(); - for( SimComponentIterator i = components.begin(); i != components.end(); i++ ) - { - (*i)->mOwner = owner; - - // Tell the component itself to register it's interfaces - (*i)->registerInterfaces( owner ); - - (*i)->mOwner = NULL; // This tests to see if the object's onComponentRegister call will call up to the parent. - - // Recurse - (*i)->_registerInterfaces( owner ); - } - - unlockComponentList(); -} - -bool SimComponent::_registerComponents( SimComponent *owner ) -{ - // This method will return true if the object contains no components. See the - // documentation for SimComponent::onComponentRegister for more information - // on this behavior. - bool ret = true; - - // If this doesn't contain components, don't even lock the list. - if( hasComponents() ) - { - VectorPtr &components = lockComponentList(); - for( SimComponentIterator i = components.begin(); i != components.end(); i++ ) - { - if( !(*i)->onComponentRegister( owner ) ) - { - ret = false; - break; - } - - AssertFatal( (*i)->mOwner == owner, "Component failed to call parent onComponentRegister!" ); - - // Recurse - if( !(*i)->_registerComponents( owner ) ) - { - ret = false; - break; - } - } - - unlockComponentList(); - } - - return ret; -} - -void SimComponent::_unregisterComponents() -{ - if( !hasComponents() ) - return; - - VectorPtr &components = lockComponentList(); - for( SimComponentIterator i = components.begin(); i != components.end(); i++ ) - { - (*i)->onComponentUnRegister(); - - AssertFatal( (*i)->mOwner == NULL, "Component failed to call parent onUnRegister" ); - - // Recurse - (*i)->_unregisterComponents(); - } - - unlockComponentList(); -} - -void SimComponent::onRemove() -{ - //Con::executef(this, 1, "onRemove"); - - _unregisterComponents(); - - // Delete all components - VectorPtr&componentList = lockComponentList(); - while(componentList.size() > 0) - { - SimComponent *c = componentList[0]; - componentList.erase( componentList.begin() ); - - if( c->isProperlyAdded() ) - c->deleteObject(); - else if( !c->isRemoved() && !c->isDeleted() ) - delete c; - // else, something else is deleting this, don't mess with it - } - unlockComponentList(); - - Parent::onRemove(); -} - -////////////////////////////////////////////////////////////////////////// - -bool SimComponent::processArguments(S32 argc, ConsoleValueRef *argv) -{ - for(S32 i = 0; i < argc; i++) - { - SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); - if(obj) - addComponent(obj); - else - Con::printf("SimComponent::processArguments - Invalid Component Object \"%s\"", (const char*)argv[i]); - } - return true; -} - -////////////////////////////////////////////////////////////////////////// - -void SimComponent::initPersistFields() -{ - addGroup("Component"); - - addProtectedField( "Template", TypeBool, Offset(mTemplate, SimComponent), - &setIsTemplate, &defaultProtectedGetFn, - "Places the object in a component set for later use in new levels." ); - - endGroup("Component"); - - // Call Parent. - Parent::initPersistFields(); -} - -//------------------------------------------------------------------------------ - -bool SimComponent::getInterfaces( ComponentInterfaceList *list, const char *type /* = NULL */, const char *name /* = NULL */, - const SimComponent *owner /* = NULL */, bool notOwner /* = false */ ) -{ - AssertFatal( list != NULL, "Passing NULL for a list is not supported functionality for SimComponents." ); - return ( mInterfaceCache.enumerate( list, type, name, owner, notOwner ) > 0 ); -} - -bool SimComponent::registerCachedInterface( const char *type, const char *name, SimComponent *interfaceOwner, ComponentInterface *cinterface ) -{ - if( mInterfaceCache.add( type, name, interfaceOwner, cinterface ) ) - { - cinterface->mOwner = interfaceOwner; - - // Recurse - if( mOwner != NULL ) - return mOwner->registerCachedInterface( type, name, interfaceOwner, cinterface ); - - return true; - } - - // So this is not a good assert, because it will get triggered due to the recursive - // nature of interface caching. I want to keep it here, though, just so nobody - // else thinks, "Oh I'll add an assert here." - // - //AssertFatal( false, avar( "registerCachedInterface failed, probably because interface with type '%s', name '%s' and owner with SimObjectId '%d' already exists", - // type, name, interfaceOwner->getId() ) ); - - return false; -} - -////////////////////////////////////////////////////////////////////////// -// Component Management -////////////////////////////////////////////////////////////////////////// - -bool SimComponent::addComponentFromField( void* obj, const char* data ) -{ - SimComponent *pComponent = dynamic_cast( Sim::findObject( data ) ); - if( pComponent != NULL ) - static_cast(obj)->addComponent( pComponent ); - return false; -} - -// Add Component to this one -bool SimComponent::addComponent( SimComponent *component ) -{ - AssertFatal( dynamic_cast(component), "SimComponent - Cannot add non SimObject derived components!" ); - - MutexHandle mh; - if( mh.lock( mMutex, true ) ) - { - for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ ) - { - SimComponent *pComponent = dynamic_cast(*nItr); - AssertFatal( pComponent, "SimComponent::addComponent - NULL component in list!" ); - if( pComponent == component ) - return true; - } - - if(component->onComponentAdd(this)) - { - component->mOwner = this; - mComponentList.push_back( component ); - return true; - } - } - - return false; -} - -// Remove Component from this one -bool SimComponent::removeComponent( SimComponent *component ) -{ - MutexHandle mh; - if( mh.lock( mMutex, true ) ) - { - for( SimComponentIterator nItr = mComponentList.begin(); nItr != mComponentList.end(); nItr++ ) - { - SimComponent *pComponent = dynamic_cast(*nItr); - AssertFatal( pComponent, "SimComponent::removeComponent - NULL component in list!" ); - if( pComponent == component ) - { - AssertFatal( component->mOwner == this, "Somehow we contain a component who doesn't think we are it's owner." ); - (*nItr)->onComponentRemove(this); - component->mOwner = NULL; - mComponentList.erase( nItr ); - return true; - } - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////// - -bool SimComponent::onComponentAdd(SimComponent *target) -{ - Con::executef(this, "onComponentAdd", Con::getIntArg(target->getId())); - return true; -} - -void SimComponent::onComponentRemove(SimComponent *target) -{ - Con::executef(this, "onComponentRemove", Con::getIntArg(target->getId())); -} - -////////////////////////////////////////////////////////////////////////// - -ComponentInterface *SimComponent::getInterface(const char *type /* = NULL */, const char *name /* = NULL */, - const SimComponent *owner /* = NULL */, bool notOwner /* = false */) -{ - ComponentInterfaceList iLst; - - if( getInterfaces( &iLst, type, name, owner, notOwner ) ) - return iLst[0]; - - return NULL; -} - -////////////////////////////////////////////////////////////////////////// - -bool SimComponent::writeField(StringTableEntry fieldname, const char* value) -{ - if (!Parent::writeField(fieldname, value)) - return false; - - if( fieldname == StringTable->insert("owner") ) - return false; - - return true; -} - -void SimComponent::write(Stream &stream, U32 tabStop, U32 flags /* = 0 */) -{ - MutexHandle handle; - handle.lock(mMutex); // When this goes out of scope, it will unlock it - - // export selected only? - if((flags & SelectedOnly) && !isSelected()) - { - for(U32 i = 0; i < mComponentList.size(); i++) - mComponentList[i]->write(stream, tabStop, flags); - - return; - } - - stream.writeTabs(tabStop); - char buffer[1024]; - dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : ""); - stream.write(dStrlen(buffer), buffer); - writeFields(stream, tabStop + 1); - - if(mComponentList.size()) - { - stream.write(2, "\r\n"); - - stream.writeTabs(tabStop+1); - stream.writeLine((U8 *)"// Note: This is a list of behaviors, not arbitrary SimObjects as in a SimGroup or SimSet.\r\n"); - - for(U32 i = 0; i < mComponentList.size(); i++) - mComponentList[i]->write(stream, tabStop + 1, flags); - } - - stream.writeTabs(tabStop); - stream.write(4, "};\r\n"); -} - -////////////////////////////////////////////////////////////////////////// -// Console Methods -////////////////////////////////////////////////////////////////////////// - -ConsoleMethod( SimComponent, addComponents, bool, 3, 64, "%obj.addComponents( %compObjName, %compObjName2, ... );\n" - "Adds additional components to current list.\n" - "@param Up to 62 component names\n" - "@return Returns true on success, false otherwise.") -{ - for(S32 i = 2; i < argc; i++) - { - SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); - if(obj) - object->addComponent(obj); - else - Con::printf("SimComponent::addComponents - Invalid Component Object \"%s\"", (const char*)argv[i]); - } - return true; -} - -ConsoleMethod( SimComponent, removeComponents, bool, 3, 64, "%obj.removeComponents( %compObjName, %compObjName2, ... );\n" - "Removes components by name from current list.\n" - "@param objNamex Up to 62 component names\n" - "@return Returns true on success, false otherwise.") -{ - for(S32 i = 2; i < argc; i++) - { - SimComponent *obj = dynamic_cast (Sim::findObject(argv[i]) ); - if(obj) - object->removeComponent(obj); - else - Con::printf("SimComponent::removeComponents - Invalid Component Object \"%s\"", (const char*)argv[i]); - } - return true; -} - -DefineConsoleMethod( SimComponent, getComponentCount, S32, (), , "() Get the current component count\n" - "@return The number of components in the list as an integer") -{ - return object->getComponentCount(); -} - -DefineConsoleMethod( SimComponent, getComponent, S32, (S32 idx), , "(idx) Get the component corresponding to the given index.\n" - "@param idx An integer index value corresponding to the desired component.\n" - "@return The id of the component at the given index as an integer") -{ - if(idx < 0 || idx >= object->getComponentCount()) - { - Con::errorf("SimComponent::getComponent - Invalid index %d", idx); - return 0; - } - - SimComponent *c = object->getComponent(idx); - return c ? c->getId() : 0; -} - -DefineConsoleMethod(SimComponent, setEnabled, void, (bool enabled), , "(enabled) Sets or unsets the enabled flag\n" - "@param enabled Boolean value\n" - "@return No return value") -{ - object->setEnabled(enabled); -} - -DefineConsoleMethod(SimComponent, isEnabled, bool, (), , "() Check whether SimComponent is currently enabled\n" - "@return true if enabled and false if not") -{ - return object->isEnabled(); -} - -DefineConsoleMethod(SimComponent, setIsTemplate, void, (bool templateFlag), , "(template) Sets or unsets the template flag\n" - "@param template Boolean value\n" - "@return No return value") -{ - object->setIsTemplate(templateFlag); -} - -DefineConsoleMethod(SimComponent, getIsTemplate, bool, (), , "() Check whether SimComponent is currently a template\n" - "@return true if is a template and false if not") -{ - return object->getIsTemplate(); -} diff --git a/Engine/source/component/simComponent.h b/Engine/source/component/simComponent.h deleted file mode 100644 index 70e41f69e..000000000 --- a/Engine/source/component/simComponent.h +++ /dev/null @@ -1,256 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _SIMCOMPONENT_H_ -#define _SIMCOMPONENT_H_ - -#ifndef _TVECTOR_H_ -#include "core/util/tVector.h" -#endif -#ifndef _STRINGTABLE_H_ -#include "core/stringTable.h" -#endif -#ifndef _NETOBJECT_H_ -#include "sim/netObject.h" -#endif -#ifndef _COMPONENTINTERFACE_H_ -#include "component/componentInterface.h" -#endif -#ifndef _PLATFORM_THREADS_MUTEX_H_ -#include "platform/threads/mutex.h" -#endif -#ifndef _STRINGFUNCTIONS_H_ -#include "core/strings/stringFunctions.h" -#endif - -// Forward refs -class Stream; -class ComponentInterface; -class ComponentInterfaceCache; - -class SimComponent : public NetObject -{ - typedef NetObject Parent; - -private: - VectorPtr mComponentList; ///< The Component List - void *mMutex; ///< Component List Mutex - - SimObjectPtr mOwner; ///< The component which owns this one. - - /// This is called internally to instruct the component to iterate over it's - // list of components and recursively call _registerInterfaces on their lists - // of components. - void _registerInterfaces( SimComponent *owner ); - - bool _registerComponents( SimComponent *owner ); - void _unregisterComponents(); - -protected: - ComponentInterfaceCache mInterfaceCache; ///< Stores the interfaces exposed by this component. - - bool mEnabled; - - bool mTemplate; - - // Non-const getOwner for derived classes - SimComponent *_getOwner() { return mOwner; } - - /// Returns a const reference to private mComponentList - typedef VectorPtr::iterator SimComponentIterator; - VectorPtr &lockComponentList() - { - Mutex::lockMutex( mMutex ); - return mComponentList; - }; - - void unlockComponentList() - { - Mutex::unlockMutex( mMutex ); - } - - /// onComponentRegister is called on each component by it's owner. If a component - /// has no owner, onComponentRegister will not be called on it. The purpose - /// of onComponentRegister is to allow a component to check for any external - /// interfaces, or other dependencies which it needs to function. If any component - /// in a component hierarchy returns false from it's onComponentRegister call - /// the entire hierarchy is invalid, and SimObject::onAdd will fail on the - /// top-level component. To put it another way, if a component contains other - /// components, it will be registered successfully with Sim iff each subcomponent - /// returns true from onComponentRegister. If a component does not contain - /// other components, it will not receive an onComponentRegister call. - /// - /// Overloads of this method must pass the call along to their parent, as is - /// shown in the example below. - /// - /// @code - /// bool FooComponent::onComponentRegister( SimComponent *owner ) - /// { - /// if( !Parent::onComponentRegister( owner ) ) - /// return false; - /// ... - /// } - /// @endcode - virtual bool onComponentRegister( SimComponent *owner ) - { - mOwner = owner; - return true; - } - - /// onUnregister is called when the owner is unregistering. Your object should - /// do cleanup here, as well as pass a call up the chain to the parent. - virtual void onComponentUnRegister() - { - mOwner = NULL; - } - - /// registerInterfaces is called on each component as it's owner is registering - /// it's interfaces. This is called before onComponentRegister, and should be used to - /// register all interfaces exposed by your component, as well as all callbacks - /// needed by your component. - virtual void registerInterfaces( SimComponent *owner ) - { - - } - -public: - DECLARE_CONOBJECT(SimComponent); - - /// Constructor - /// Add this component - SimComponent(); - - /// Destructor - /// Remove this component and destroy child references - virtual ~SimComponent(); - -public: - - virtual bool onAdd(); - virtual void onRemove(); - - static void initPersistFields(); - - virtual bool processArguments(S32 argc, ConsoleValueRef *argv); - - bool isEnabled() const { return mEnabled; } - - void setEnabled( bool value ) { mEnabled = value; } - - /// Will return true if this object contains components. - bool hasComponents() const { return ( mComponentList.size() > 0 ); }; - - /// The component which owns this object - const SimComponent *getOwner() const { return mOwner; }; - - // Component Information - inline virtual StringTableEntry getComponentName() { return StringTable->insert( getClassName() ); }; - - /// Protected 'Component' Field setter that will add a component to the list. - static bool addComponentFromField(void* obj, const char* data); - - /// Add Component to this one - virtual bool addComponent( SimComponent *component ); - - /// Remove Component from this one - virtual bool removeComponent( SimComponent *component ); - - /// Clear Child components of this one - virtual bool clearComponents() { mComponentList.clear(); return true; }; - - virtual bool onComponentAdd(SimComponent *target); - virtual void onComponentRemove(SimComponent *target); - - S32 getComponentCount() { return mComponentList.size(); } - SimComponent *getComponent(S32 idx) { return mComponentList[idx]; } - - SimComponentIterator find(SimComponentIterator first, SimComponentIterator last, SimComponent *value) - { - return ::find(first, last, value); - } - - static bool setIsTemplate( void *object, const char *index, const char *data ) - { static_cast(object)->setIsTemplate( dAtob( data ) ); return false; }; - virtual void setIsTemplate( const bool pTemplate ) { mTemplate = pTemplate; } - bool getIsTemplate() const { return mTemplate; } - - virtual void write(Stream &stream, U32 tabStop, U32 flags = 0); - virtual bool writeField(StringTableEntry fieldname, const char* value); - - - /// getInterfaces allows the caller to enumerate the interfaces exposed by - /// this component. This method can be overwritten to expose interfaces - /// which are not cached on the object, before passing the call to the Parent. - /// This can be used delay interface creation until it is queried for, instead - /// of creating it on initialization, and caching it. Returns false if no results - /// were found - /// - /// @param list The list that this method will append search results on to. - /// @param type An expression which the 'type' field on an added object must match to be included in results - /// @param name An expression which the 'name' field on an added object must match to be included in results - /// @param owner Limit results to components owned/not-owned by this SimComponent (see next param) - /// @param notOwner If set to true, this will enumerate only interfaces NOT owned by 'owner' - virtual bool getInterfaces( ComponentInterfaceList *list, const char *type = NULL, const char *name = NULL, const SimComponent *owner = NULL, bool notOwner = false ); // const omission intentional - - - /// These two methods allow for easy query of component interfaces if you know - /// exactly what you are looking for, and don't mind being passed back the first - /// matching result. - ComponentInterface *getInterface( const char *type = NULL, const char *name = NULL, const SimComponent *owner = NULL, bool notOwner = false ); - - template - T *getInterface( const char *type = NULL, const char *name = NULL, const SimComponent *owner = NULL, bool notOwner = false ); - - /// Add an interface to the cache. This function will return true if the interface - /// is added successfully. An interface will not be added successfully if an entry - /// in this components cache with the same values for 'type' and 'name' is present. - /// - /// @param type Type of the interface being added. If NULL is passed, it will match any type string queried. - /// @param name Name of interface being added. If NULL is passed, it will match any name string queried. - /// @param interfaceOwner The component which owns the interface being cached - /// @param cinterface The ComponentInterface being cached - bool registerCachedInterface( const char *type, const char *name, SimComponent *interfaceOwner, ComponentInterface *cinterface ); -}; - -////////////////////////////////////////////////////////////////////////// - -template -T *SimComponent::getInterface( const char *type /* = NULL */, const char *name /* = NULL */, - const SimComponent *owner /* = NULL */, bool notOwner /* = false */ ) -{ - ComponentInterfaceList iLst; - - if( getInterfaces( &iLst, type, name, owner, notOwner ) ) - { - ComponentInterfaceListIterator itr = iLst.begin(); - - while( dynamic_cast( *itr ) == NULL ) - itr++; - - if( itr != iLst.end() ) - return static_cast( *itr ); - } - - return NULL; -} - -#endif // _SIMCOMPONENT_H_ diff --git a/Engine/source/component/simpleComponent.cpp b/Engine/source/component/simpleComponent.cpp deleted file mode 100644 index 246672c28..000000000 --- a/Engine/source/component/simpleComponent.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "component/simpleComponent.h" - -IMPLEMENT_CONOBJECT(SimpleComponent); - -ConsoleDocClass( SimpleComponent, - "@brief The purpose of this component is to provide a minimalistic component that " - "exposes a simple, cached interface\n\n" - "Soon to be deprecated, internal only.\n\n " - "@internal"); \ No newline at end of file diff --git a/Engine/source/component/simpleComponent.h b/Engine/source/component/simpleComponent.h deleted file mode 100644 index e4c32bfb3..000000000 --- a/Engine/source/component/simpleComponent.h +++ /dev/null @@ -1,159 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _SIMPLECOMPONENT_H_ -#define _SIMPLECOMPONENT_H_ - -#ifndef _SIMCOMPONENT_H_ -#include "component/simComponent.h" -#endif - -#ifndef _COMPONENTINTERFACE_H_ -#include "component/componentInterface.h" -#endif - -/// This is a very simple interface. Interfaces provide ways for components to -/// interact with each-other, and query each-other for functionality. It makes it -/// possible for two components to be interdependent on one another, as well. An -/// interface should make accessor calls to it's owner for functionality, and -/// generally be as thin of a layer as possible. -class SimpleComponentInterface : public ComponentInterface -{ -public: - bool isFortyTwo( const U32 test ); -}; - -////////////////////////////////////////////////////////////////////////// -/// The purpose of this component is to provide a minimalistic component that -/// exposes a simple, cached interface -class SimpleComponent : public SimComponent -{ - typedef SimComponent Parent; - -protected: - SimpleComponentInterface mSCInterface; - -public: - // Components are still SimObjects, and need to be declared and implemented - // with the standard macros - DECLARE_CONOBJECT(SimpleComponent); - - ////////////////////////////////////////////////////////////////////////// - // SimComponent overloads. - - // This method is called on each component as it's parent is getting onAdd - // called. The purpose of overloading this method is to expose cached interfaces - // before onComponentRegister is called, so that other components can depend on the - // interfaces you expose in order to register properly. This functionality - // will be demonstrated in a more advanced example. - virtual void registerInterfaces( SimComponent *owner ) - { - // While it is not imperative that we pass this call to the Parent in this - // example, if there existed a class-heirarchy of components, it would be - // critical, so for good practice, call up to the Parent. - Parent::registerInterfaces( owner ); - - // Now we should go ahead and register our cached interface. What we are doing - // is telling the component which contains this component (if it exists) - // all of the interfaces that we expose. When this call is made, it will - // recurse up the owner list. - // - // For example, there exists components A, B, and C. - // A owns B, and B owns C. - // - // If C exposes a cached interface, it will expose it via registerCachedInterface - // when registerInterfaces is recursively called. It will add it's interface to - // it's cache list, and then pass the register call up to it's parent. The parent - // will also cache the interface, and continue to pass the cache call up the - // child->parent chain until there exists no parent. - // - // The result is that, if C exposes an interface 'foo', and A owns B, and - // B owns C, an interface request for 'foo' given to component A will result - // in 'foo' being returned, even though A does not expose 'foo'. This makes - // it possible for a component to query it's owner for an interface, and - // not care where that interface is exposed. It also allows for game code - // to work with any SimComponent and query that component for any interface - // it wants without knowing or caring exactly where it is coming from. - // - // registerCachedInterface returns a boolean value if it was successful. - // Success results in the caching of this interface throughout the full - // child->parent chain. An interface will be added to a cache list - // successfully iff there exists no entry in that list that has matching - // values for 'type', 'name' and 'owner'. - owner->registerCachedInterface( - // The first parameter is the 'type' of the interface, this is not to be - // confused with any kind of existing console, or c++ type. It is simply - // a string which is can be set to any value - "example", - - // The next parameter is the 'name' of the interface. This is also a string - // which can be set to any value - "isfortytwo", - - // The owner of the interface. Note that the value being assigned here - // is this instance of SimpleComponent, and not the 'owner' argument - // of the function registerInterfaces that we are calling from. - this, - - // And finally the interface; a pointer to an object with type ComponentInterface - &mSCInterface ); - } - - ////////////////////////////////////////////////////////////////////////// - // Specific functionality - - /// This is the test method, it will return true if the number provided - /// is forty two - bool isFortyTwo( const U32 test ) const - { - return ( test == 42 ); - } -}; - -////////////////////////////////////////////////////////////////////////// -// Interface implementation -// -// Since interfaces themselves implement very little functionality, it is a good -// idea to inline them if at all possible. Interdependent components will be using -// these interfaces constantly, and so putting as thin of a layer between the -// functionality they expose, and the functionality the component implements is -// a good design practice. -inline bool SimpleComponentInterface::isFortyTwo( const U32 test ) -{ - // This code block will test for a valid owner in a debug build before - // performing operations on it's owner. It is worth noting that the - // ComponentInterface::isValid() method can be overridden to include - // validation specific to your interface and/or component. - AssertFatal( isValid(), "SimpleComponentInterface has not been registered properly by the component which exposes it." ); - - // This is a sanity check. The owner of this interface should have the type - // SimpleComponent, otherwise this won't work. (See further interface examples - // for some ways around this) - AssertFatal( dynamic_cast( getOwner() ) != NULL, "Owner of SimpleComponentInterface is not a SimpleComponent" ); - - // Component interfaces rely on being registered to set their mOwner - // field. This field is initialized to NULL, and then gets set by - // SimComponent when the interface is registered. - return static_cast( getOwner() )->isFortyTwo( test ); -} - -#endif \ No newline at end of file diff --git a/Engine/source/component/test/moreAdvancedComponentTest.cpp b/Engine/source/component/test/moreAdvancedComponentTest.cpp deleted file mode 100644 index a6a7335f4..000000000 --- a/Engine/source/component/test/moreAdvancedComponentTest.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2014 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. -//----------------------------------------------------------------------------- - -#ifdef TORQUE_TESTS_ENABLED -#include "testing/unitTesting.h" -#include "component/moreAdvancedComponent.h" - -TEST(MoreAdvancedComponent, MoreAdvancedComponent) -{ - // Create component instances and compose them. - SimComponent *parentComponent = new SimComponent(); - SimpleComponent *simpleComponent = new SimpleComponent(); - MoreAdvancedComponent *moreAdvComponent = new MoreAdvancedComponent(); - // CodeReview note that the interface pointer isn't initialized in a ctor - // on the components, so it's bad memory against which you might - // be checking in testDependentInterface [3/3/2007 justind] - parentComponent->addComponent( simpleComponent ); - parentComponent->addComponent( moreAdvComponent ); - - simpleComponent->registerObject(); - moreAdvComponent->registerObject(); - - // Put a break-point here, follow the onAdd call, and observe the order in - // which the SimComponent::onAdd function executes. You will see the interfaces - // get cached, and the dependent interface query being made. - parentComponent->registerObject(); - - // If the MoreAdvancedComponent found an interface, than the parentComponent - // should have returned true, from onAdd, and should therefore be registered - // properly with the Sim - EXPECT_TRUE( parentComponent->isProperlyAdded() ) - << "Parent component not properly added!"; - - // Now lets test the interface. You can step through this, as well. - EXPECT_TRUE( moreAdvComponent->testDependentInterface() ) - << "Dependent interface test failed."; - - // CodeReview is there a reason we can't just delete the parentComponent here? [3/3/2007 justind] - // - // Clean up - parentComponent->removeComponent( simpleComponent ); - parentComponent->removeComponent( moreAdvComponent ); - - parentComponent->deleteObject(); - moreAdvComponent->deleteObject(); - simpleComponent->deleteObject(); -}; - -#endif \ No newline at end of file diff --git a/Engine/source/component/test/simComponentTest.cpp b/Engine/source/component/test/simComponentTest.cpp deleted file mode 100644 index 407e3adce..000000000 --- a/Engine/source/component/test/simComponentTest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2014 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. -//----------------------------------------------------------------------------- - -#ifdef TORQUE_TESTS_ENABLED -#include "testing/unitTesting.h" -#include "component/simComponent.h" - -class CachedInterfaceExampleComponent : public SimComponent -{ - typedef SimComponent Parent; - - ComponentProperty mMyId; - static U32 smNumInstances; - ComponentProperty *mpU32; // CodeReview [patw, 2, 17, 2007] Make ref objects when this is in Jugg - -public: - DECLARE_CONOBJECT( CachedInterfaceExampleComponent ); - - CachedInterfaceExampleComponent() : mpU32( NULL ) - { - mMyId = ( ( 1 << 24 ) | smNumInstances++ ); - } - virtual ~CachedInterfaceExampleComponent() - { - smNumInstances--; - } - -public: - ////////////////////////////////////////////////////////////////////////// - - virtual void registerInterfaces( SimComponent *owner ) - { - // Register a cached interface for this - owner->registerCachedInterface( NULL, "aU32", this, &mMyId ); - } - - ////////////////////////////////////////////////////////////////////////// - - bool onComponentRegister( SimComponent *owner ) - { - // Call up to the parent first - if( !Parent::onComponentRegister( owner ) ) - return false; - - // We want to get an interface from another object in our containing component - // to simulate component interdependency. - ComponentInterfaceList list; - - // Enumerate the interfaces on the owner, only ignore interfaces that this object owns - if( !owner->getInterfaces( &list, NULL, "aU32", this, true ) ) - return false; - - // Sanity check before just assigning all willy-nilly - for( ComponentInterfaceListIterator i = list.begin(); i != list.end(); i++ ) - { - mpU32 = dynamic_cast *>( (*i) ); - - if( mpU32 != NULL ) - return true; - } - - return false; - } - - ////////////////////////////////////////////////////////////////////////// - - // CodeReview [patw, 2, 17, 2007] I'm going to make another lightweight interface - // for this functionality later - void unit_test() - { - EXPECT_TRUE( mpU32 != NULL ) - << "Pointer to dependent interface is NULL"; - if( mpU32 ) - { - EXPECT_TRUE( *(*mpU32) & ( 1 << 24 ) ) - << "Pointer to interface data is bogus."; - EXPECT_TRUE( *(*mpU32) != *mMyId ) - << "Two of me have the same ID, bad!"; - } - } -}; - -IMPLEMENT_CONOBJECT( CachedInterfaceExampleComponent ); -U32 CachedInterfaceExampleComponent::smNumInstances = 0; - -ConsoleDocClass( CachedInterfaceExampleComponent, - "@brief Legacy from older component system.\n\n" - "Not intended for game development, for editors or internal use only.\n\n " - "@internal"); - -TEST(SimComponent, Composition) -{ - SimComponent *testComponent = new SimComponent(); - CachedInterfaceExampleComponent *componentA = new CachedInterfaceExampleComponent(); - CachedInterfaceExampleComponent *componentB = new CachedInterfaceExampleComponent(); - - // Register sub-components - EXPECT_TRUE( componentA->registerObject() ) - << "Failed to register componentA"; - EXPECT_TRUE( componentB->registerObject() ) - << "Failed to register componentB"; - - // Add the components - EXPECT_TRUE( testComponent->addComponent( componentA ) ) - << "Failed to add component a to testComponent"; - EXPECT_TRUE( testComponent->addComponent( componentB ) ) - << "Failed to add component b to testComponent"; - - EXPECT_EQ( componentA->getOwner(), testComponent ) - << "testComponent did not properly set the mOwner field of componentA to NULL."; - EXPECT_EQ( componentB->getOwner(), testComponent ) - << "testComponent did not properly set the mOwner field of componentB to NULL."; - - // Register the object with the simulation, kicking off the interface registration - ASSERT_TRUE( testComponent->registerObject() ) - << "Failed to register testComponent"; - - { - SCOPED_TRACE("componentA"); - componentA->unit_test(); - } - { - SCOPED_TRACE("componentB"); - componentB->unit_test(); - } - - testComponent->deleteObject(); -}; - -#endif \ No newline at end of file diff --git a/Engine/source/component/test/simpleComponentTest.cpp b/Engine/source/component/test/simpleComponentTest.cpp deleted file mode 100644 index a528e918f..000000000 --- a/Engine/source/component/test/simpleComponentTest.cpp +++ /dev/null @@ -1,131 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2014 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. -//----------------------------------------------------------------------------- - -#ifdef TORQUE_TESTS_ENABLED -#include "testing/unitTesting.h" -#include "component/simpleComponent.h" - -TEST(SimpleComponent, SimpleComponent) -{ - // When instantiating, and working with a SimObject in C++ code, such as - // a unit test, you *may not* allocate a SimObject off of the stack. - // - // For example: - // SimpleComponent sc; - // is a stack allocation. This memory is allocated off of the program stack - // when the function is called. SimObject deletion is done via SimObject::deleteObject() - // and the last command of this method is 'delete this;' That command will - // cause an assert if it is called on stack-allocated memory. Therefor, when - // instantiating SimObjects in C++ code, it is imperitive that you keep in - // mind that if any script calls 'delete()' on that SimObject, or any other - // C++ code calls 'deleteObject()' on that SimObject, it will crash. - SimpleComponent *sc = new SimpleComponent(); - - // SimObject::registerObject must be called on a SimObject before it is - // fully 'hooked in' to the engine. - // - // Tracing execution of this function will let you see onAdd get called on - // the component, and you will see it cache the interface we exposed. - sc->registerObject(); - - // It is *not* required that a component always be owned by a component (obviously) - // however I am using an owner so that you can trace execution of recursive - // calls to cache interfaces and such. - SimComponent *testOwner = new SimComponent(); - - // Add the test component to it's owner. This will set the 'mOwner' field - // of 'sc' to the address of 'testOwner' - testOwner->addComponent( sc ); - - // If you step-into this registerObject the same way as the previous one, - // you will be able to see the recursive caching of the exposed interface. - testOwner->registerObject(); - - // Now to prove that object composition is working properly, lets ask - // both of these components for their interface lists... - - // The ComponentInterfaceList is a typedef for type 'VectorPtr' - // and it will be used by getInterfaces() to store the results of the interface - // query. This is the "complete" way to obtain an interface, and it is too - // heavy-weight for most cases. A simplified query will be performed next, - // to demonstrate the usage of both. - ComponentInterfaceList iLst; - - // This query requests all interfaces, on all components, regardless of name - // or owner. - sc->getInterfaces( &iLst, - // This is the type field. I am passing NULL here to signify that the query - // should match all values of 'type' in the list. - NULL, - - // The name field, let's pass NULL again just so when you trace execution - // you can see how queries work in the simple case, first. - NULL ); - - // Lets process the list that we've gotten back, and find the interface that - // we want. - SimpleComponentInterface *scQueriedInterface = NULL; - - for( ComponentInterfaceListIterator i = iLst.begin(); i != iLst.end(); i++ ) - { - scQueriedInterface = dynamic_cast( *i ); - - if( scQueriedInterface != NULL ) - break; - } - - AssertFatal( scQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); - - // Lets do it again, only we will execute the query on the parent instead, - // in a simplified way. Remember the parent component doesn't expose any - // interfaces at all, so the success of this behavior is entirely dependent - // on the recursive registration that occurs in registerInterfaces() - SimpleComponentInterface *ownerQueriedInterface = testOwner->getInterface(); - - AssertFatal( ownerQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); - - // We should now have two pointers to the same interface obtained by querying - // different components. - EXPECT_EQ( ownerQueriedInterface, scQueriedInterface ) - << "This really shouldn't be possible to fail given the setup of the test"; - - // Lets call the method that was exposed on the component via the interface. - // Trace the execution of this function, if you wish. - EXPECT_TRUE( ownerQueriedInterface->isFortyTwo( 42 ) ) - << "Don't panic, but it's a bad day in the component system."; - EXPECT_TRUE( scQueriedInterface->isFortyTwo( 42 ) ) - << "Don't panic, but it's a bad day in the component system."; - - // So there you have it. Writing a simple component that exposes a cached - // interface, and testing it. It's time to clean up. - testOwner->removeComponent( sc ); - - sc->deleteObject(); - testOwner->deleteObject(); - - // Interfaces do not need to be freed. In Juggernaught, these will be ref-counted - // for more robust behavior. Right now, however, the values of our two interface - // pointers, scQueriedInterface and ownerQueriedInterface, reference invalid - // memory. -}; - -#endif \ No newline at end of file diff --git a/Engine/source/gui/core/guiCanvas.h b/Engine/source/gui/core/guiCanvas.h index 0a2e44fa5..fa213f56a 100644 --- a/Engine/source/gui/core/guiCanvas.h +++ b/Engine/source/gui/core/guiCanvas.h @@ -37,7 +37,7 @@ #include "core/util/tSignal.h" #endif -#include "component/interfaces/IProcessInput.h" +#include "platform/input/IProcessInput.h" #include "windowManager/platformWindowMgr.h" #include "gfx/gfxFence.h" diff --git a/Engine/source/component/interfaces/IProcessInput.h b/Engine/source/platform/input/IProcessInput.h similarity index 100% rename from Engine/source/component/interfaces/IProcessInput.h rename to Engine/source/platform/input/IProcessInput.h diff --git a/Engine/source/windowManager/windowInputGenerator.cpp b/Engine/source/windowManager/windowInputGenerator.cpp index 608aadb8a..193d0248a 100644 --- a/Engine/source/windowManager/windowInputGenerator.cpp +++ b/Engine/source/windowManager/windowInputGenerator.cpp @@ -23,7 +23,7 @@ #include "windowManager/windowInputGenerator.h" #include "windowManager/platformWindow.h" #include "sim/actionMap.h" -#include "component/interfaces/IProcessInput.h" +#include "platform/input/IProcessInput.h" extern InputModifiers convertModifierBits(const U32 in); From 1b47bdd972fe83b529dc3d475b1ade7b7266eea1 Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 12 May 2016 23:49:06 -0500 Subject: [PATCH 25/71] Git apparently forgot to commit ALL the changes. --- Engine/source/math/mMath.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Engine/source/math/mMath.h b/Engine/source/math/mMath.h index a1e070db7..4710f6bf0 100644 --- a/Engine/source/math/mMath.h +++ b/Engine/source/math/mMath.h @@ -48,5 +48,8 @@ #ifndef _MEASE_H_ #include "math/mEase.h" #endif +#ifndef MROTATION_H +#include "math/mRotation.h" +#endif #endif //_MMATH_H_ From 49a735e0515c77a2957cc0fec9ad7f4a18175c86 Mon Sep 17 00:00:00 2001 From: James Urquhart Date: Fri, 13 May 2016 12:09:40 +0100 Subject: [PATCH 26/71] Fix axis check in Box3F::extend method --- Engine/source/math/mBox.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/math/mBox.h b/Engine/source/math/mBox.h index 379d5291a..b81775bb0 100644 --- a/Engine/source/math/mBox.h +++ b/Engine/source/math/mBox.h @@ -415,7 +415,7 @@ inline void Box3F::extend(const Point3F & p) #define EXTEND_AXIS(AXIS) \ if (p.AXIS < minExtents.AXIS) \ minExtents.AXIS = p.AXIS; \ -else if (p.AXIS > maxExtents.AXIS) \ +if (p.AXIS > maxExtents.AXIS) \ maxExtents.AXIS = p.AXIS; EXTEND_AXIS(x) From 1299b527f1a405f78a79fd8ee045087fcc906d16 Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 13 May 2016 23:14:55 -0500 Subject: [PATCH 27/71] Adds the ability to the ShapeAsset to get the resource of the shape. --- Engine/source/T3D/assets/ShapeAsset.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 7c87cf8de..dac95a45e 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -76,6 +76,8 @@ public: TSShape* getShape() { return mShape; } + Resource getShapeResource() { return mShape; } + protected: virtual void onAssetRefresh(void) {} }; From b64123a452d50ba53b9a8db476fed119ffe414d6 Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 13 May 2016 23:57:48 -0500 Subject: [PATCH 28/71] Adds findContact to regular physics bodies so that they can find contacting objects and surfaces in a way similar to players. --- Engine/source/T3D/physics/bullet/btBody.cpp | 64 ++++++++++++++++++++ Engine/source/T3D/physics/bullet/btBody.h | 2 + Engine/source/T3D/physics/physicsBody.h | 4 ++ Engine/source/T3D/physics/physx3/px3Body.cpp | 52 ++++++++++++++++ Engine/source/T3D/physics/physx3/px3Body.h | 3 + 5 files changed, 125 insertions(+) diff --git a/Engine/source/T3D/physics/bullet/btBody.cpp b/Engine/source/T3D/physics/bullet/btBody.cpp index 77c3b8115..eb722fd17 100644 --- a/Engine/source/T3D/physics/bullet/btBody.cpp +++ b/Engine/source/T3D/physics/bullet/btBody.cpp @@ -378,3 +378,67 @@ void BtBody::setSimulationEnabled( bool enabled ) mIsEnabled = enabled; } + +void BtBody::findContact(SceneObject **contactObject, + VectorF *contactNormal, + Vector *outOverlapObjects) const +{ + AssertFatal(mActor, "BtPlayer::findContact - The controller is null!"); + + VectorF normal; + F32 maxDot = -1.0f; + + // Go thru the contact points... get the first contact. + //mWorld->getDynamicsWorld()->computeOverlappingPairs(); + btOverlappingPairCache *pairCache = mWorld->getDynamicsWorld()->getBroadphase()->getOverlappingPairCache(); + + btBroadphasePairArray& pairArray = pairCache->getOverlappingPairArray(); + U32 numPairs = pairArray.size(); + btManifoldArray manifoldArray; + + for (U32 i = 0; i < numPairs; i++) + { + const btBroadphasePair &pair = pairArray[i]; + + btBroadphasePair *collisionPair = pairCache->findPair(pair.m_pProxy0, pair.m_pProxy1); + if (!collisionPair || !collisionPair->m_algorithm) + continue; + + btCollisionObject *other = (btCollisionObject*)pair.m_pProxy0->m_clientObject; + if (other == mActor) + other = (btCollisionObject*)pair.m_pProxy1->m_clientObject; + + // AssertFatal(!outOverlapObjects->contains(PhysicsUserData::getObject(other->getUserPointer())), + // "Got multiple pairs of the same object!"); + outOverlapObjects->push_back(PhysicsUserData::getObject(other->getUserPointer())); + + if (other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE) + continue; + + manifoldArray.clear(); + collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); + + for (U32 j = 0; j < manifoldArray.size(); j++) + { + btPersistentManifold *manifold = manifoldArray[j]; + btScalar directionSign = manifold->getBody0() == mActor ? 1.0f : -1.0f; + + for (U32 p = 0; p < manifold->getNumContacts(); p++) + { + const btManifoldPoint &pt = manifold->getContactPoint(p); + + // Test the normal... is it the most vertical one we got? + normal = btCast(pt.m_normalWorldOnB * directionSign); + F32 dot = mDot(normal, VectorF(0, 0, 1)); + if (dot > maxDot) + { + maxDot = dot; + + btCollisionObject *colObject = (btCollisionObject*)collisionPair->m_pProxy0->m_clientObject; + *contactObject = PhysicsUserData::getObject(colObject->getUserPointer()); + *contactNormal = normal; + } + } + } + } +} diff --git a/Engine/source/T3D/physics/bullet/btBody.h b/Engine/source/T3D/physics/bullet/btBody.h index 0f1ab669c..2de1215d2 100644 --- a/Engine/source/T3D/physics/bullet/btBody.h +++ b/Engine/source/T3D/physics/bullet/btBody.h @@ -111,6 +111,8 @@ public: F32 staticFriction ); virtual void applyCorrection( const MatrixF &xfm ); virtual void applyImpulse( const Point3F &origin, const Point3F &force ); + + virtual void findContact(SceneObject **contactObject, VectorF *contactNormal, Vector *outOverlapObjects) const; }; #endif // _T3D_PHYSICS_BTBODY_H_ diff --git a/Engine/source/T3D/physics/physicsBody.h b/Engine/source/T3D/physics/physicsBody.h index 15e94bcbd..fd8cca089 100644 --- a/Engine/source/T3D/physics/physicsBody.h +++ b/Engine/source/T3D/physics/physicsBody.h @@ -113,6 +113,10 @@ public: /// virtual void applyImpulse( const Point3F &origin, const Point3F &force ) = 0; + + virtual void findContact(SceneObject **contactObject, + VectorF *contactNormal, + Vector *outOverlapObjects) const = 0; }; diff --git a/Engine/source/T3D/physics/physx3/px3Body.cpp b/Engine/source/T3D/physics/physx3/px3Body.cpp index 026309f08..e36e76d8d 100644 --- a/Engine/source/T3D/physics/physx3/px3Body.cpp +++ b/Engine/source/T3D/physics/physx3/px3Body.cpp @@ -417,3 +417,55 @@ void Px3Body::applyImpulse( const Point3F &origin, const Point3F &force ) } +void Px3Body::findContact(SceneObject **contactObject, + VectorF *contactNormal, + Vector *outOverlapObjects) const +{ + // Calculate the sweep motion... + F32 halfCapSize = mOriginOffset; + F32 halfSmallCapSize = halfCapSize * 0.8f; + F32 diff = halfCapSize - halfSmallCapSize; + + F32 distance = diff + mSkinWidth + 0.01f; + physx::PxVec3 dir(0, 0, -1); + + physx::PxScene *scene = mWorld->getScene(); + physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT); + physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC | physx::PxQueryFlag::eSTATIC); + filterData.data.word0 = PX3_DEFAULT; + physx::PxSweepHit sweepHit; + physx::PxRigidDynamic *actor = mController->getActor(); + physx::PxU32 shapeIndex; + + bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor, *scene, dir, distance, hitFlags, sweepHit, shapeIndex, filterData); + if (hit) + { + PhysicsUserData *data = PhysicsUserData::cast(sweepHit.actor->userData); + if (data) + { + *contactObject = data->getObject(); + *contactNormal = px3Cast(sweepHit.normal); + } + } + + // Check for overlapped objects ( triggers ) + + if (!outOverlapObjects) + return; + + filterData.data.word0 = PX3_TRIGGER; + + const physx::PxU32 bufferSize = 10; + physx::PxOverlapBufferN hitBuffer; + hit = scene->overlap(mGeometry, actor->getGlobalPose(), hitBuffer, filterData); + if (hit) + { + for (U32 i = 0; i < hitBuffer.nbTouches; i++) + { + PhysicsUserData *data = PhysicsUserData::cast(hitBuffer.touches[i].actor->userData); + if (data) + outOverlapObjects->push_back(data->getObject()); + } + } + +} \ No newline at end of file diff --git a/Engine/source/T3D/physics/physx3/px3Body.h b/Engine/source/T3D/physics/physx3/px3Body.h index 79096f57b..831d54cde 100644 --- a/Engine/source/T3D/physics/physx3/px3Body.h +++ b/Engine/source/T3D/physics/physx3/px3Body.h @@ -117,6 +117,9 @@ public: F32 staticFriction ); virtual void applyCorrection( const MatrixF &xfm ); virtual void applyImpulse( const Point3F &origin, const Point3F &force ); + + virtual void findContact(SceneObject **contactObject, VectorF *contactNormal, + Vector *outOverlapObjects) const; }; #endif // _PX3BODY_H_ From 2e339bafbabc8cc4162a2fbeec4ae5046a5e91a1 Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 13 May 2016 23:58:57 -0500 Subject: [PATCH 29/71] Adds the Entity object. --- Engine/source/T3D/Entity.cpp | 1898 +++++++++++++++++++++++++++++++ Engine/source/T3D/Entity.h | 287 +++++ Engine/source/T3D/objectTypes.h | 13 +- 3 files changed, 2195 insertions(+), 3 deletions(-) create mode 100644 Engine/source/T3D/Entity.cpp create mode 100644 Engine/source/T3D/Entity.h diff --git a/Engine/source/T3D/Entity.cpp b/Engine/source/T3D/Entity.cpp new file mode 100644 index 000000000..e80f4e8b8 --- /dev/null +++ b/Engine/source/T3D/Entity.cpp @@ -0,0 +1,1898 @@ +//----------------------------------------------------------------------------- +// 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 "T3D/Entity.h" +#include "core/stream/bitStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "sim/netConnection.h" +#include "scene/sceneRenderState.h" +#include "scene/sceneManager.h" +#include "T3D/gameBase/gameProcess.h" +#include "console/engineAPI.h" +#include "T3D/gameBase/gameConnection.h" +#include "math/mathIO.h" +#include "math/mTransform.h" + +#include "T3D/Components/coreInterfaces.h" +#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/Components/Collision/collisionInterfaces.h" + +#include "gui/controls/guiTreeViewCtrl.h" + +#include "console/consoleInternal.h" +#include "T3D/gameBase/std/stdMoveList.h" + +#include "T3D/prefab.h" + +// +#include "gfx/sim/debugDraw.h" +// + +extern bool gEditingMission; + +// Client prediction +static F32 sMinWarpTicks = 0.5f; // Fraction of tick at which instant warp occurs +static S32 sMaxWarpTicks = 3; // Max warp duration in ticks +static S32 sMaxPredictionTicks = 30; // Number of ticks to predict + +IMPLEMENT_CO_NETOBJECT_V1(Entity); + +ConsoleDocClass(Entity, + "@brief Base Entity class.\n\n" + + "Entity is typically made up of a shape and up to two particle emitters. In most cases Entity objects are " + "not created directly. They are usually produced automatically by other means, such as through the Explosion " + "class. When an explosion goes off, its ExplosionData datablock determines what Entity to emit.\n" + + "@tsexample\n" + "datablock ExplosionData(GrenadeLauncherExplosion)\n" + "{\n" + " // Assiging Entity data\n" + " Entity = GrenadeEntity;\n\n" + " // Adjust how Entity is ejected\n" + " EntityThetaMin = 10;\n" + " EntityThetaMax = 60;\n" + " EntityNum = 4;\n" + " EntityNumVariance = 2;\n" + " EntityVelocity = 25;\n" + " EntityVelocityVariance = 5;\n\n" + " // Note: other ExplosionData properties are not listed for this example\n" + "};\n" + "@endtsexample\n\n" + + "@note Entity are client side only objects.\n" + + "@see EntityData\n" + "@see ExplosionData\n" + "@see Explosion\n" + + "@ingroup FX\n" + ); + +Entity::Entity() +{ + //mTypeMask |= DynamicShapeObjectType | StaticObjectType | ; + mTypeMask |= EntityObjectType; + mNetFlags.set(Ghostable | ScopeAlways); + + mPos = Point3F(0, 0, 0); + mRot = Point3F(0, 0, 0); + + mDelta.pos = mDelta.posVec = Point3F::Zero; + mDelta.rot[0].identity(); + mDelta.rot[1].identity(); + mDelta.warpOffset.set(0.0f, 0.0f, 0.0f); + + mDelta.warpTicks = mDelta.warpCount = 0; + mDelta.dt = 1.0f; + mDelta.move = NullMove; + + mComponents.clear(); + + mStartComponentUpdate = false; + + mInitialized = false; + +} + +Entity::~Entity() +{ + +} + +void Entity::initPersistFields() +{ + Parent::initPersistFields(); + + removeField("DataBlock"); + + addGroup("Transform"); + + removeField("Position"); + addProtectedField("Position", TypePoint3F, Offset(mPos, Entity), &_setPosition, &_getPosition, "Object world orientation."); + + removeField("Rotation"); + addProtectedField("Rotation", TypeRotationF, Offset(mRot, Entity), &_setRotation, &_getRotation, "Object world orientation."); + + //These are basically renamed mountPos/Rot. pretty much there for conveinence + addField("LocalPosition", TypeMatrixPosition, Offset(mMount.xfm, Entity), "Position we are mounted at ( object space of our mount object )."); + addField("LocalRotation", TypeMatrixRotation, Offset(mMount.xfm, Entity), "Rotation we are mounted at ( object space of our mount object )."); + + endGroup("Transform"); +} + +// +bool Entity::_setPosition(void *object, const char *index, const char *data) +{ + Entity* so = static_cast(object); + if (so) + { + Point3F pos; + + if (!dStrcmp(data, "")) + pos = Point3F(0, 0, 0); + else + Con::setData(TypePoint3F, &pos, 0, 1, &data); + + so->setTransform(pos, so->mRot); + } + return false; +} + +const char * Entity::_getPosition(void* obj, const char* data) +{ + Entity* so = static_cast(obj); + if (so) + { + Point3F pos = so->getPosition(); + + static const U32 bufSize = 256; + char* returnBuffer = Con::getReturnBuffer(bufSize); + dSprintf(returnBuffer, bufSize, "%g %g %g", pos.x, pos.y, pos.z); + return returnBuffer; + } + return "0 0 0"; +} + +bool Entity::_setRotation(void *object, const char *index, const char *data) +{ + Entity* so = static_cast(object); + if (so) + { + RotationF rot; + Con::setData(TypeRotationF, &rot, 0, 1, &data); + + //so->mRot = rot; + //MatrixF mat = rot.asMatrixF(); + //mat.setPosition(so->getPosition()); + //so->setTransform(mat); + so->setTransform(so->getPosition(), rot); + } + return false; +} + +const char * Entity::_getRotation(void* obj, const char* data) +{ + Entity* so = static_cast(obj); + if (so) + { + EulerF eulRot = so->mRot.asEulerF(); + + static const U32 bufSize = 256; + char* returnBuffer = Con::getReturnBuffer(bufSize); + dSprintf(returnBuffer, bufSize, "%g %g %g", mRadToDeg(eulRot.x), mRadToDeg(eulRot.y), mRadToDeg(eulRot.z)); + return returnBuffer; + } + return "0 0 0"; +} + +bool Entity::onAdd() +{ + if (!Parent::onAdd()) + return false; + + mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); + + resetWorldBox(); + setObjectBox(mObjBox); + + addToScene(); + + //Make sure we get positioned + setMaskBits(TransformMask); + + return true; +} + +void Entity::onRemove() +{ + clearComponents(false); + + removeFromScene(); + + onDataSet.removeAll(); + + Parent::onRemove(); +} + +void Entity::onPostAdd() +{ + mInitialized = true; + + //everything's done and added. go ahead and initialize the components + for (U32 i = 0; i < mComponents.size(); i++) + { + mComponents[i]->onComponentAdd(); + } + + if (isMethod("onAdd")) + Con::executef(this, "onAdd"); +} + +void Entity::setDataField(StringTableEntry slotName, const char *array, const char *value) +{ + Parent::setDataField(slotName, array, value); + + onDataSet.trigger(this, slotName, value); +} + +void Entity::onStaticModified(const char* slotName, const char* newValue) +{ + Parent::onStaticModified(slotName, newValue); + + onDataSet.trigger(this, slotName, newValue); +} + +//Updating +void Entity::processTick(const Move* move) +{ + if (!isHidden()) + { + if (mDelta.warpCount < mDelta.warpTicks) + { + mDelta.warpCount++; + + // Set new pos. + mObjToWorld.getColumn(3, &mDelta.pos); + mDelta.pos += mDelta.warpOffset; + mDelta.rot[0] = mDelta.rot[1]; + mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks); + setTransform(mDelta.pos, mDelta.rot[1]); + + // Pos backstepping + mDelta.posVec.x = -mDelta.warpOffset.x; + mDelta.posVec.y = -mDelta.warpOffset.y; + mDelta.posVec.z = -mDelta.warpOffset.z; + } + else + { + if (isMounted()) + { + MatrixF mat; + mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat); + Parent::setTransform(mat); + Parent::setRenderTransform(mat); + } + else + { + if (!move) + { + if (isGhost()) + { + // If we haven't run out of prediction time, + // predict using the last known move. + if (mPredictionCount-- <= 0) + return; + + move = &mDelta.move; + } + else + { + move = &NullMove; + } + } + } + } + + Move prevMove = lastMove; + + if (move != NULL) + lastMove = *move; + else + lastMove = NullMove; + + if (move && isServerObject()) + { + if ((move->y != 0 || prevMove.y != 0) + || (move->x != 0 || prevMove.x != 0) + || (move->z != 0 || prevMove.x != 0)) + { + if (isMethod("moveVectorEvent")) + Con::executef(this, "moveVectorEvent", move->x, move->y, move->z); + } + + if (move->yaw != 0) + { + if (isMethod("moveYawEvent")) + Con::executef(this, "moveYawEvent", move->yaw); + } + + if (move->pitch != 0) + { + if (isMethod("movePitchEvent")) + Con::executef(this, "movePitchEvent", move->pitch); + } + + if (move->roll != 0) + { + if (isMethod("moveRollEvent")) + Con::executef(this, "moveRollEvent", move->roll); + } + + for (U32 i = 0; i < MaxTriggerKeys; i++) + { + if (move->trigger[i] != prevMove.trigger[i]) + { + if (isMethod("moveTriggerEvent")) + Con::executef(this, "moveTriggerEvent", i, move->trigger[i]); + } + } + } + + if (isMethod("processTick")) + Con::executef(this, "processTick"); + } +} + +void Entity::advanceTime(F32 dt) +{ +} + +void Entity::interpolateTick(F32 dt) +{ + if (dt == 0.0f) + { + setRenderTransform(mDelta.pos, mDelta.rot[1]); + } + else + { + QuatF rot; + rot.interpolate(mDelta.rot[1], mDelta.rot[0], dt); + Point3F pos = mDelta.pos + mDelta.posVec * dt; + + setRenderTransform(pos, rot); + } + + mDelta.dt = dt; +} + +//Render +void Entity::prepRenderImage(SceneRenderState *state) +{ +} + +//Networking +U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (stream->writeFlag(mask & TransformMask)) + { + //mathWrite( *stream, getScale() ); + //stream->writeAffineTransform(mObjToWorld); + //mathWrite(*stream, getPosition()); + mathWrite(*stream, mPos); + + //mathWrite(*stream, getRotation()); + mathWrite(*stream, getRotation().asEulerF()); + + mDelta.move.pack(stream); + + stream->writeFlag(!(mask & NoWarpMask)); + } + + /*if (stream->writeFlag(mask & MountedMask)) + { + mathWrite(*stream, mMount.xfm.getPosition()); + mathWrite(*stream, mMount.xfm.toEuler()); + }*/ + + if (stream->writeFlag(mask & BoundsMask)) + { + mathWrite(*stream, mObjBox); + } + + //pass our behaviors around + if (mask & ComponentsMask || mask & InitialUpdateMask) + { + stream->writeFlag(true); + //now, we run through a list of our to-be-sent behaviors and begin sending them + //if any fail, we keep our list and re-queue the mask + S32 componentCount = mToLoadComponents.size(); + + //build our 'ready' list + //This requires both the instance and the instances' template to be prepped(if the template hasn't been ghosted, + //then we know we shouldn't be passing the instance's ghosts around yet) + U32 ghostedCompCnt = 0; + for (U32 i = 0; i < componentCount; i++) + { + if (con->getGhostIndex(mToLoadComponents[i]) != -1) + ghostedCompCnt++; + } + + if (ghostedCompCnt != 0) + { + stream->writeFlag(true); + + stream->writeFlag(mStartComponentUpdate); + + //if not all the behaviors have been ghosted, we'll need another pass + if (ghostedCompCnt != componentCount) + retMask |= ComponentsMask; + + //write the currently ghosted behavior count + stream->writeInt(ghostedCompCnt, 16); + + for (U32 i = 0; i < mToLoadComponents.size(); i++) + { + //now fetch them and pass the ghost + S32 ghostIndex = con->getGhostIndex(mToLoadComponents[i]); + if (ghostIndex != -1) + { + stream->writeInt(ghostIndex, NetConnection::GhostIdBitSize); + mToLoadComponents.erase(i); + i--; + + mStartComponentUpdate = false; + } + } + } + else if (componentCount) + { + //on the odd chance we have behaviors to ghost, but NONE of them have been yet, just set the flag now + stream->writeFlag(false); + retMask |= ComponentsMask; + } + else + stream->writeFlag(false); + } + else + stream->writeFlag(false); + + return retMask; +} + +void Entity::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) + { + /*Point3F scale; + mathRead( *stream, &scale ); + setScale( scale);*/ + + //MatrixF objToWorld; + //stream->readAffineTransform(&objToWorld); + + Point3F pos; + + mathRead(*stream, &pos); + + RotationF rot; + + EulerF eRot; + mathRead(*stream, &eRot); + + rot = RotationF(eRot); + + mDelta.move.unpack(stream); + + if (stream->readFlag() && isProperlyAdded()) + { + // Determine number of ticks to warp based on the average + // of the client and server velocities. + /*mDelta.warpOffset = pos - mDelta.pos; + + F32 dt = mDelta.warpOffset.len() / (0.5f * TickSec); + + mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f); + + //F32 as = (speed + mVelocity.len()) * 0.5f * TickSec; + //F32 dt = (as > 0.00001f) ? mDelta.warpOffset.len() / as : sMaxWarpTicks; + //mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f); + + //mDelta.warpTicks = (S32)((dt > sMinWarpTicks) ? getMax(mFloor(dt + 0.5f), 1.0f) : 0.0f); + + //mDelta.warpTicks = sMaxWarpTicks; + + mDelta.warpTicks = 0; + + if (mDelta.warpTicks) + { + // Setup the warp to start on the next tick. + if (mDelta.warpTicks > sMaxWarpTicks) + mDelta.warpTicks = sMaxWarpTicks; + mDelta.warpOffset /= (F32)mDelta.warpTicks; + + mDelta.rot[0] = rot.asQuatF(); + mDelta.rot[1] = rot.asQuatF(); + + mDelta.rotOffset = rot.asEulerF() - mDelta.rot.asEulerF(); + + // Ignore small rotation differences + if (mFabs(mDelta.rotOffset.x) < 0.001f) + mDelta.rotOffset.x = 0; + + if (mFabs(mDelta.rotOffset.y) < 0.001f) + mDelta.rotOffset.y = 0; + + if (mFabs(mDelta.rotOffset.z) < 0.001f) + mDelta.rotOffset.z = 0; + + mDelta.rotOffset /= (F32)mDelta.warpTicks; + } + else + { + // Going to skip the warp, server and client are real close. + // Adjust the frame interpolation to move smoothly to the + // new position within the current tick. + Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt; + if (mDelta.dt == 0) + { + mDelta.posVec.set(0.0f, 0.0f, 0.0f); + mDelta.rotVec.set(0.0f, 0.0f, 0.0f); + } + else + { + F32 dti = 1.0f / mDelta.dt; + mDelta.posVec = (cp - pos) * dti; + mDelta.rotVec.z = mRot.z - rot.z; + + mDelta.rotVec.z *= dti; + } + + mDelta.pos = pos; + mDelta.rot = rot; + + setTransform(pos, rot); + }*/ + + Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt; + mDelta.warpOffset = pos - cp; + + // Calc the distance covered in one tick as the average of + // the old speed and the new speed from the server. + VectorF vel = pos - mDelta.pos; + F32 dt, as = vel.len() * 0.5 * TickSec; + + // Cal how many ticks it will take to cover the warp offset. + // If it's less than what's left in the current tick, we'll just + // warp in the remaining time. + if (!as || (dt = mDelta.warpOffset.len() / as) > sMaxWarpTicks) + dt = mDelta.dt + sMaxWarpTicks; + else + dt = (dt <= mDelta.dt) ? mDelta.dt : mCeil(dt - mDelta.dt) + mDelta.dt; + + // Adjust current frame interpolation + if (mDelta.dt) + { + mDelta.pos = cp + (mDelta.warpOffset * (mDelta.dt / dt)); + mDelta.posVec = (cp - mDelta.pos) / mDelta.dt; + QuatF cr; + cr.interpolate(mDelta.rot[1], mDelta.rot[0], mDelta.dt); + mDelta.rot[1].interpolate(cr, pos, mDelta.dt / dt); + mDelta.rot[0].extrapolate(mDelta.rot[1], cr, mDelta.dt); + } + + // Calculated multi-tick warp + mDelta.warpCount = 0; + mDelta.warpTicks = (S32)(mFloor(dt)); + if (mDelta.warpTicks) + { + mDelta.warpOffset = pos - mDelta.pos; + mDelta.warpOffset /= mDelta.warpTicks; + mDelta.warpRot[0] = mDelta.rot[1]; + mDelta.warpRot[1] = rot.asQuatF(); + } + } + else + { + // Set the entity to the server position + mDelta.dt = 0; + mDelta.pos = pos; + mDelta.posVec.set(0, 0, 0); + mDelta.rot[1] = mDelta.rot[0] = rot.asQuatF(); + mDelta.warpCount = mDelta.warpTicks = 0; + setTransform(pos, rot); + } + } + + /*if (stream->readFlag()) + { + Point3F mountOffset; + EulerF mountRot; + mathRead(*stream, &mountOffset); + mathRead(*stream, &mountRot); + + RotationF rot = RotationF(mountRot); + mountRot = rot.asEulerF(RotationF::Degrees); + + setMountOffset(mountOffset); + setMountRotation(mountRot); + }*/ + + if (stream->readFlag()) + { + mathRead(*stream, &mObjBox); + resetWorldBox(); + } + + if (stream->readFlag()) + { + //are we passing any behaviors currently? + if (stream->readFlag()) + { + //if we've just started the update, clear our behaviors + if (stream->readFlag()) + clearComponents(false); + + S32 componentCount = stream->readInt(16); + + for (U32 i = 0; i < componentCount; i++) + { + S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize); + addComponent(dynamic_cast(con->resolveGhost(gIndex))); + } + } + } +} + +//Manipulation +void Entity::setTransform(const MatrixF &mat) +{ + //setMaskBits(TransformMask); + setMaskBits(TransformMask | NoWarpMask); + + if (isMounted()) + { + // Use transform from mounted object + Point3F newPos = mat.getPosition(); + Point3F parentPos = mMount.object->getTransform().getPosition(); + + Point3F newOffset = newPos - parentPos; + + if (!newOffset.isZero()) + { + //setMountOffset(newOffset); + mPos = newOffset; + } + + Point3F matEul = mat.toEuler(); + + //mRot = Point3F(mRadToDeg(matEul.x), mRadToDeg(matEul.y), mRadToDeg(matEul.z)); + + if (matEul != Point3F(0, 0, 0)) + { + Point3F mountEul = mMount.object->getTransform().toEuler(); + Point3F diff = matEul - mountEul; + + //setMountRotation(Point3F(mRadToDeg(diff.x), mRadToDeg(diff.y), mRadToDeg(diff.z))); + mRot = diff; + } + else + { + //setMountRotation(Point3F(0, 0, 0)); + mRot = Point3F(0, 0, 0); + } + + RotationF addRot = mRot + RotationF(mMount.object->getTransform()); + MatrixF transf = addRot.asMatrixF(); + transf.setPosition(mPos + mMount.object->getPosition()); + + Parent::setTransform(transf); + } + else + { + //Are we part of a prefab? + /*Prefab* p = Prefab::getPrefabByChild(this); + if (p) + { + //just let our prefab know we moved + p->childTransformUpdated(this, mat); + }*/ + //else + { + //mRot.set(mat); + //Parent::setTransform(mat); + + RotationF rot = RotationF(mat); + + EulerF tempRot = rot.asEulerF(RotationF::Degrees); + + Point3F pos; + + mat.getColumn(3,&pos); + + setTransform(pos, rot); + } + } +} + +void Entity::setTransform(Point3F position, RotationF rotation) +{ + if (isMounted()) + { + mPos = position; + mRot = rotation; + + RotationF addRot = mRot + RotationF(mMount.object->getTransform()); + MatrixF transf = addRot.asMatrixF(); + transf.setPosition(mPos + mMount.object->getPosition()); + + Parent::setTransform(transf); + + setMaskBits(TransformMask); + } + else + { + /*MatrixF newMat, imat, xmat, ymat, zmat; + Point3F radRot = Point3F(mDegToRad(rotation.x), mDegToRad(rotation.y), mDegToRad(rotation.z)); + xmat.set(EulerF(radRot.x, 0, 0)); + ymat.set(EulerF(0.0f, radRot.y, 0.0f)); + zmat.set(EulerF(0, 0, radRot.z)); + imat.mul(zmat, xmat); + newMat.mul(imat, ymat);*/ + + MatrixF newMat = rotation.asMatrixF(); + + newMat.setColumn(3, position); + + mPos = position; + mRot = rotation; + + setMaskBits(TransformMask); + //if (isServerObject()) + // setMaskBits(TransformMask); + + //setTransform(temp); + + // This test is a bit expensive so turn it off in release. +#ifdef TORQUE_DEBUG + //AssertFatal( mat.isAffine(), "SceneObject::setTransform() - Bad transform (non affine)!" ); +#endif + + //PROFILE_SCOPE(Entity_setTransform); + + // Update the transforms. + + Parent::setTransform(newMat); + + onTransformSet.trigger(&newMat); + + /*mObjToWorld = mWorldToObj = newMat; + mWorldToObj.affineInverse(); + // Update the world-space AABB. + resetWorldBox(); + // If we're in a SceneManager, sync our scene state. + if (mSceneManager != NULL) + mSceneManager->notifyObjectDirty(this); + setRenderTransform(newMat);*/ + } +} + +void Entity::setRenderTransform(const MatrixF &mat) +{ + Parent::setRenderTransform(mat); +} + +void Entity::setRenderTransform(Point3F position, RotationF rotation) +{ + if (isMounted()) + { + mPos = position; + mRot = rotation; + + RotationF addRot = mRot + RotationF(mMount.object->getTransform()); + MatrixF transf = addRot.asMatrixF(); + transf.setPosition(mPos + mMount.object->getPosition()); + + Parent::setRenderTransform(transf); + } + else + { + MatrixF newMat = rotation.asMatrixF(); + + newMat.setColumn(3, position); + + mPos = position; + mRot = rotation; + + Parent::setRenderTransform(newMat); + + onTransformSet.trigger(&newMat); + } +} + +MatrixF Entity::getTransform() +{ + if (isMounted()) + { + MatrixF mat; + + //Use transform from mount + mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat); + + Point3F transPos = mat.getPosition() + mPos; + + mat.mul(mRot.asMatrixF()); + + mat.setPosition(transPos); + + return mat; + } + else + { + return Parent::getTransform(); + } +} + +void Entity::setMountOffset(Point3F posOffset) +{ + if (isMounted()) + { + mMount.xfm.setColumn(3, posOffset); + //mPos = posOffset; + setMaskBits(MountedMask); + } +} + +void Entity::setMountRotation(EulerF rotOffset) +{ + if (isMounted()) + { + MatrixF temp, imat, xmat, ymat, zmat; + + Point3F radRot = Point3F(mDegToRad(rotOffset.x), mDegToRad(rotOffset.y), mDegToRad(rotOffset.z)); + xmat.set(EulerF(radRot.x, 0, 0)); + ymat.set(EulerF(0.0f, radRot.y, 0.0f)); + zmat.set(EulerF(0, 0, radRot.z)); + + imat.mul(zmat, xmat); + temp.mul(imat, ymat); + + temp.setColumn(3, mMount.xfm.getPosition()); + + mMount.xfm = temp; + //mRot = RotationF(temp); + setMaskBits(MountedMask); + } +} +// +void Entity::getCameraTransform(F32* pos, MatrixF* mat) +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) { + if ((*it)->getCameraTransform(pos, mat)) { + return; + } + } +} + +void Entity::getMountTransform(S32 index, const MatrixF &xfm, MatrixF *outMat) +{ + RenderComponentInterface* renderInterface = getComponent(); + + if (renderInterface) + { + renderInterface->getShapeInstance()->animate(); + S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size(); + + if (index >= 0 && index < nodeCount) + { + MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index]; + mountTransform.mul(xfm); + const Point3F& scale = getScale(); + + // The position of the mount point needs to be scaled. + Point3F position = mountTransform.getPosition(); + position.convolve(scale); + mountTransform.setPosition(position); + + // Also we would like the object to be scaled to the model. + outMat->mul(mObjToWorld, mountTransform); + return; + } + } + + // Then let SceneObject handle it. + Parent::getMountTransform(index, xfm, outMat); +} + +void Entity::getRenderMountTransform(F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat) +{ + RenderComponentInterface* renderInterface = getComponent(); + + if (renderInterface && renderInterface->getShapeInstance()) + { + renderInterface->getShapeInstance()->animate(); + S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size(); + + if (index >= 0 && index < nodeCount) + { + MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index]; + mountTransform.mul(xfm); + const Point3F& scale = getScale(); + + // The position of the mount point needs to be scaled. + Point3F position = mountTransform.getPosition(); + position.convolve(scale); + mountTransform.setPosition(position); + + // Also we would like the object to be scaled to the model. + outMat->mul(getRenderTransform(), mountTransform); + return; + } + } + + // Then let SceneObject handle it. + Parent::getMountTransform(index, xfm, outMat); +} + +void Entity::setForwardVector(VectorF newForward, VectorF upVector) +{ + MatrixF mat = getTransform(); + + VectorF up(0.0f, 0.0f, 1.0f); + VectorF axisX; + VectorF axisY = newForward; + VectorF axisZ; + + if (upVector != VectorF::Zero) + up = upVector; + + // Validate and normalize input: + F32 lenSq; + lenSq = axisY.lenSquared(); + if (lenSq < 0.000001f) + { + axisY.set(0.0f, 1.0f, 0.0f); + Con::errorf("Entity::setForwardVector() - degenerate forward vector"); + } + else + { + axisY /= mSqrt(lenSq); + } + + + lenSq = up.lenSquared(); + if (lenSq < 0.000001f) + { + up.set(0.0f, 0.0f, 1.0f); + Con::errorf("SceneObject::setForwardVector() - degenerate up vector - too small"); + } + else + { + up /= mSqrt(lenSq); + } + + if (fabsf(mDot(up, axisY)) > 0.9999f) + { + Con::errorf("SceneObject::setForwardVector() - degenerate up vector - same as forward"); + // i haven't really tested this, but i think it generates something which should be not parallel to the previous vector: + F32 tmp = up.x; + up.x = -up.y; + up.y = up.z; + up.z = tmp; + } + + // construct the remaining axes: + mCross(axisY, up, &axisX); + mCross(axisX, axisY, &axisZ); + + mat.setColumn(0, axisX); + mat.setColumn(1, axisY); + mat.setColumn(2, axisZ); + + setTransform(mat); +} +// +//These basically just redirect to any collision behaviors we have +bool Entity::castRay(const Point3F &start, const Point3F &end, RayInfo* info) +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { + if ((*it)->castRay(start, end, info)) + { + return true; + } + } + return false; +} + +bool Entity::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info) +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { + if ((*it)->castRayRendered(start, end, info)) + { + return true; + } + } + return false; +} + +bool Entity::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { + return (*it)->buildPolyList(context, polyList, box, sphere); + } + + return false; +} + +void Entity::buildConvex(const Box3F& box, Convex* convex) +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { + (*it)->buildConvex(box, convex); + } +} + +// +// Mounting and heirarchy manipulation +void Entity::mountObject(SceneObject* objB, MatrixF txfm) +{ + Parent::mountObject(objB, -1, txfm); + Parent::addObject(objB); +} + +void Entity::mountObject(SceneObject *obj, S32 node, const MatrixF &xfm) +{ + Parent::mountObject(obj, node, xfm); +} + +void Entity::onMount(SceneObject *obj, S32 node) +{ + deleteNotify(obj); + + // Are we mounting to a GameBase object? + Entity *entityObj = dynamic_cast(obj); + + if (entityObj && entityObj->getControlObject() != this) + processAfter(entityObj); + + if (!isGhost()) { + setMaskBits(MountedMask); + + //TODO implement this callback + //onMount_callback( this, obj, node ); + } +} + +void Entity::onUnmount(SceneObject *obj, S32 node) +{ + clearNotify(obj); + + Entity *entityObj = dynamic_cast(obj); + + if (entityObj && entityObj->getControlObject() != this) + clearProcessAfter(); + + if (!isGhost()) { + setMaskBits(MountedMask); + + //TODO implement this callback + //onUnmount_callback( this, obj, node ); + } +} + +//Heirarchy stuff +void Entity::addObject(SimObject* object) +{ + Component* component = dynamic_cast(object); + if (component) + { + addComponent(component); + return; + } + + Entity* e = dynamic_cast(object); + if (e) + { + MatrixF offset; + + //offset.mul(getWorldTransform(), e->getWorldTransform()); + + //check if we're mounting to a node on a shape we have + String node = e->getDataField("mountNode", NULL); + if (!node.isEmpty()) + { + RenderComponentInterface *renderInterface = getComponent(); + if (renderInterface) + { + TSShape* shape = renderInterface->getShape(); + S32 nodeIdx = shape->findNode(node); + + mountObject(e, nodeIdx, MatrixF::Identity); + } + else + { + mountObject(e, MatrixF::Identity); + } + } + else + { + /*Point3F posOffset = mPos - e->getPosition(); + mPos = posOffset; + + RotationF rotOffset = mRot - e->getRotation(); + mRot = rotOffset; + setMaskBits(TransformMask); + mountObject(e, MatrixF::Identity);*/ + + mountObject(e, MatrixF::Identity); + } + + //e->setMountOffset(e->getPosition() - getPosition()); + + //Point3F diff = getWorldTransform().toEuler() - e->getWorldTransform().toEuler(); + + //e->setMountRotation(Point3F(mRadToDeg(diff.x),mRadToDeg(diff.y),mRadToDeg(diff.z))); + + //mountObject(e, offset); + } + else + { + SceneObject* so = dynamic_cast(object); + if (so) + { + //get the difference and build it as our offset! + Point3F posOffset = so->getPosition() - mPos; + RotationF rotOffset = RotationF(so->getTransform()) - mRot; + + MatrixF offset = rotOffset.asMatrixF(); + offset.setPosition(posOffset); + + mountObject(so, offset); + return; + } + } + + Parent::addObject(object); +} + +void Entity::removeObject(SimObject* object) +{ + Entity* e = dynamic_cast(object); + if (e) + { + mPos = mPos + e->getPosition(); + mRot = mRot + e->getRotation(); + unmountObject(e); + setMaskBits(TransformMask); + } + else + { + SceneObject* so = dynamic_cast(object); + if (so) + unmountObject(so); + } + + Parent::removeObject(object); +} + +bool Entity::addComponent(Component *comp) +{ + if (comp == NULL || !comp->isProperlyAdded()) + return false; + + //double-check were not re-adding anything + mComponents.push_back(comp); + + // Register the component with this owner. + comp->setOwner(this); + + //if we've already been added and this is being added after the fact(at runtime), + //then just go ahead and call it's onComponentAdd so it can get to work + if (mInitialized) + comp->onComponentAdd(); + + onComponentAdded.trigger(comp); + + return true; +} + +SimObject* Entity::findObjectByInternalName(StringTableEntry internalName, bool searchChildren) +{ + for (U32 i = 0; i < mComponents.size(); i++) + { + if (mComponents[i]->getInternalName() == internalName) + { + return mComponents[i]; + } + } + + return Parent::findObjectByInternalName(internalName, searchChildren); +} + +////////////////////////////////////////////////////////////////////////// + +bool Entity::removeComponent(Component *comp, bool deleteComponent) +{ + if (comp == NULL) + return false; + + if(mComponents.remove(comp)) + { + AssertFatal(comp->isProperlyAdded(), "Don't know how but a component is not registered w/ the sim"); + + //setComponentsDirty(); + + onComponentRemoved.trigger(comp); + + comp->setOwner(NULL); + + comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner + + if (deleteComponent) + comp->safeDeleteObject(); + + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////// +//NOTE: +//The actor class calls this and flags the deletion of the behaviors to false so that behaviors that should no longer be attached during +//a network update will indeed be removed from the object. The reason it doesn't delete them is because when clearing the local behavior +//list, it would delete them, purging the ghost, and causing a crash when the unpack update tried to fetch any existing behaviors' ghosts +//to re-add them. Need to implement a clean clear function that will clear the local list, and only delete unused behaviors during an update. +void Entity::clearComponents(bool deleteComponents) +{ + bool srv = isServerObject(); + if (!deleteComponents) + { + while (mComponents.size() > 0) + { + removeComponent(mComponents.first(), deleteComponents); + } + } + else + { + while (mComponents.size() > 0) + { + Component* comp = mComponents.first(); + + if (comp) + { + comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner + + bool removed = mComponents.remove(comp); + + //we only need to delete them on the server side. they'll be cleaned up on the client side + //via the ghosting system for us + if (isServerObject()) + comp->deleteObject(); + } + } + } +} + +////////////////////////////////////////////////////////////////////////// +Component *Entity::getComponent(const U32 index) const +{ + if (index < mComponents.size()) + return mComponents[index]; + + return NULL; +} + +Component *Entity::getComponent(String componentType) +{ + for (U32 i = 0; i < mComponents.size(); i++) + { + Component* comp = mComponents[i]; + + /*String namespaceName = comp->getNamespace()->mName; + //check our namespace first + if (namespaceName == componentType) + { + return comp; + } + else + {*/ + //lets scan up, just to be sure + Namespace *NS = comp->getNamespace(); + + //we shouldn't ever go past Component into net object, as we're no longer dealing with component classes + while (dStrcmp(NS->getName(), "NetObject")) + { + String namespaceName = NS->getName(); + + if (namespaceName == componentType) + { + return comp; + } + else + { + NS = NS->getParent(); + } + } + //} + } + + return NULL; +} + +void Entity::onInspect() +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) { + (*it)->onInspect(); + } + + GuiTreeViewCtrl *editorTree = dynamic_cast(Sim::findObject("EditorTree")); + if (!editorTree) + return; + + GuiTreeViewCtrl::Item *newItem, *parentItem; + + parentItem = editorTree->getItem(editorTree->findItemByObjectId(getId())); + + S32 componentID = editorTree->insertItem(parentItem->getID(), "Components"); + + newItem = editorTree->getItem(componentID); + newItem->mState.set(GuiTreeViewCtrl::Item::VirtualParent); + newItem->mState.set(GuiTreeViewCtrl::Item::DenyDrag); + //newItem->mState.set(GuiTreeViewCtrl::Item::InspectorData); + newItem->mState.set(GuiTreeViewCtrl::Item::ForceItemName); + //newItem->mInspectorInfo.mObject = this; + + for (U32 i = 0; i < mComponents.size(); i++) + { + String compName = mComponents[i]->getFriendlyName(); + S32 compID = editorTree->insertItem(componentID, compName); + newItem = editorTree->getItem(compID); + newItem->mInspectorInfo.mObject = mComponents[i]; + newItem->mState.set(GuiTreeViewCtrl::Item::ForceItemName); + newItem->mState.set(GuiTreeViewCtrl::Item::DenyDrag); + newItem->mState.set(GuiTreeViewCtrl::Item::InspectorData); + } + + editorTree->buildVisibleTree(true); +} + +void Entity::onEndInspect() +{ + Vector updaters = getComponents(); + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) { + (*it)->onEndInspect(); + } + + GuiTreeViewCtrl *editorTree = dynamic_cast(Sim::findObject("EditorTree")); + if (!editorTree) + return; + + S32 componentItemIdx = editorTree->findItemByName("Components"); + + editorTree->removeItem(componentItemIdx, false); +} + +static void writeTabs(Stream &stream, U32 count) +{ + char tab[] = " "; + while (count--) + stream.write(3, (void*)tab); +} + +void Entity::write(Stream &stream, U32 tabStop, U32 flags) +{ + // Do *not* call parent on this + + /*VectorPtr &componentList = lockComponentList(); + // export selected only? + if( ( flags & SelectedOnly ) && !isSelected() ) + { + for( BehaviorObjectIterator i = componentList.begin(); i != componentList.end(); i++ ) + (*i)->write(stream, tabStop, flags); + + goto write_end; + }*/ + + //catch if we have any written behavior fields already in the file, and clear them. We don't need to double-up + //the entries for no reason. + /*if(getFieldDictionary()) + { + //get our dynamic field count, then parse through them to see if they're a behavior or not + + //reset it + SimFieldDictionary* fieldDictionary = getFieldDictionary(); + SimFieldDictionaryIterator itr(fieldDictionary); + for (S32 i = 0; i < fieldDictionary->getNumFields(); i++) + { + if (!(*itr)) + break; + + SimFieldDictionary::Entry* entry = *itr; + if(strstr(entry->slotName, "_behavior")) + { + entry->slotName = ""; + entry->value = ""; + } + + ++itr; + } + }*/ + //all existing written behavior fields should be cleared. now write the object block + + writeTabs(stream, tabStop); + + char buffer[1024]; + dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : ""); + stream.write(dStrlen(buffer), buffer); + writeFields(stream, tabStop + 1); + + stream.write(1, "\n"); + ////first, write out our behavior objects + + // NOW we write the behavior fields proper + if (mComponents.size() > 0) + { + // Pack out the behaviors into fields + U32 i = 0; + for (U32 i = 0; i < mComponents.size(); i++) + { + writeTabs(stream, tabStop + 1); + char buffer[1024]; + dSprintf(buffer, sizeof(buffer), "new %s() {\r\n", mComponents[i]->getClassName()); + stream.write(dStrlen(buffer), buffer); + //bi->writeFields( stream, tabStop + 2 ); + + mComponents[i]->packToStream(stream, tabStop + 2, i - 1, flags); + + writeTabs(stream, tabStop + 1); + stream.write(4, "};\r\n"); + } + } + + // + //if (size() > 0) + // stream.write(2, "\r\n"); + + for (U32 i = 0; i < size(); i++) + { + SimObject* child = (*this)[i]; + if (child->getCanSave()) + child->write(stream, tabStop + 1, flags); + } + + //stream.write(2, "\r\n"); + + writeTabs(stream, tabStop); + stream.write(4, "};\r\n"); + + //write_end: + //unlockComponentList(); +} + +SimObject* Entity::getTamlChild(const U32 childIndex) const +{ + // Sanity! + AssertFatal(childIndex < getTamlChildCount(), "SimSet::getTamlChild() - Child index is out of range."); + + // For when the assert is not used. + if (childIndex >= getTamlChildCount()) + return NULL; + + //we always order components first, child objects second + if (childIndex >= getComponentCount()) + return at(childIndex - getComponentCount()); + else + return getComponent(childIndex); +} +// +void Entity::onCameraScopeQuery(NetConnection* connection, CameraScopeQuery* query) +{ + // Object itself is in scope. + Parent::onCameraScopeQuery(connection, query); + + if (CameraInterface* cI = getComponent()) + { + cI->onCameraScopeQuery(connection, query); + } +} +// +void Entity::setObjectBox(Box3F objBox) +{ + mObjBox = objBox; + resetWorldBox(); + + if (isServerObject()) + setMaskBits(BoundsMask); +} + +void Entity::updateContainer() +{ + PROFILE_SCOPE(Entity_updateContainer); + + // Update container drag and buoyancy properties + containerInfo.box = getWorldBox(); + //containerInfo.mass = mMass; + + getContainer()->findObjects(containerInfo.box, WaterObjectType | PhysicalZoneObjectType, findRouter, &containerInfo); + + //mWaterCoverage = info.waterCoverage; + //mLiquidType = info.liquidType; + //mLiquidHeight = info.waterHeight; + //setCurrentWaterObject( info.waterObject ); + + // This value might be useful as a datablock value, + // This is what allows the player to stand in shallow water (below this coverage) + // without jiggling from buoyancy + /*if (info.waterCoverage >= 0.25f) + { + // water viscosity is used as drag for in water. + // ShapeBaseData drag is used for drag outside of water. + // Combine these two components to calculate this ShapeBase object's + // current drag. + mDrag = (info.waterCoverage * info.waterViscosity) + + (1.0f - info.waterCoverage) * mDrag; + //mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage; + } + + //mAppliedForce = info.appliedForce; + mGravityMod = info.gravityScale;*/ +} +// + +void Entity::setComponentsDirty() +{ + if (mToLoadComponents.empty()) + mStartComponentUpdate = true; + + //we need to build a list of behaviors that need to be pushed across the network + for (U32 i = 0; i < mComponents.size(); i++) + { + // We can do this because both are in the string table + Component *comp = mComponents[i]; + + if (comp->isNetworked()) + { + bool unique = true; + for (U32 i = 0; i < mToLoadComponents.size(); i++) + { + if (mToLoadComponents[i]->getId() == comp->getId()) + { + unique = false; + break; + } + } + if (unique) + mToLoadComponents.push_back(comp); + } + } + + setMaskBits(ComponentsMask); +} + +void Entity::setComponentDirty(Component *comp, bool forceUpdate) +{ + bool found = false; + for (U32 i = 0; i < mComponents.size(); i++) + { + if (mComponents[i]->getId() == comp->getId()) + { + mComponents[i]->setOwner(this); + return; + } + } + + if (!found) + return; + + //if(mToLoadComponents.empty()) + // mStartComponentUpdate = true; + + /*if (comp->isNetworked() || forceUpdate) + { + bool unique = true; + for (U32 i = 0; i < mToLoadComponents.size(); i++) + { + if (mToLoadComponents[i]->getId() == comp->getId()) + { + unique = false; + break; + } + } + if (unique) + mToLoadComponents.push_back(comp); + } + + setMaskBits(ComponentsMask);*/ + +} + +DefineEngineMethod(Entity, mountObject, bool, + (SceneObject* objB, TransformF txfm), (MatrixF::Identity), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (objB) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + object->mountObject(objB, /*MatrixF::Identity*/txfm.getMatrix()); + return true; + } + return false; +} + +DefineEngineMethod(Entity, setMountOffset, void, + (Point3F posOffset), (Point3F(0, 0, 0)), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setMountOffset(posOffset); +} + +DefineEngineMethod(Entity, setMountRotation, void, + (EulerF rotOffset), (EulerF(0, 0, 0)), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setMountRotation(rotOffset); +} + +DefineEngineMethod(Entity, getMountTransform, TransformF, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + MatrixF mat; + object->getMountTransform(0, MatrixF::Identity, &mat); + return mat; +} + +DefineEngineMethod(Entity, setBox, void, + (Point3F box), (Point3F(1, 1, 1)), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setObjectBox(Box3F(-box, box)); +} + + +/*DefineConsoleMethod(Entity, callOnComponents, void, (const char* functionName), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + object->callOnComponents(functionName); +} + +ConsoleMethod(Entity, callMethod, void, 3, 64, "(methodName, argi) Calls script defined method\n" + "@param methodName The method's name as a string\n" + "@param argi Any arguments to pass to the method\n" + "@return No return value" + "@note %obj.callMethod( %methodName, %arg1, %arg2, ... );\n") + +{ + object->callMethodArgList(argc - 1, argv + 2); +} + +ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors\n" + "@return No return value") +{ + object->addComponents(); +}*/ + +ConsoleMethod(Entity, addComponent, bool, 3, 3, "(ComponentInstance bi) - Add a behavior to the object\n" + "@param bi The behavior instance to add" + "@return (bool success) Whether or not the behavior was successfully added") +{ + Component *comp = dynamic_cast(Sim::findObject(argv[2])); + + if (comp != NULL) + { + bool success = object->addComponent(comp); + + if (success) + { + //Placed here so we can differentiate against adding a new behavior during runtime, or when we load all + //fielded behaviors on mission load. This way, we can ensure that we only call the callback + //once everything is loaded. This avoids any problems with looking for behaviors that haven't been added yet, etc. + if (comp->isMethod("onBehaviorAdd")) + Con::executef(comp, "onBehaviorAdd"); + + return true; + } + } + + return false; +} + +ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(ComponentInstance bi, [bool deleteBehavior = true])\n" + "@param bi The behavior instance to remove\n" + "@param deleteBehavior Whether or not to delete the behavior\n" + "@return (bool success) Whether the behavior was successfully removed") +{ + bool deleteComponent = true; + if (argc > 3) + deleteComponent = dAtob(argv[3]); + + return object->removeComponent(dynamic_cast(Sim::findObject(argv[2])), deleteComponent); +} + +ConsoleMethod(Entity, clearComponents, void, 2, 2, "() - Clear all behavior instances\n" + "@return No return value") +{ + object->clearComponents(); +} + +ConsoleMethod(Entity, getComponentByIndex, S32, 3, 3, "(int index) - Gets a particular behavior\n" + "@param index The index of the behavior to get\n" + "@return (ComponentInstance bi) The behavior instance you requested") +{ + Component *comp = object->getComponent(dAtoi(argv[2])); + + return (comp != NULL) ? comp->getId() : 0; +} + +DefineConsoleMethod(Entity, getComponent, S32, (String componentName), (""), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + Component *comp = object->getComponent(componentName); + + return (comp != NULL) ? comp->getId() : 0; + return 0; +} + +/*ConsoleMethod(Entity, getBehaviorByType, S32, 3, 3, "(string BehaviorTemplateName) - gets a behavior\n" + "@param BehaviorTemplateName The name of the template of the behavior instance you want\n" + "@return (ComponentInstance bi) The behavior instance you requested") +{ + ComponentInstance *bInstance = object->getComponentByType(StringTable->insert(argv[2])); + + return (bInstance != NULL) ? bInstance->getId() : 0; +}*/ + +/*ConsoleMethod(Entity, reOrder, bool, 3, 3, "(ComponentInstance inst, [int desiredIndex = 0])\n" + "@param inst The behavior instance you want to reorder\n" + "@param desiredIndex The index you want the behavior instance to be reordered to\n" + "@return (bool success) Whether or not the behavior instance was successfully reordered") +{ + Component *inst = dynamic_cast(Sim::findObject(argv[1])); + + if (inst == NULL) + return false; + + U32 idx = 0; + if (argc > 2) + idx = dAtoi(argv[2]); + + return object->reOrder(inst, idx); +}*/ + +ConsoleMethod(Entity, getComponentCount, S32, 2, 2, "() - Get the count of behaviors on an object\n" + "@return (int count) The number of behaviors on an object") +{ + return object->getComponentCount(); +} + +DefineConsoleMethod(Entity, setComponentDirty, void, (S32 componentID, bool forceUpdate), (0, false), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + /*Component* comp; + if (Sim::findObject(componentID, comp)) + object->setComponentDirty(comp, forceUpdate);*/ +} + +DefineConsoleMethod(Entity, getMoveVector, VectorF, (),, + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getControllingClient() != NULL) + { + //fetch our last move + if (object->lastMove.x != 0 || object->lastMove.y != 0 || object->lastMove.z != 0) + return VectorF(object->lastMove.x, object->lastMove.y, object->lastMove.z); + } + + return VectorF::Zero; +} + +DefineConsoleMethod(Entity, getMoveRotation, VectorF, (), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + if(object->getControllingClient() != NULL) + { + //fetch our last move + if (object->lastMove.pitch != 0 || object->lastMove.roll != 0 || object->lastMove.yaw != 0) + return VectorF(object->lastMove.pitch, object->lastMove.roll, object->lastMove.yaw); + } + + return VectorF::Zero; +} + +DefineConsoleMethod(Entity, getMoveTrigger, bool, (S32 triggerNum), (0), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getControllingClient() != NULL && triggerNum < MaxTriggerKeys) + { + return object->lastMove.trigger[triggerNum]; + } + + return false; +} + +DefineConsoleMethod(Entity, setForwardVector, void, (VectorF newForward), (VectorF(0,0,0)), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + object->setForwardVector(newForward); +} + +DefineConsoleMethod(Entity, lookAt, void, (Point3F lookPosition),, + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + //object->setForwardVector(newForward); +} + +DefineConsoleMethod(Entity, rotateTo, void, (Point3F lookPosition, F32 degreePerSecond), (1.0), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + //object->setForwardVector(newForward); +} \ No newline at end of file diff --git a/Engine/source/T3D/Entity.h b/Engine/source/T3D/Entity.h new file mode 100644 index 000000000..e2a35bf9f --- /dev/null +++ b/Engine/source/T3D/Entity.h @@ -0,0 +1,287 @@ +//----------------------------------------------------------------------------- +// 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 ENTITY_H +#define ENTITY_H + +#ifndef _GAMEBASE_H_ +#include "T3D/gameBase/gameBase.h" +#endif +#ifndef _MOVEMANAGER_H_ +#include "T3D/gameBase/moveManager.h" +#endif +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef MROTATION_H +#include "math/mRotation.h" +#endif +#ifndef _CONTAINERQUERY_H_ +#include "T3D/containerQuery.h" +#endif + +//************************************************************************** +// Entity +//************************************************************************** +class Entity : public GameBase +{ + typedef GameBase Parent; + friend class Component; + +private: + Point3F mPos; + RotationF mRot; + + Vector mComponents; + + Vector mToLoadComponents; + + bool mStartComponentUpdate; + + ContainerQueryInfo containerInfo; + + bool mInitialized; + + Signal< void(Component*) > Entity::onComponentAdded; + Signal< void(Component*) > Entity::onComponentRemoved; + + Signal< void(MatrixF*) > Entity::onTransformSet; + +protected: + + virtual void processTick(const Move* move); + virtual void advanceTime(F32 dt); + virtual void interpolateTick(F32 delta); + + void prepRenderImage(SceneRenderState *state); + + virtual bool onAdd(); + virtual void onRemove(); + +public: + struct StateDelta + { + Move move; ///< Last move from server + F32 dt; ///< Last interpolation time + // Interpolation data + Point3F pos; + Point3F posVec; + QuatF rot[2]; + // Warp data + S32 warpTicks; ///< Number of ticks to warp + S32 warpCount; ///< Current pos in warp + Point3F warpOffset; + QuatF warpRot[2]; + }; + + enum MaskBits + { + TransformMask = Parent::NextFreeMask << 0, + BoundsMask = Parent::NextFreeMask << 1, + ComponentsMask = Parent::NextFreeMask << 2, + NoWarpMask = Parent::NextFreeMask << 3, + NextFreeMask = Parent::NextFreeMask << 4 + }; + + StateDelta mDelta; + S32 mPredictionCount; ///< Number of ticks to predict + + Move lastMove; + + // + Entity(); + ~Entity(); + + static void initPersistFields(); + virtual void onPostAdd(); + + virtual void setTransform(const MatrixF &mat); + virtual void setRenderTransform(const MatrixF &mat); + + void setTransform(Point3F position, RotationF rotation); + + void setRenderTransform(Point3F position, RotationF rotation); + + virtual MatrixF getTransform(); + virtual Point3F getPosition() const { return mPos; } + + //void setTransform(Point3F position, RotationF rot); + + //void setRotation(RotationF rotation); + + void setRotation(RotationF rotation) { + mRot = rotation; + setMaskBits(TransformMask); + }; + RotationF getRotation() { return mRot; } + + void setMountOffset(Point3F posOffset); + void setMountRotation(EulerF rotOffset); + + //static bool _setEulerRotation( void *object, const char *index, const char *data ); + static bool _setPosition(void *object, const char *index, const char *data); + static const char * _getPosition(void* obj, const char* data); + + static bool _setRotation(void *object, const char *index, const char *data); + static const char * _getRotation(void* obj, const char* data); + + virtual void getMountTransform(S32 index, const MatrixF &xfm, MatrixF *outMat); + virtual void getRenderMountTransform(F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat); + + void setForwardVector(VectorF newForward, VectorF upVector = VectorF::Zero); + + virtual void mountObject(SceneObject *obj, S32 node, const MatrixF &xfm = MatrixF::Identity); + void mountObject(SceneObject* objB, MatrixF txfm); + void onMount(SceneObject *obj, S32 node); + void onUnmount(SceneObject *obj, S32 node); + + // NetObject + U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream); + void unpackUpdate(NetConnection *conn, BitStream *stream); + + void setComponentsDirty(); + void setComponentDirty(Component *comp, bool forceUpdate = false); + + //Components + virtual bool deferAddingComponents() const { return true; } + + template + T* getComponent(); + template + Vector getComponents(); + + Component* getComponent(String componentType); + + U32 getComponentCount() const + { + return mComponents.size(); + } + + virtual void setObjectBox(Box3F objBox); + + void resetWorldBox() { Parent::resetWorldBox(); } + void resetObjectBox() { Parent::resetObjectBox(); } + void resetRenderWorldBox() { Parent::resetRenderWorldBox(); } + + //function redirects for collisions + bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); + bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo* info); + bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere); + virtual void buildConvex(const Box3F& box, Convex* convex); + + Signal< void(SimObject*, String, String) > onDataSet; + virtual void setDataField(StringTableEntry slotName, const char *array, const char *value); + virtual void onStaticModified(const char* slotName, const char* newValue); + + //void pushEvent(const char* eventName, Vector eventParams); + + void updateContainer(); + + ContainerQueryInfo getContainerInfo() { return containerInfo; } + + //camera stuff + virtual void getCameraTransform(F32* pos, MatrixF* mat); + virtual void onCameraScopeQuery(NetConnection* connection, CameraScopeQuery* query); + + //Heirarchy stuff + virtual void addObject(SimObject* object); + virtual void removeObject(SimObject* object); + + virtual SimObject* findObjectByInternalName(StringTableEntry internalName, bool searchChildren); + + //component stuff + bool addComponent(Component *comp); + bool removeComponent(Component *comp, bool deleteComponent); + void clearComponents(bool deleteComponents = true); + Component* getComponent(const U32 index) const; + + void onInspect(); + void onEndInspect(); + + virtual void write(Stream &stream, U32 tabStop, U32 flags); + + // TamlChildren + virtual U32 getTamlChildCount(void) const + { + U32 componentCount = getComponentCount(); + U32 childSize = (U32)size(); + return componentCount + childSize; + } + + virtual SimObject* getTamlChild(const U32 childIndex) const; + + virtual void addTamlChild(SimObject* pSimObject) + { + // Sanity! + AssertFatal(pSimObject != NULL, "SimSet::addTamlChild() - Cannot add a NULL child object."); + + addObject(pSimObject); + } + + Box3F getObjectBox() { return mObjBox; } + MatrixF getWorldToObj() { return mWorldToObj; } + MatrixF getObjToWorld() { return mObjToWorld; } + + DECLARE_CONOBJECT(Entity); + +}; + +template +T *Entity::getComponent() +{ + U32 componentCount = getComponentCount(); + for (U32 i = 0; i < componentCount; i++) + { + T* t = dynamic_cast(mComponents[i]); + + if (t) + { + return t; + } + } + return NULL; +} + +template +Vector Entity::getComponents() +{ + Vector foundObjects; + + T *curObj; + Component* comp; + + // Loop through our child objects. + for (U32 i = 0; i < mComponents.size(); i++) + { + if (!mComponents[i]->isEnabled()) + continue; + + curObj = dynamic_cast(mComponents[i]); + + // Add this child object if appropriate. + if (curObj) + foundObjects.push_back(curObj); + } + + return foundObjects; +} +#endif //ENTITY_H diff --git a/Engine/source/T3D/objectTypes.h b/Engine/source/T3D/objectTypes.h index e65745e1b..5f3266708 100644 --- a/Engine/source/T3D/objectTypes.h +++ b/Engine/source/T3D/objectTypes.h @@ -147,21 +147,25 @@ enum SceneObjectTypes /// @see PhysicalZone PhysicalZoneObjectType = BIT( 22 ), + EntityObjectType = BIT(23), /// @} }; enum SceneObjectTypeMasks { - STATIC_COLLISION_TYPEMASK = StaticShapeObjectType, + STATIC_COLLISION_TYPEMASK = (StaticShapeObjectType | + EntityObjectType), DAMAGEABLE_TYPEMASK = ( PlayerObjectType | + EntityObjectType | VehicleObjectType ), /// Typemask for objects that should be rendered into shadow passes. /// These should be all objects that are either meant to receive or cast /// shadows or both. SHADOW_TYPEMASK = ( StaticShapeObjectType | - DynamicShapeObjectType ), + DynamicShapeObjectType | + EntityObjectType), /// Typemask for objects that should be subjected to more fine-grained /// culling tests. Anything that is trivial rendering stuff or doesn't @@ -172,6 +176,7 @@ enum SceneObjectTypeMasks CULLING_INCLUDE_TYPEMASK = ( GameBaseObjectType | // Includes most other renderable types; but broader than we ideally want. StaticShapeObjectType | DynamicShapeObjectType | + EntityObjectType | ZoneObjectType ), // This improves the result of zone traversals. /// Mask for objects that should be specifically excluded from zone culling. @@ -185,7 +190,9 @@ enum SceneObjectTypeMasks StaticShapeObjectType | DynamicShapeObjectType | LightObjectType | // Flares. - GameBaseObjectType ), + GameBaseObjectType | + TriggerObjectType | + EntityObjectType), /// Typemask to use for rendering when inside the editor. EDITOR_RENDER_TYPEMASK = U32( -1 ), From fa78a2f3547a6be8d95009221dae593c0f834a3e Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 00:00:02 -0500 Subject: [PATCH 30/71] Adds Component, the various main component classes and their interfaces. --- .../Animation/animationComponent.cpp | 715 +++++++++++++++ .../components/Animation/animationComponent.h | 138 +++ .../animationComponent_ScriptBinding.h | 222 +++++ .../T3D/components/Camera/CameraComponent.cpp | 483 ++++++++++ .../T3D/components/Camera/CameraComponent.h | 159 ++++ .../Camera/CameraComponent_ScriptBinding.h | 91 ++ .../Camera/CameraOrbiterComponent.cpp | 146 +++ .../Camera/CameraOrbiterComponent.h | 71 ++ .../CollisionComponent_ScriptBinding.h | 172 ++++ .../Collision/collisionComponent.cpp | 582 ++++++++++++ .../components/Collision/collisionComponent.h | 208 +++++ .../Collision/collisionInterfaces.cpp | 258 ++++++ .../Collision/collisionInterfaces.h | 167 ++++ .../components/Collision/collisionTrigger.cpp | 619 +++++++++++++ .../components/Collision/collisionTrigger.h | 145 +++ Engine/source/T3D/components/Component.cpp | 638 +++++++++++++ Engine/source/T3D/components/Component.h | 197 ++++ .../components/Game/StateMachineComponent.cpp | 215 +++++ .../components/Game/StateMachineComponent.h | 81 ++ .../T3D/components/Game/stateMachine.cpp | 434 +++++++++ .../source/T3D/components/Game/stateMachine.h | 259 ++++++ .../T3D/components/Game/triggerComponent.cpp | 358 ++++++++ .../T3D/components/Game/triggerComponent.h | 74 ++ .../components/Physics/physicsBehavior.cpp | 368 ++++++++ .../T3D/components/Physics/physicsBehavior.h | 135 +++ .../Physics/physicsComponentInterface.cpp | 0 .../Physics/physicsComponentInterface.h | 49 + .../Physics/playerControllerComponent.cpp | 863 ++++++++++++++++++ .../Physics/playerControllerComponent.h | 212 +++++ .../components/Physics/rigidBodyComponent.cpp | 467 ++++++++++ .../components/Physics/rigidBodyComponent.h | 183 ++++ .../T3D/components/Render/MeshComponent.cpp | 524 +++++++++++ .../T3D/components/Render/MeshComponent.h | 183 ++++ .../Render/MeshComponent_ScriptBinding.h | 155 ++++ .../Render/renderComponentInterface.h | 62 ++ Engine/source/T3D/components/coreInterfaces.h | 101 ++ Engine/source/console/consoleObject.h | 2 + 37 files changed, 9736 insertions(+) create mode 100644 Engine/source/T3D/components/Animation/animationComponent.cpp create mode 100644 Engine/source/T3D/components/Animation/animationComponent.h create mode 100644 Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h create mode 100644 Engine/source/T3D/components/Camera/CameraComponent.cpp create mode 100644 Engine/source/T3D/components/Camera/CameraComponent.h create mode 100644 Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h create mode 100644 Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp create mode 100644 Engine/source/T3D/components/Camera/CameraOrbiterComponent.h create mode 100644 Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h create mode 100644 Engine/source/T3D/components/Collision/collisionComponent.cpp create mode 100644 Engine/source/T3D/components/Collision/collisionComponent.h create mode 100644 Engine/source/T3D/components/Collision/collisionInterfaces.cpp create mode 100644 Engine/source/T3D/components/Collision/collisionInterfaces.h create mode 100644 Engine/source/T3D/components/Collision/collisionTrigger.cpp create mode 100644 Engine/source/T3D/components/Collision/collisionTrigger.h create mode 100644 Engine/source/T3D/components/Component.cpp create mode 100644 Engine/source/T3D/components/Component.h create mode 100644 Engine/source/T3D/components/Game/StateMachineComponent.cpp create mode 100644 Engine/source/T3D/components/Game/StateMachineComponent.h create mode 100644 Engine/source/T3D/components/Game/stateMachine.cpp create mode 100644 Engine/source/T3D/components/Game/stateMachine.h create mode 100644 Engine/source/T3D/components/Game/triggerComponent.cpp create mode 100644 Engine/source/T3D/components/Game/triggerComponent.h create mode 100644 Engine/source/T3D/components/Physics/physicsBehavior.cpp create mode 100644 Engine/source/T3D/components/Physics/physicsBehavior.h create mode 100644 Engine/source/T3D/components/Physics/physicsComponentInterface.cpp create mode 100644 Engine/source/T3D/components/Physics/physicsComponentInterface.h create mode 100644 Engine/source/T3D/components/Physics/playerControllerComponent.cpp create mode 100644 Engine/source/T3D/components/Physics/playerControllerComponent.h create mode 100644 Engine/source/T3D/components/Physics/rigidBodyComponent.cpp create mode 100644 Engine/source/T3D/components/Physics/rigidBodyComponent.h create mode 100644 Engine/source/T3D/components/Render/MeshComponent.cpp create mode 100644 Engine/source/T3D/components/Render/MeshComponent.h create mode 100644 Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h create mode 100644 Engine/source/T3D/components/Render/renderComponentInterface.h create mode 100644 Engine/source/T3D/components/coreInterfaces.h diff --git a/Engine/source/T3D/components/Animation/animationComponent.cpp b/Engine/source/T3D/components/Animation/animationComponent.cpp new file mode 100644 index 000000000..a43eedd7a --- /dev/null +++ b/Engine/source/T3D/components/Animation/animationComponent.cpp @@ -0,0 +1,715 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Animation/AnimationComponent.h" +#include "T3D/Components/Animation/AnimationComponent_ScriptBinding.h" +#include "T3D/components/Render/MeshComponent.h" + +#include "platform/platform.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "ts/tsShapeInstance.h" +#include "core/stream/bitStream.h" +#include "sim/netConnection.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" +#include "gfx/sim/debugDraw.h" + +extern bool gEditingMission; + +////////////////////////////////////////////////////////////////////////// +// Callbacks +////////////////////////////////////////////////////////////////////////// +IMPLEMENT_CALLBACK( AnimationComponent, onAnimationStart, void, ( Component* obj, const String& animName ), ( obj, animName ), + "@brief Called when we collide with another object.\n\n" + "@param obj The ShapeBase object\n" + "@param collObj The object we collided with\n" + "@param vec Collision impact vector\n" + "@param len Length of the impact vector\n" ); + +IMPLEMENT_CALLBACK(AnimationComponent, onAnimationEnd, void, (Component* obj, const char* animName), (obj, animName), + "@brief Called when we collide with another object.\n\n" + "@param obj The ShapeBase object\n" + "@param collObj The object we collided with\n" + "@param vec Collision impact vector\n" + "@param len Length of the impact vector\n" ); + +IMPLEMENT_CALLBACK(AnimationComponent, onAnimationTrigger, void, (Component* obj, const String& animName, S32 triggerID), (obj, animName, triggerID), + "@brief Called when we collide with another object.\n\n" + "@param obj The ShapeBase object\n" + "@param collObj The object we collided with\n" + "@param vec Collision impact vector\n" + "@param len Length of the impact vector\n" ); + + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +AnimationComponent::AnimationComponent() : Component() +{ + mNetworked = true; + mNetFlags.set(Ghostable | ScopeAlways); + + mFriendlyName = "Animation(Component)"; + mComponentType = "Render"; + + mDescription = getDescriptionText("Allows a rendered mesh to be animated"); + + mOwnerRenderInst = NULL; + + mOwnerShapeInstance = NULL; + + for (U32 i = 0; i < MaxScriptThreads; i++) + { + mAnimationThreads[i].sequence = -1; + mAnimationThreads[i].thread = 0; + mAnimationThreads[i].sound = 0; + mAnimationThreads[i].state = Thread::Stop; + mAnimationThreads[i].atEnd = false; + mAnimationThreads[i].timescale = 1.f; + mAnimationThreads[i].position = -1.f; + mAnimationThreads[i].transition = true; + } +} + +AnimationComponent::~AnimationComponent() +{ + for(S32 i = 0;i < mFields.size();++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(AnimationComponent); + +bool AnimationComponent::onAdd() +{ + if (!Parent::onAdd()) + return false; + + //we need at least one layer + for (U32 i = 0; i < MaxScriptThreads; i++) + { + Thread& st = mAnimationThreads[i]; + + if (st.sequence != -1) + { + // TG: Need to see about suppressing non-cyclic sounds + // if the sequences were activated before the object was + // ghosted. + // TG: Cyclic animations need to have a random pos if + // they were started before the object was ghosted. + + // If there was something running on the old shape, the thread + // needs to be reset. Otherwise we assume that it's been + // initialized either by the constructor or from the server. + bool reset = st.thread != 0; + st.thread = 0; + + if (st.sequence != -1) + { + setThreadSequence(i, st.sequence, reset); + } + } + + if (st.thread) + updateThread(st); + } + + return true; +} + +void AnimationComponent::onRemove() +{ + Parent::onRemove(); +} + +void AnimationComponent::onComponentAdd() +{ + //test if this is a shape component! + RenderComponentInterface *shapeInstanceInterface = mOwner->getComponent(); + if (shapeInstanceInterface) + { + shapeInstanceInterface->onShapeInstanceChanged.notify(this, &AnimationComponent::targetShapeChanged); + targetShapeChanged(shapeInstanceInterface); + } +} + +void AnimationComponent::componentAddedToOwner(Component *comp) +{ + if (comp->getId() == getId()) + return; + + //test if this is a shape component! + RenderComponentInterface *shapeInstanceInterface = dynamic_cast(comp); + if (shapeInstanceInterface) + { + shapeInstanceInterface->onShapeInstanceChanged.notify(this, &AnimationComponent::targetShapeChanged); + targetShapeChanged(shapeInstanceInterface); + } +} + +void AnimationComponent::componentRemovedFromOwner(Component *comp) +{ + if (comp->getId() == getId()) //????????? + return; + + //test if this is a shape component! + RenderComponentInterface *shapeInstanceInterface = dynamic_cast(comp); + if (shapeInstanceInterface) + { + shapeInstanceInterface->onShapeInstanceChanged.remove(this, &AnimationComponent::targetShapeChanged); + mOwnerRenderInst = NULL; + } +} + +void AnimationComponent::targetShapeChanged(RenderComponentInterface* instanceInterface) +{ + mOwnerRenderInst = instanceInterface; + + if (!mOwnerRenderInst || !getShape()) + return; + + MeshComponent* meshComp = dynamic_cast(mOwnerRenderInst); + + mOwnerShapeInstance = meshComp->getShapeInstance(); + + if (!mOwnerShapeInstance) + return; + + for (U32 i = 0; i < MaxScriptThreads; i++) + { + Thread& st = mAnimationThreads[i]; + + st.thread = mOwnerShapeInstance->addThread(); + } +} + +void AnimationComponent::initPersistFields() +{ + Parent::initPersistFields(); +} + +U32 AnimationComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + //early test if we lack an owner, ghost-wise + //no point in trying, just re-queue the mask and go + if (!mOwner || con->getGhostIndex(mOwner) == -1) + { + stream->writeFlag(false); + return retMask |= ThreadMask; + } + else + { + stream->writeFlag(true); + + for (int i = 0; i < MaxScriptThreads; i++) + { + Thread& st = mAnimationThreads[i]; + if (stream->writeFlag( (st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i)) ) ) + { + stream->writeInt(st.sequence,ThreadSequenceBits); + stream->writeInt(st.state,2); + stream->write(st.timescale); + stream->write(st.position); + stream->writeFlag(st.atEnd); + stream->writeFlag(st.transition); + } + } + } + + return retMask; +} + +void AnimationComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) + { + for (S32 i = 0; i < MaxScriptThreads; i++) + { + if (stream->readFlag()) + { + Thread& st = mAnimationThreads[i]; + U32 seq = stream->readInt(ThreadSequenceBits); + st.state = stream->readInt(2); + stream->read( &st.timescale ); + stream->read( &st.position ); + st.atEnd = stream->readFlag(); + bool transition = stream->readFlag(); + + if (!st.thread || st.sequence != seq && st.state != Thread::Destroy) + setThreadSequence(i, seq, false, transition); + else + updateThread(st); + + } + } + } +} +void AnimationComponent::processTick() +{ + Parent::processTick(); + + if (!isActive()) + return; + + if (isServerObject()) + { + // Server only... + advanceThreads(TickSec); + } +} + +void AnimationComponent::advanceTime(F32 dt) +{ + Parent::advanceTime(dt); + + // On the client, the shape threads and images are + // advanced at framerate. + advanceThreads(dt); +} +// +const char *AnimationComponent::getThreadSequenceName(U32 slot) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence == -1) + { + // Invalid Animation. + return ""; + } + + // Name Index + TSShape* shape = getShape(); + + if (shape) + { + const U32 nameIndex = shape->sequences[st.sequence].nameIndex; + + // Return Name. + return shape->getName(nameIndex); + } + + return ""; +} + +bool AnimationComponent::setThreadSequence(U32 slot, S32 seq, bool reset, bool transition, F32 transTime) +{ + if (!mOwnerShapeInstance) + return false; + + Thread& st = mAnimationThreads[slot]; + if (st.thread && st.sequence == seq && st.state == Thread::Play && !reset) + return true; + + // Handle a -1 sequence, as this may be set when a thread has been destroyed. + if (seq == -1) + return true; + + if (seq < MaxSequenceIndex) + { + setMaskBits(-1); + setMaskBits(ThreadMaskN << slot); + st.sequence = seq; + st.transition = transition; + + if (reset) + { + st.state = Thread::Play; + st.atEnd = false; + st.timescale = 1.f; + st.position = 0.f; + } + + if (mOwnerShapeInstance) + { + if (!st.thread) + st.thread = mOwnerShapeInstance->addThread(); + + if (transition) + { + mOwnerShapeInstance->transitionToSequence(st.thread, seq, st.position, transTime, true); + } + else + { + mOwnerShapeInstance->setSequence(st.thread, seq, 0); + stopThreadSound(st); + } + + updateThread(st); + } + return true; + } + return false; +} + +S32 AnimationComponent::getThreadSequenceID(S32 slot) +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + return mAnimationThreads[slot].sequence; + } + else + { + return -1; + } +} + +void AnimationComponent::updateThread(Thread& st) +{ + if (!mOwnerShapeInstance) + return; + + switch (st.state) + { + case Thread::Stop: + { + mOwnerShapeInstance->setTimeScale(st.thread, 1.f); + mOwnerShapeInstance->setPos(st.thread, (st.timescale > 0.f) ? 0.0f : 1.0f); + } // Drop through to pause state + + case Thread::Pause: + { + if (st.position != -1.f) + { + mOwnerShapeInstance->setTimeScale(st.thread, 1.f); + mOwnerShapeInstance->setPos(st.thread, st.position); + } + + mOwnerShapeInstance->setTimeScale(st.thread, 0.f); + stopThreadSound(st); + } break; + + case Thread::Play: + { + if (st.atEnd) + { + mOwnerShapeInstance->setTimeScale(st.thread, 1); + mOwnerShapeInstance->setPos(st.thread, (st.timescale > 0.f) ? 1.0f : 0.0f); + mOwnerShapeInstance->setTimeScale(st.thread, 0); + stopThreadSound(st); + st.state = Thread::Stop; + } + else + { + if (st.position != -1.f) + { + mOwnerShapeInstance->setTimeScale(st.thread, 1.f); + mOwnerShapeInstance->setPos(st.thread, st.position); + } + + mOwnerShapeInstance->setTimeScale(st.thread, st.timescale); + if (!st.sound) + { + startSequenceSound(st); + } + } + } break; + + case Thread::Destroy: + { + stopThreadSound(st); + st.atEnd = true; + st.sequence = -1; + if (st.thread) + { + mOwnerShapeInstance->destroyThread(st.thread); + st.thread = 0; + } + } break; + } +} + +bool AnimationComponent::stopThread(U32 slot) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1 && st.state != Thread::Stop) + { + setMaskBits(ThreadMaskN << slot); + st.state = Thread::Stop; + updateThread(st); + return true; + } + return false; +} + +bool AnimationComponent::destroyThread(U32 slot) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1 && st.state != Thread::Destroy) + { + setMaskBits(ThreadMaskN << slot); + st.state = Thread::Destroy; + updateThread(st); + return true; + } + return false; +} + +bool AnimationComponent::pauseThread(U32 slot) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1 && st.state != Thread::Pause) + { + setMaskBits(ThreadMaskN << slot); + st.state = Thread::Pause; + updateThread(st); + return true; + } + return false; +} + +bool AnimationComponent::playThread(U32 slot) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1 && st.state != Thread::Play) + { + setMaskBits(ThreadMaskN << slot); + st.state = Thread::Play; + updateThread(st); + return true; + } + return false; +} + +bool AnimationComponent::playThread(U32 slot, const char* name, bool transition, F32 transitionTime) +{ + if (slot < AnimationComponent::MaxScriptThreads) + { + if (!dStrEqual(name, "")) + { + if (TSShape* shape = getShape()) + { + S32 seq = shape->findSequence(name); + if (seq != -1 && setThreadSequence(slot, seq, true, transition, transitionTime)) + { + return true; + } + else if (seq == -1) + { + //We tried to play a non-existaint sequence, so stop the thread just in case + destroyThread(slot); + return false; + } + } + } + else + { + if (playThread(slot)) + return true; + } + } + + return false; +} + +bool AnimationComponent::setThreadAnimation(U32 slot, const char* name) +{ + if (slot < AnimationComponent::MaxScriptThreads) + { + if (!dStrEqual(name, "")) + { + if (TSShape* shape = getShape()) + { + S32 seq = shape->findSequence(name); + if (seq != -1 && setThreadSequence(slot, seq, false, false)) + { + Thread& st = mAnimationThreads[slot]; + if (st.position == -1) + st.position = 0; + //st.state = Thread::Pause; + return true; + } + else if (seq == -1) + { + //We tried to play a non-existaint sequence, so stop the thread just in case + destroyThread(slot); + return false; + } + } + } + else + { + if (playThread(slot)) + return true; + } + } + + return false; +} + +bool AnimationComponent::setThreadPosition(U32 slot, F32 pos) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1) + { + setMaskBits(ThreadMaskN << slot); + st.position = pos; + st.atEnd = false; + updateThread(st); + + return true; + } + return false; +} + +bool AnimationComponent::setThreadDir(U32 slot, bool forward) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1) + { + if ((st.timescale >= 0.f) != forward) + { + setMaskBits(ThreadMaskN << slot); + st.timescale *= -1.f; + st.atEnd = false; + updateThread(st); + } + return true; + } + return false; +} + +bool AnimationComponent::setThreadTimeScale(U32 slot, F32 timeScale) +{ + Thread& st = mAnimationThreads[slot]; + if (st.sequence != -1) + { + if (st.timescale != timeScale) + { + setMaskBits(ThreadMaskN << slot); + st.timescale = timeScale; + updateThread(st); + } + return true; + } + return false; +} + +void AnimationComponent::stopThreadSound(Thread& thread) +{ + return; +} + +void AnimationComponent::startSequenceSound(Thread& thread) +{ + return; +} + +void AnimationComponent::advanceThreads(F32 dt) +{ + if (!mOwnerShapeInstance) + return; + + for (U32 i = 0; i < MaxScriptThreads; i++) + { + Thread& st = mAnimationThreads[i]; + if (st.thread && st.sequence != -1) + { + bool cyclic = getShape()->sequences[st.sequence].isCyclic(); + + if (!getShape()->sequences[st.sequence].isCyclic() && + !st.atEnd && + ((st.timescale > 0.f) ? mOwnerShapeInstance->getPos(st.thread) >= 1.0 : mOwnerShapeInstance->getPos(st.thread) <= 0)) + { + st.atEnd = true; + updateThread(st); + + if (!isGhost()) + { + Con::executef(this, "onAnimationEnd", st.thread->getSequenceName()); + } + } + + // Make sure the thread is still valid after the call to onEndSequence_callback(). + // Someone could have called destroyThread() while in there. + if (st.thread) + { + mOwnerShapeInstance->advanceTime(dt, st.thread); + } + + if (mOwnerShapeInstance && !isGhost()) + { + for (U32 i = 1; i < 32; i++) + { + if (mOwnerShapeInstance->getTriggerState(i)) + { + const char* animName = st.thread->getSequenceName().c_str(); + onAnimationTrigger_callback(this, animName, i); + } + } + } + + if (isGhost()) + mOwnerShapeInstance->animate(); + } + } +} + +TSShape* AnimationComponent::getShape() +{ + if (mOwner == NULL) + return NULL; + + if (mOwnerRenderInst == NULL) + return NULL; + + return mOwnerRenderInst->getShape(); +} + +S32 AnimationComponent::getAnimationCount() +{ + if (getShape()) + return getShape()->sequences.size(); + else + return 0; +} + +S32 AnimationComponent::getAnimationIndex(const char* name) +{ + if (getShape()) + return getShape()->findSequence(name); + else + return -1; +} + +const char* AnimationComponent::getAnimationName(S32 index) +{ + if (getShape()) + { + if (index >= 0 && index < getShape()->sequences.size()) + return getShape()->getName(getShape()->sequences[index].nameIndex); + } + + return ""; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Animation/animationComponent.h b/Engine/source/T3D/components/Animation/animationComponent.h new file mode 100644 index 000000000..7e9378899 --- /dev/null +++ b/Engine/source/T3D/components/Animation/animationComponent.h @@ -0,0 +1,138 @@ +//----------------------------------------------------------------------------- +// 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 ANIMATION_COMPONENT_H +#define ANIMATION_COMPONENT_H + +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef _TSSHAPE_H_ +#include "ts/tsShapeInstance.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef RENDER_COMPONENT_INTERFACE_H +#include "T3D/Components/render/renderComponentInterface.h" +#endif + +class SceneRenderState; + +class AnimationComponent : public Component +{ + typedef Component Parent; +public: + enum PublicConstants { + ThreadSequenceBits = 6, + MaxSequenceIndex = (1 << ThreadSequenceBits) - 1, + MaxScriptThreads = 16, ///< Should be a power of 2 + }; + + enum MaskBits { + ThreadMaskN = Parent::NextFreeMask << 0, + ThreadMask = (ThreadMaskN << MaxScriptThreads) - ThreadMaskN, + NextFreeMask = ThreadMaskN << MaxScriptThreads + }; + +protected: + + struct Thread + { + /// State of the animation thread. + enum State + { + Play, Stop, Pause, Destroy + }; + TSThread* thread; ///< Pointer to 3space data. + U32 state; ///< State of the thread + /// + /// @see Thread::State + S32 sequence; ///< The animation sequence which is running in this thread. + F32 timescale; ///< Timescale + U32 sound; ///< Handle to sound. + bool atEnd; ///< Are we at the end of this thread? + F32 position; + bool transition; + }; + + Thread mAnimationThreads[MaxScriptThreads]; + +protected: + RenderComponentInterface * mOwnerRenderInst; + + TSShapeInstance *mOwnerShapeInstance; + +public: + AnimationComponent(); + virtual ~AnimationComponent(); + DECLARE_CONOBJECT(AnimationComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + TSShape* getShape(); + + void targetShapeChanged(RenderComponentInterface* instanceInterface); + + virtual void processTick(); + virtual void advanceTime(F32 dt); + + const char *getThreadSequenceName(U32 slot); + bool setThreadSequence(U32 slot, S32 seq, bool reset = true, bool transition = true, F32 transitionTime = 0.5); + void updateThread(Thread& st); + bool stopThread(U32 slot); + bool destroyThread(U32 slot); + bool pauseThread(U32 slot); + bool playThread(U32 slot); + bool playThread(U32 slot, const char* name, bool transition, F32 transitionTime); + bool setThreadAnimation(U32 slot, const char* name); + bool setThreadPosition(U32 slot, F32 pos); + bool setThreadDir(U32 slot, bool forward); + bool setThreadTimeScale(U32 slot, F32 timeScale); + void stopThreadSound(Thread& thread); + void startSequenceSound(Thread& thread); + void advanceThreads(F32 dt); + + S32 getThreadSequenceID(S32 slot); + + //other helper functions + S32 getAnimationCount(); + S32 getAnimationIndex(const char* name); + const char* getAnimationName(S32 index); + + //callbacks + DECLARE_CALLBACK(void, onAnimationStart, (Component* obj, const String& animName)); + DECLARE_CALLBACK(void, onAnimationEnd, (Component* obj, const char* animName)); + DECLARE_CALLBACK(void, onAnimationTrigger, (Component* obj, const String& animName, S32 triggerID)); +}; + +#endif //_ANIMATION_COMPONENT_H \ No newline at end of file diff --git a/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h b/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h new file mode 100644 index 000000000..ffba3f790 --- /dev/null +++ b/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h @@ -0,0 +1,222 @@ +//----------------------------------------------------------------------------- +// 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 "console/engineAPI.h" +#include "T3D/Components/Animation/animationComponent.h" + +DefineEngineMethod(AnimationComponent, playThread, bool, (S32 slot, const char* name, bool transition, F32 transitionTime), (-1, "", true, 0.5), + "@brief Start a new animation thread, or restart one that has been paused or " + "stopped.\n\n" + + "@param slot thread slot to play. Valid range is 0 - 3)\n" // 3 = AnimationComponent::MaxScriptThreads-1 + "@param name name of the animation sequence to play in this slot. If not " + "specified, the paused or stopped thread in this slot will be resumed.\n" + "@return true if successful, false if failed\n\n" + + "@tsexample\n" + "%obj.playThread( 0, \"ambient\" ); // Play the ambient sequence in slot 0\n" + "%obj.setThreadTimeScale( 0, 0.5 ); // Play at half-speed\n" + "%obj.pauseThread( 0 ); // Pause the sequence\n" + "%obj.playThread( 0 ); // Resume playback\n" + "%obj.playThread( 0, \"spin\" ); // Replace the sequence in slot 0\n" + "@endtsexample\n" + + "@see pauseThread()\n" + "@see stopThread()\n" + "@see setThreadDir()\n" + "@see setThreadTimeScale()\n" + "@see destroyThread()\n") +{ + return object->playThread(slot, name, transition, transitionTime); +} + +DefineEngineMethod(AnimationComponent, setThreadDir, bool, (S32 slot, bool fwd), , + "@brief Set the playback direction of an animation thread.\n\n" + + "@param slot thread slot to modify\n" + "@param fwd true to play the animation forwards, false to play backwards\n" + "@return true if successful, false if failed\n\n" + + "@see playThread()\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->setThreadDir(slot, fwd)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, setThreadTimeScale, bool, (S32 slot, F32 scale), , + "@brief Set the playback time scale of an animation thread.\n\n" + + "@param slot thread slot to modify\n" + "@param scale new thread time scale (1=normal speed, 0.5=half speed etc)\n" + "@return true if successful, false if failed\n\n" + + "@see playThread\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->setThreadTimeScale(slot, scale)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, setThreadPosition, bool, (S32 slot, F32 pos), , + "@brief Set the position within an animation thread.\n\n" + + "@param slot thread slot to modify\n" + "@param pos position within thread\n" + "@return true if successful, false if failed\n\n" + + "@see playThread\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->setThreadPosition(slot, pos)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, setThreadAnimation, bool, (S32 slot, const char* name), (""), + "@brief Force-sets the animation in a particular thread without starting it playing." + + "@param slot thread slot to play. Valid range is 0 - 3)\n" // 3 = AnimationComponent::MaxScriptThreads-1 + "@param name name of the animation sequence to play in this slot. If not " + "specified, the paused or stopped thread in this slot will be resumed.\n" + "@return true if successful, false if failed\n\n") +{ + return object->setThreadAnimation(slot, name); +} + +DefineEngineMethod(AnimationComponent, getThreadAnimation, String, (S32 slot), , + "@brief Force-sets the animation in a particular thread without starting it playing." + + "@param slot thread slot to play. Valid range is 0 - 3)\n" // 3 = AnimationComponent::MaxScriptThreads-1 + "@param name name of the animation sequence to play in this slot. If not " + "specified, the paused or stopped thread in this slot will be resumed.\n" + "@return true if successful, false if failed\n\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (TSShape* shape = object->getShape()) + { + S32 seq = object->getThreadSequenceID(slot); + if (seq != -1) + { + String animationName = object->getAnimationName(seq); + return animationName; + } + } + } + + return ""; +} + +DefineEngineMethod(AnimationComponent, stopThread, bool, (S32 slot), , + "@brief Stop an animation thread.\n\n" + + "If restarted using playThread, the animation " + "will start from the beginning again.\n" + "@param slot thread slot to stop\n" + "@return true if successful, false if failed\n\n" + + "@see playThread\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->stopThread(slot)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, destroyThread, bool, (S32 slot), , + "@brief Destroy an animation thread, which prevents it from playing.\n\n" + + "@param slot thread slot to destroy\n" + "@return true if successful, false if failed\n\n" + + "@see playThread\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->destroyThread(slot)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, pauseThread, bool, (S32 slot), , + "@brief Pause an animation thread.\n\n" + + "If restarted using playThread, the animation " + "will resume from the paused position.\n" + "@param slot thread slot to stop\n" + "@return true if successful, false if failed\n\n" + + "@see playThread\n") +{ + if (slot >= 0 && slot < AnimationComponent::MaxScriptThreads) + { + if (object->pauseThread(slot)) + return true; + } + return false; +} + +DefineEngineMethod(AnimationComponent, getAnimationCount, S32, (), , + "Get the total number of sequences in the shape.\n" + "@return the number of sequences in the shape\n\n") +{ + return object->getAnimationCount(); +} + +DefineEngineMethod(AnimationComponent, getAnimationIndex, S32, (const char* name), , + "Find the index of the sequence with the given name.\n" + "@param name name of the sequence to lookup\n" + "@return index of the sequence with matching name, or -1 if not found\n\n" + "@tsexample\n" + "// Check if a given sequence exists in the shape\n" + "if ( %this.getSequenceIndex( \"walk\" ) == -1 )\n" + " echo( \"Could not find 'walk' sequence\" );\n" + "@endtsexample\n") +{ + return object->getAnimationIndex(name); +} + +DefineEngineMethod(AnimationComponent, getAnimationName, const char*, (S32 index), , + "Get the name of the indexed sequence.\n" + "@param index index of the sequence to query (valid range is 0 - getSequenceCount()-1)\n" + "@return the name of the sequence\n\n" + "@tsexample\n" + "// print the name of all sequences in the shape\n" + "%count = %this.getSequenceCount();\n" + "for ( %i = 0; %i < %count; %i++ )\n" + " echo( %i SPC %this.getSequenceName( %i ) );\n" + "@endtsexample\n") +{ + return object->getAnimationName(index); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Camera/CameraComponent.cpp b/Engine/source/T3D/components/Camera/CameraComponent.cpp new file mode 100644 index 000000000..5d914084c --- /dev/null +++ b/Engine/source/T3D/components/Camera/CameraComponent.cpp @@ -0,0 +1,483 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/camera/CameraComponent.h" +#include "T3D/Components/Camera/CameraComponent_ScriptBinding.h" +#include "platform/platform.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "ts/tsShapeInstance.h" +#include "core/stream/bitStream.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" +#include "T3D/gameBase/gameConnection.h" +#include "T3D/gameFunctions.h" +#include "math/mathUtils.h" +#include "T3D/Components/render/renderComponentInterface.h" + +IMPLEMENT_CALLBACK( CameraComponent, validateCameraFov, F32, (F32 fov), (fov), + "@brief Called on the server when the client has requested a FOV change.\n\n" + + "When the client requests that its field of view should be changed (because " + "they want to use a sniper scope, for example) this new FOV needs to be validated " + "by the server. This method is called if it exists (it is optional) to validate " + "the requested FOV, and modify it if necessary. This could be as simple as checking " + "that the FOV falls within a correct range, to making sure that the FOV matches the " + "capabilities of the current weapon.\n\n" + + "Following this method, ShapeBase ensures that the given FOV still falls within " + "the datablock's mCameraMinFov and mCameraMaxFov. If that is good enough for your " + "purposes, then you do not need to define the validateCameraFov() callback for " + "your ShapeBase.\n\n" + + "@param fov The FOV that has been requested by the client.\n" + "@return The FOV as validated by the server.\n\n" + + "@see ShapeBaseData\n\n"); + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// + +CameraComponent::CameraComponent() : Component() +{ + mClientScreen = Point2F(1, 1); + + mCameraFov = mCameraDefaultFov = 80; + mCameraMinFov = 5; + mCameraMaxFov = 175; + + mTargetNodeIdx = -1; + + mPosOffset = Point3F(0, 0, 0); + mRotOffset = EulerF(0, 0, 0); + + mTargetNode = ""; + + mUseParentTransform = true; + + mFriendlyName = "Camera(Component)"; +} + +CameraComponent::~CameraComponent() +{ + for(S32 i = 0;i < mFields.size();++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(CameraComponent); + +bool CameraComponent::onAdd() +{ + if(! Parent::onAdd()) + return false; + + return true; +} + +void CameraComponent::onRemove() +{ + Parent::onRemove(); +} + +void CameraComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addProtectedField("FOV", TypeF32, Offset(mCameraFov, CameraComponent), &_setCameraFov, defaultProtectedGetFn, ""); + + addField("MinFOV", TypeF32, Offset(mCameraMinFov, CameraComponent), ""); + + addField("MaxFOV", TypeF32, Offset(mCameraMaxFov, CameraComponent), ""); + + addField("ScreenAspect", TypePoint2I, Offset(mClientScreen, CameraComponent), ""); + + addProtectedField("targetNode", TypeString, Offset(mTargetNode, CameraComponent), &_setNode, defaultProtectedGetFn, ""); + + addProtectedField("positionOffset", TypePoint3F, Offset(mPosOffset, CameraComponent), &_setPosOffset, defaultProtectedGetFn, ""); + + addProtectedField("rotationOffset", TypeRotationF, Offset(mRotOffset, CameraComponent), &_setRotOffset, defaultProtectedGetFn, ""); + + addField("useParentTransform", TypeBool, Offset(mUseParentTransform, CameraComponent), ""); +} + +bool CameraComponent::_setNode(void *object, const char *index, const char *data) +{ + CameraComponent *mcc = static_cast(object); + + mcc->mTargetNode = StringTable->insert(data); + mcc->setMaskBits(OffsetMask); + + return true; +} + +bool CameraComponent::_setPosOffset(void *object, const char *index, const char *data) +{ + CameraComponent *mcc = static_cast(object); + + if (mcc) + { + Point3F pos; + Con::setData(TypePoint3F, &pos, 0, 1, &data); + + mcc->mPosOffset = pos; + mcc->setMaskBits(OffsetMask); + + return true; + } + + return false; +} + +bool CameraComponent::_setRotOffset(void *object, const char *index, const char *data) +{ + CameraComponent *mcc = static_cast(object); + + if (mcc) + { + RotationF rot; + Con::setData(TypeRotationF, &rot, 0, 1, &data); + + mcc->mRotOffset = rot; + mcc->setMaskBits(OffsetMask); + + return true; + } + + return false; +} + +bool CameraComponent::isValidCameraFov(F32 fov) +{ + return((fov >= mCameraMinFov) && (fov <= mCameraMaxFov)); +} + +bool CameraComponent::_setCameraFov(void *object, const char *index, const char *data) +{ + CameraComponent *cCI = static_cast(object); + cCI->setCameraFov(dAtof(data)); + return true; +} + +void CameraComponent::setCameraFov(F32 fov) +{ + mCameraFov = mClampF(fov, mCameraMinFov, mCameraMaxFov); + + if (isClientObject()) + GameSetCameraTargetFov(mCameraFov); + + if (isServerObject()) + setMaskBits(FOVMask); +} + +void CameraComponent::onCameraScopeQuery(NetConnection *cr, CameraScopeQuery * query) +{ + // update the camera query + query->camera = this; + + if(GameConnection * con = dynamic_cast(cr)) + { + // get the fov from the connection (in deg) + F32 fov; + if (con->getControlCameraFov(&fov)) + { + query->fov = mDegToRad(fov/2); + query->sinFov = mSin(query->fov); + query->cosFov = mCos(query->fov); + } + else + { + query->fov = mDegToRad(mCameraFov/2); + query->sinFov = mSin(query->fov); + query->cosFov = mCos(query->fov); + } + } + + // use eye rather than camera transform (good enough and faster) + MatrixF camTransform = mOwner->getTransform(); + camTransform.getColumn(3, &query->pos); + camTransform.getColumn(1, &query->orientation); + + // Get the visible distance. + if (mOwner->getSceneManager() != NULL) + query->visibleDistance = mOwner->getSceneManager()->getVisibleDistance(); +} + +bool CameraComponent::getCameraTransform(F32* pos,MatrixF* mat) +{ + // Returns camera to world space transform + // Handles first person / third person camera position + bool isServer = isServerObject(); + + if (mTargetNodeIdx == -1) + { + if (mUseParentTransform) + { + MatrixF rMat = mOwner->getRenderTransform(); + + rMat.mul(mRotOffset.asMatrixF()); + + mat->set(rMat.toEuler(), rMat.getPosition() + mPosOffset); + } + else + { + mat->set(mRotOffset.asEulerF(), mPosOffset); + } + + return true; + } + else + { + RenderComponentInterface *renderInterface = mOwner->getComponent(); + + if (!renderInterface) + return false; + + if (mUseParentTransform) + { + MatrixF rMat = mOwner->getRenderTransform(); + + Point3F position = rMat.getPosition(); + + RotationF rot = mRotOffset; + + if (mTargetNodeIdx != -1) + { + Point3F nodPos; + MatrixF nodeTrans = renderInterface->getNodeTransform(mTargetNodeIdx); + nodeTrans.getColumn(3, &nodPos); + + // Scale the camera position before applying the transform + const Point3F& scale = mOwner->getScale(); + nodPos.convolve(scale); + + mOwner->getRenderTransform().mulP(nodPos, &position); + + nodeTrans.mul(rMat); + + rot = nodeTrans; + } + + position += mPosOffset; + + MatrixF rotMat = rot.asMatrixF(); + + MatrixF rotOffsetMat = mRotOffset.asMatrixF(); + + rotMat.mul(rotOffsetMat); + + rot = RotationF(rotMat); + + mat->set(rot.asEulerF(), position); + } + else + { + MatrixF rMat = mOwner->getRenderTransform(); + + Point3F position = rMat.getPosition(); + + RotationF rot = mRotOffset; + + if (mTargetNodeIdx != -1) + { + Point3F nodPos; + MatrixF nodeTrans = renderInterface->getNodeTransform(mTargetNodeIdx); + nodeTrans.getColumn(3, &nodPos); + + // Scale the camera position before applying the transform + const Point3F& scale = mOwner->getScale(); + nodPos.convolve(scale); + + position = nodPos; + } + + position += mPosOffset; + + mat->set(rot.asEulerF(), position); + } + + return true; + } +} + +void CameraComponent::getCameraParameters(F32 *min, F32* max, Point3F* off, MatrixF* rot) +{ + *min = 0.2f; + *max = 0.f; + off->set(0, 0, 0); + rot->identity(); +} + +U32 CameraComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retmask = Parent::packUpdate(con, mask, stream); + + if (stream->writeFlag(mask & FOVMask)) + { + stream->write(mCameraFov); + } + + if (stream->writeFlag(mask & OffsetMask)) + { + RenderComponentInterface* renderInterface = getOwner()->getComponent(); + + if (renderInterface && renderInterface->getShape()) + { + S32 nodeIndex = renderInterface->getShape()->findNode(mTargetNode); + + mTargetNodeIdx = nodeIndex; + } + + stream->writeInt(mTargetNodeIdx, 32); + //send offsets here + + stream->writeCompressedPoint(mPosOffset); + stream->writeCompressedPoint(mRotOffset.asEulerF()); + + stream->writeFlag(mUseParentTransform); + } + + return retmask; +} + +void CameraComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) + { + F32 fov; + stream->read(&fov); + setCameraFov(fov); + } + + if(stream->readFlag()) + { + mTargetNodeIdx = stream->readInt(32); + + stream->readCompressedPoint(&mPosOffset); + + EulerF rot; + stream->readCompressedPoint(&rot); + + mRotOffset = RotationF(rot); + + mUseParentTransform = stream->readFlag(); + } +} + +void CameraComponent::setForwardVector(VectorF newForward, VectorF upVector) +{ + MatrixF mat; + F32 pos = 0; + getCameraTransform(&pos, &mat); + + mPosOffset = mat.getPosition(); + + VectorF up(0.0f, 0.0f, 1.0f); + VectorF axisX; + VectorF axisY = newForward; + VectorF axisZ; + + if (upVector != VectorF::Zero) + up = upVector; + + // Validate and normalize input: + F32 lenSq; + lenSq = axisY.lenSquared(); + if (lenSq < 0.000001f) + { + axisY.set(0.0f, 1.0f, 0.0f); + Con::errorf("Entity::setForwardVector() - degenerate forward vector"); + } + else + { + axisY /= mSqrt(lenSq); + } + + lenSq = up.lenSquared(); + if (lenSq < 0.000001f) + { + up.set(0.0f, 0.0f, 1.0f); + Con::errorf("SceneObject::setForwardVector() - degenerate up vector - too small"); + } + else + { + up /= mSqrt(lenSq); + } + + if (fabsf(mDot(up, axisY)) > 0.9999f) + { + Con::errorf("SceneObject::setForwardVector() - degenerate up vector - same as forward"); + // i haven't really tested this, but i think it generates something which should be not parallel to the previous vector: + F32 tmp = up.x; + up.x = -up.y; + up.y = up.z; + up.z = tmp; + } + + // construct the remaining axes: + mCross(axisY, up, &axisX); + mCross(axisX, axisY, &axisZ); + + mat.setColumn(0, axisX); + mat.setColumn(1, axisY); + mat.setColumn(2, axisZ); + + mRotOffset = RotationF(mat.toEuler()); + mRotOffset.y = 0; + + setMaskBits(OffsetMask); +} + +void CameraComponent::setPosition(Point3F newPos) +{ + mPosOffset = newPos; + setMaskBits(OffsetMask); +} + +void CameraComponent::setRotation(RotationF newRot) +{ + mRotOffset = newRot; + setMaskBits(OffsetMask); +} + +Frustum CameraComponent::getFrustum() +{ + Frustum visFrustum; + F32 left, right, top, bottom; + F32 aspectRatio = mClientScreen.x / mClientScreen.y; + + visFrustum.set(false, mDegToRad(mCameraFov), aspectRatio, 0.1f, 1000, mOwner->getTransform()); + + return visFrustum; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Camera/CameraComponent.h b/Engine/source/T3D/components/Camera/CameraComponent.h new file mode 100644 index 000000000..1e5403833 --- /dev/null +++ b/Engine/source/T3D/components/Camera/CameraComponent.h @@ -0,0 +1,159 @@ +//----------------------------------------------------------------------------- +// 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 CAMERA_COMPONENT_H +#define CAMERA_COMPONENT_H + +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif + +class SceneRenderState; +struct CameraScopeQuery; + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class CameraComponent : public Component, public CameraInterface +{ + typedef Component Parent; + + F32 mCameraFov; ///< The camera vertical FOV in degrees. + + Point2F mClientScreen; ///< The dimensions of the client's screen. Used to calculate the aspect ratio. + + F32 mCameraDefaultFov; ///< Default vertical FOV in degrees. + F32 mCameraMinFov; ///< Min vertical FOV allowed in degrees. + F32 mCameraMaxFov; ///< Max vertical FOV allowed in degrees. + +protected: + Point3F mPosOffset; + RotationF mRotOffset; + + StringTableEntry mTargetNode; + S32 mTargetNodeIdx; + + bool mUseParentTransform; + + enum + { + FOVMask = Parent::NextFreeMask, + OffsetMask = Parent::NextFreeMask << 1, + NextFreeMask = Parent::NextFreeMask << 2, + }; + +public: + CameraComponent(); + virtual ~CameraComponent(); + DECLARE_CONOBJECT(CameraComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + static bool _setCameraFov(void *object, const char *index, const char *data); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + static bool _setNode(void *object, const char *index, const char *data); + static bool _setPosOffset(void *object, const char *index, const char *data); + static bool _setRotOffset(void *object, const char *index, const char *data); + + void setRotOffset(RotationF rot) + { + mRotOffset = rot; + setMaskBits(OffsetMask); + } + + RotationF getRotOffset() + { + return mRotOffset; + } + + Point3F getPosOffset() + { + return mPosOffset; + } + + /// Gets the minimum viewing distance, maximum viewing distance, camera offsetand rotation + /// for this object, if the world were to be viewed through its eyes + /// @param min Minimum viewing distance + /// @param max Maximum viewing distance + /// @param offset Offset of the camera from the origin in local space + /// @param rot Rotation matrix + virtual void getCameraParameters(F32 *min, F32* max, Point3F* offset, MatrixF* rot); + + /// Gets the camera to world space transform matrix + /// @todo Find out what pos does + /// @param pos TODO: Find out what this does + /// @param mat Camera transform (out) + virtual bool getCameraTransform(F32* pos, MatrixF* mat); + + /// Returns the vertical field of view in degrees for + /// this object if used as a camera. + virtual F32 getCameraFov() { return mCameraFov; } + + /// Returns the default vertical field of view in degrees + /// if this object is used as a camera. + virtual F32 getDefaultCameraFov() { return mCameraDefaultFov; } + + /// Sets the vertical field of view in degrees for this + /// object if used as a camera. + /// @param yfov The vertical FOV in degrees to test. + virtual void setCameraFov(F32 fov); + + /// Returns true if the vertical FOV in degrees is within + /// allowable parameters of the datablock. + /// @param yfov The vertical FOV in degrees to test. + /// @see ShapeBaseData::cameraMinFov + /// @see ShapeBaseData::cameraMaxFov + virtual bool isValidCameraFov(F32 fov); + /// @} + + virtual Frustum getFrustum(); + + /// Control object scoping + void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *camInfo); + + void setForwardVector(VectorF newForward, VectorF upVector = VectorF::Zero); + void setPosition(Point3F newPos); + void setRotation(RotationF newRot); + +protected: + DECLARE_CALLBACK(F32, validateCameraFov, (F32 fov)); +}; + +#endif // CAMERA_BEHAVIOR_H diff --git a/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h b/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h new file mode 100644 index 000000000..c7ed90cb1 --- /dev/null +++ b/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// 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 "console/engineAPI.h" +#include "T3D/Components/Camera/CameraComponent.h" + +//Basically, this only exists for backwards compatibility for parts of the editors +ConsoleMethod(CameraComponent, getMode, const char*, 2, 2, "() - We get the first behavior of the requested type on our owner object.\n" + "@return (string name) The type of the behavior we're requesting") +{ + return "fly"; +} + +DefineConsoleMethod(CameraComponent, getForwardVector, VectorF, (), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + F32 pos = 0; + MatrixF cameraMat; + object->getCameraTransform(&pos, &cameraMat); + + VectorF returnVec = cameraMat.getForwardVector(); + returnVec = VectorF(mRadToDeg(returnVec.x), mRadToDeg(returnVec.y), mRadToDeg(returnVec.z)); + returnVec.normalize(); + return returnVec; +} + +DefineConsoleMethod(CameraComponent, getRightVector, VectorF, (), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + F32 pos = 0; + MatrixF cameraMat; + object->getCameraTransform(&pos, &cameraMat); + + VectorF returnVec = cameraMat.getRightVector(); + returnVec = VectorF(mRadToDeg(returnVec.x), mRadToDeg(returnVec.y), mRadToDeg(returnVec.z)); + returnVec.normalize(); + return returnVec; +} + +DefineConsoleMethod(CameraComponent, getUpVector, VectorF, (), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + F32 pos = 0; + MatrixF cameraMat; + object->getCameraTransform(&pos, &cameraMat); + + VectorF returnVec = cameraMat.getUpVector(); + returnVec = VectorF(mRadToDeg(returnVec.x), mRadToDeg(returnVec.y), mRadToDeg(returnVec.z)); + returnVec.normalize(); + return returnVec; +} + +DefineConsoleMethod(CameraComponent, setForwardVector, void, (VectorF newForward), (VectorF(0, 0, 0)), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + object->setForwardVector(newForward); +} + +DefineConsoleMethod(CameraComponent, getWorldPosition, Point3F, (), , + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + F32 pos = 0; + MatrixF mat; + object->getCameraTransform(&pos, &mat); + + return mat.getPosition(); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp new file mode 100644 index 000000000..6b7866873 --- /dev/null +++ b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp @@ -0,0 +1,146 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Camera/CameraOrbiterComponent.h" +#include "core/util/safeDelete.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "core/stream/bitStream.h" +#include "console/engineAPI.h" +#include "sim/netConnection.h" +#include "math/mathUtils.h" + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +CameraOrbiterComponent::CameraOrbiterComponent() : Component() +{ + mMinOrbitDist = 0.0f; + mMaxOrbitDist = 0.0f; + mCurOrbitDist = 8.0f; + mPosition.set(0.0f, 0.0f, 0.0f); + + mMaxPitchAngle = 70; + mMinPitchAngle = -10; + + mRotation.set(0, 0, 0); + + mCamera = NULL; +} + +CameraOrbiterComponent::~CameraOrbiterComponent() +{ +} + +IMPLEMENT_CO_NETOBJECT_V1(CameraOrbiterComponent); + +bool CameraOrbiterComponent::onAdd() +{ + if (!Parent::onAdd()) + return false; + + return true; +} + +void CameraOrbiterComponent::onRemove() +{ + Parent::onRemove(); +} +void CameraOrbiterComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addField("orbitDistance", TypeF32, Offset(mCurOrbitDist, CameraOrbiterComponent), "Object world orientation."); + addField("Rotation", TypeRotationF, Offset(mRotation, CameraOrbiterComponent), "Object world orientation."); + addField("maxPitchAngle", TypeF32, Offset(mMaxPitchAngle, CameraOrbiterComponent), "Object world orientation."); + addField("minPitchAngle", TypeF32, Offset(mMinPitchAngle, CameraOrbiterComponent), "Object world orientation."); +} + +//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior +void CameraOrbiterComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + CameraComponent *cam = mOwner->getComponent(); + if (cam) + { + mCamera = cam; + } +} + +void CameraOrbiterComponent::onComponentRemove() +{ + Parent::onComponentRemove(); +} + +U32 CameraOrbiterComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + return retMask; +} + +void CameraOrbiterComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); +} + +void CameraOrbiterComponent::processTick() +{ + Parent::processTick(); + + if (!mOwner) + return; + + if (mCamera) + { + //Clamp our pitch to whatever range we allow, first. + mRotation.x = mClampF(mRotation.x, mDegToRad(mMinPitchAngle), mDegToRad(mMaxPitchAngle)); + + MatrixF ownerTrans = mOwner->getRenderTransform(); + Point3F ownerPos = ownerTrans.getPosition(); + + Point3F pos; + pos.x = mCurOrbitDist * mSin(mRotation.x + M_HALFPI_F) * mCos(-1.0f * (mRotation.z + M_HALFPI_F)); + pos.y = mCurOrbitDist * mSin(mRotation.x + M_HALFPI_F) * mSin(-1.0f * (mRotation.z + M_HALFPI_F)); + pos.z = mCurOrbitDist * mSin(mRotation.x); + + //orient the camera towards the owner + VectorF ownerVec = ownerPos - pos; + ownerVec.normalize(); + + MatrixF xRot, zRot, cameraMatrix; + xRot.set(EulerF(mRotation.x, 0.0f, 0.0f)); + zRot.set(EulerF(0.0f, 0.0f, mRotation.z)); + + cameraMatrix.mul(zRot, xRot); + cameraMatrix.getColumn(1, &ownerVec); + cameraMatrix.setColumn(3, pos - ownerVec * pos); + + RotationF camRot = RotationF(cameraMatrix); + + if (camRot != mCamera->getRotOffset()) + mCamera->setRotation(camRot); + + if (pos != mCamera->getPosOffset()) + mCamera->setPosition(pos); + } +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h new file mode 100644 index 000000000..c13029f37 --- /dev/null +++ b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// 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 CAMERA_ORBITER_COMPONENT_H +#define CAMERA_ORBITER_COMPONENT_H + +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef CAMERA_COMPONENT_H +#include "T3D/Components/camera/cameraComponent.h" +#endif + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class CameraOrbiterComponent : public Component +{ + typedef Component Parent; + + F32 mMinOrbitDist; + F32 mMaxOrbitDist; + F32 mCurOrbitDist; + Point3F mPosition; + + F32 mMaxPitchAngle; + F32 mMinPitchAngle; + + RotationF mRotation; + + CameraComponent* mCamera; + +public: + CameraOrbiterComponent(); + virtual ~CameraOrbiterComponent(); + DECLARE_CONOBJECT(CameraOrbiterComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + virtual void onComponentRemove(); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + virtual void processTick(); +}; + +#endif // EXAMPLEBEHAVIOR_H diff --git a/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h b/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h new file mode 100644 index 000000000..f822bfb76 --- /dev/null +++ b/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h @@ -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. +//----------------------------------------------------------------------------- + +#include "console/engineAPI.h" +#include "T3D/Components/Collision/CollisionComponent.h" +#include "materials/baseMatInstance.h" + +DefineConsoleMethod(CollisionComponent, getNumberOfContacts, S32, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + return object->getCollisionList()->getCount(); +} + +DefineConsoleMethod(CollisionComponent, getBestContact, S32, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + return 0; +} + +DefineConsoleMethod(CollisionComponent, getContactNormal, Point3F, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getContactInfo()) + { + if (object->getContactInfo()->contactObject) + { + return object->getContactInfo()->contactNormal; + } + } + + return Point3F::Zero; +} + +DefineConsoleMethod(CollisionComponent, getContactMaterial, S32, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getContactInfo()) + { + if (object->getContactInfo()->contactObject) + { + if (object->getContactInfo()->contactMaterial != NULL) + return object->getContactInfo()->contactMaterial->getMaterial()->getId(); + } + } + + return 0; +} + +DefineConsoleMethod(CollisionComponent, getContactObject, S32, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getContactInfo()) + { + return object->getContactInfo()->contactObject != NULL ? object->getContactInfo()->contactObject->getId() : 0; + } + + return 0; +} + +DefineConsoleMethod(CollisionComponent, getContactPoint, Point3F, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getContactInfo()) + { + if (object->getContactInfo()->contactObject) + { + return object->getContactInfo()->contactPoint; + } + } + + return Point3F::Zero; +} + +DefineConsoleMethod(CollisionComponent, getContactTime, S32, (), , + "Gets the number of contacts this collider has hit.\n" + "@return The number of static fields defined on the object.") +{ + if (object->getContactInfo()) + { + if (object->getContactInfo()->contactObject) + { + return object->getContactInfo()->contactTimer; + } + } + + return 0; +} + +DefineEngineMethod(CollisionComponent, hasContact, bool, (), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->hasContact(); +} + +DefineEngineMethod(CollisionComponent, getCollisionCount, S32, (), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getCollisionCount(); +} + +DefineEngineMethod(CollisionComponent, getCollisionNormal, Point3F, (S32 collisionIndex), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getCollisionNormal(collisionIndex); +} + +DefineEngineMethod(CollisionComponent, getCollisionAngle, F32, (S32 collisionIndex, VectorF upVector), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getCollisionAngle(collisionIndex, upVector); +} + +DefineEngineMethod(CollisionComponent, getBestCollisionAngle, F32, (VectorF upVector), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getBestCollisionAngle(upVector); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Collision/collisionComponent.cpp b/Engine/source/T3D/components/Collision/collisionComponent.cpp new file mode 100644 index 000000000..1ce851b0f --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionComponent.cpp @@ -0,0 +1,582 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Collision/collisionComponent.h" +#include "T3D/Components/Collision/collisionComponent_ScriptBinding.h" +#include "T3D/Components/Physics/physicsBehavior.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "core/stream/bitStream.h" +#include "scene/sceneRenderState.h" +#include "gfx/gfxTransformSaver.h" +#include "gfx/gfxDrawUtil.h" +#include "console/engineAPI.h" +#include "T3D/physics/physicsPlugin.h" +#include "T3D/physics/physicsBody.h" +#include "T3D/physics/physicsCollision.h" +#include "T3D/gameBase/gameConnection.h" +#include "collision/extrudedPolyList.h" +#include "math/mathIO.h" +#include "gfx/sim/debugDraw.h" +#include "collision/concretePolyList.h" + +#include "T3D/trigger.h" +#include "opcode/Opcode.h" +#include "opcode/Ice/IceAABB.h" +#include "opcode/Ice/IcePoint.h" +#include "opcode/OPC_AABBTree.h" +#include "opcode/OPC_AABBCollider.h" + +#include "math/mathUtils.h" +#include "materials/baseMatInstance.h" +#include "collision/vertexPolyList.h" + +extern bool gEditingMission; + +static bool sRenderColliders = false; + +//Docs +ConsoleDocClass(CollisionComponent, + "@brief The Box Collider component uses a box or rectangular convex shape for collisions.\n\n" + + "Colliders are individualized components that are similarly based off the CollisionInterface core.\n" + "They are basically the entire functionality of how Torque handles collisions compacted into a single component.\n" + "A collider will both collide against and be collided with, other entities.\n" + "Individual colliders will offer different shapes. This box collider will generate a box/rectangle convex, \n" + "while the mesh collider will take the owner Entity's rendered shape and do polysoup collision on it, etc.\n\n" + + "The general flow of operations for how collisions happen is thus:\n" + " -When the component is added(or updated) prepCollision() is called.\n" + " This will set up our initial convex shape for usage later.\n\n" + + " -When we update via processTick(), we first test if our entity owner is mobile.\n" + " If our owner isn't mobile(as in, they have no components that provide it a velocity to move)\n" + " then we skip doing our active collision checks. Collisions are checked by the things moving, as\n" + " opposed to being reactionary. If we're moving, we call updateWorkingCollisionSet().\n" + " updateWorkingCollisionSet() estimates our bounding space for our current ticket based on our position and velocity.\n" + " If our bounding space has changed since the last tick, we proceed to call updateWorkingList() on our convex.\n" + " This notifies any object in the bounding space that they may be collided with, so they will call buildConvex().\n" + " buildConvex() will set up our ConvexList with our collision convex info.\n\n" + + " -When the component that is actually causing our movement, such as SimplePhysicsBehavior, updates, it will check collisions.\n" + " It will call checkCollisions() on us. checkCollisions() will first build a bounding shape for our convex, and test\n" + " if we can early out because we won't hit anything based on our starting point, velocity, and tick time.\n" + " If we don't early out, we proceed to call updateCollisions(). This builds an ExtrudePolyList, which is then extruded\n" + " based on our velocity. We then test our extruded polies on our working list of objects we build\n" + " up earlier via updateWorkingCollisionSet. Any collisions that happen here will be added to our mCollisionList.\n" + " Finally, we call handleCollisionList() on our collisionList, which then queues out the colliison notice\n" + " to the object(s) we collided with so they can do callbacks and the like. We also report back on if we did collide\n" + " to the physics component via our bool return in checkCollisions() so it can make the physics react accordingly.\n\n" + + "One interesting point to note is the usage of mBlockColliding.\n" + "This is set so that it dictates the return on checkCollisions(). If set to false, it will ensure checkCollisions()\n" + "will return false, regardless if we actually collided. This is useful, because even if checkCollisions() returns false,\n" + "we still handle the collisions so the callbacks happen. This enables us to apply a collider to an object that doesn't block\n" + "objects, but does have callbacks, so it can act as a trigger, allowing for arbitrarily shaped triggers, as any collider can\n" + "act as a trigger volume(including MeshCollider).\n\n" + + "@tsexample\n" + "new CollisionComponentInstance()\n" + "{\n" + " template = CollisionComponentTemplate;\n" + " colliderSize = \"1 1 2\";\n" + " blockColldingObject = \"1\";\n" + "};\n" + "@endtsexample\n" + + "@see SimplePhysicsBehavior\n" + "@ingroup Collision\n" + "@ingroup Components\n" + ); +//Docs + +///////////////////////////////////////////////////////////////////////// +ImplementEnumType(CollisionMeshMeshType, + "Type of mesh data available in a shape.\n" + "@ingroup gameObjects") +{ CollisionComponent::None, "None", "No mesh data." }, +{ CollisionComponent::Bounds, "Bounds", "Bounding box of the shape." }, +{ CollisionComponent::CollisionMesh, "Collision Mesh", "Specifically desingated \"collision\" meshes." }, +{ CollisionComponent::VisibleMesh, "Visible Mesh", "Rendered mesh polygons." }, +EndImplementEnumType; + +// +CollisionComponent::CollisionComponent() : Component() +{ + mNetFlags.set(Ghostable | ScopeAlways); + + mFriendlyName = "Collision(Component)"; + + mOwnerRenderInterface = NULL; + mOwnerPhysicsInterface = NULL; + + mBlockColliding = true; + + mCollisionType = CollisionMesh; + mLOSType = CollisionMesh; + mDecalType = CollisionMesh; + + colisionMeshPrefix = StringTable->insert("Collision"); + + CollisionMoveMask = (TerrainObjectType | PlayerObjectType | + StaticShapeObjectType | VehicleObjectType | + VehicleBlockerObjectType | DynamicShapeObjectType | StaticObjectType | EntityObjectType | TriggerObjectType); + + mPhysicsRep = NULL; + mPhysicsWorld = NULL; + + mTimeoutList = NULL; +} + +CollisionComponent::~CollisionComponent() +{ + for (S32 i = 0; i < mFields.size(); ++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(CollisionComponent); + +void CollisionComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + RenderComponentInterface *renderInterface = mOwner->getComponent(); + if (renderInterface) + { + renderInterface->onShapeInstanceChanged.notify(this, &CollisionComponent::targetShapeChanged); + mOwnerRenderInterface = renderInterface; + } + + //physicsInterface + PhysicsComponentInterface *physicsInterface = mOwner->getComponent(); + if (!physicsInterface) + { + mPhysicsRep = PHYSICSMGR->createBody(); + } + + prepCollision(); +} + +void CollisionComponent::onComponentRemove() +{ + SAFE_DELETE(mPhysicsRep); + + Parent::onComponentRemove(); +} + +void CollisionComponent::componentAddedToOwner(Component *comp) +{ + if (comp->getId() == getId()) + return; + + //test if this is a shape component! + RenderComponentInterface *renderInterface = dynamic_cast(comp); + if (renderInterface) + { + renderInterface->onShapeInstanceChanged.notify(this, &CollisionComponent::targetShapeChanged); + mOwnerRenderInterface = renderInterface; + prepCollision(); + } + + PhysicsComponentInterface *physicsInterface = dynamic_cast(comp); + if (physicsInterface) + { + if (mPhysicsRep) + SAFE_DELETE(mPhysicsRep); + + prepCollision(); + } +} + +void CollisionComponent::componentRemovedFromOwner(Component *comp) +{ + if (comp->getId() == getId()) //????????? + return; + + //test if this is a shape component! + RenderComponentInterface *renderInterface = dynamic_cast(comp); + if (renderInterface) + { + renderInterface->onShapeInstanceChanged.remove(this, &CollisionComponent::targetShapeChanged); + mOwnerRenderInterface = NULL; + prepCollision(); + } + + //physicsInterface + PhysicsComponentInterface *physicsInterface = dynamic_cast(comp); + if (physicsInterface) + { + mPhysicsRep = PHYSICSMGR->createBody(); + + prepCollision(); + } +} + +void CollisionComponent::checkDependencies() +{ +} + +void CollisionComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addGroup("Collision"); + + addField("CollisionType", TypeCollisionMeshMeshType, Offset(mCollisionType, CollisionComponent), + "The type of mesh data to use for collision queries."); + + addField("LineOfSightType", TypeCollisionMeshMeshType, Offset(mLOSType, CollisionComponent), + "The type of mesh data to use for collision queries."); + + addField("DecalType", TypeCollisionMeshMeshType, Offset(mDecalType, CollisionComponent), + "The type of mesh data to use for collision queries."); + + addField("CollisionMeshPrefix", TypeString, Offset(colisionMeshPrefix, CollisionComponent), + "The type of mesh data to use for collision queries."); + + addField("BlockCollisions", TypeBool, Offset(mBlockColliding, CollisionComponent), ""); + + endGroup("Collision"); +} + +void CollisionComponent::inspectPostApply() +{ + // Apply any transformations set in the editor + Parent::inspectPostApply(); + + if (isServerObject()) + { + setMaskBits(ColliderMask); + prepCollision(); + } +} + +U32 CollisionComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (stream->writeFlag(mask & (ColliderMask | InitialUpdateMask))) + { + stream->write((U32)mCollisionType); + stream->writeString(colisionMeshPrefix); + } + + return retMask; +} + +void CollisionComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) // UpdateMask + { + U32 collisionType = CollisionMesh; + + stream->read(&collisionType); + + // Handle it if we have changed CollisionType's + if ((MeshType)collisionType != mCollisionType) + { + mCollisionType = (MeshType)collisionType; + + prepCollision(); + } + + char readBuffer[1024]; + + stream->readString(readBuffer); + colisionMeshPrefix = StringTable->insert(readBuffer); + } +} + +void CollisionComponent::ownerTransformSet(MatrixF *mat) +{ + if (mPhysicsRep) + mPhysicsRep->setTransform(mOwner->getTransform()); +} + +void CollisionComponent::targetShapeChanged(RenderComponentInterface* instanceInterface) +{ + prepCollision(); +} + +void CollisionComponent::prepCollision() +{ + if (!mOwner) + return; + + // Let the client know that the collision was updated + setMaskBits(ColliderMask); + + mOwner->disableCollision(); + + if ((!PHYSICSMGR || mCollisionType == None) || + (mOwnerRenderInterface == NULL && (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh))) + return; + + PhysicsCollision *colShape = NULL; + + if (mCollisionType == Bounds) + { + MatrixF offset(true); + + if (mOwnerRenderInterface && mOwnerRenderInterface->getShape()) + offset.setPosition(mOwnerRenderInterface->getShape()->center); + + colShape = PHYSICSMGR->createCollision(); + colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset); + } + else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh /*&& !mOwner->getComponent()*/)) + { + colShape = buildColShapes(); + } + + if (colShape) + { + mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + + if (mPhysicsRep) + { + if (mBlockColliding) + mPhysicsRep->init(colShape, 0, 0, mOwner, mPhysicsWorld); + else + mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER, mOwner, mPhysicsWorld); + + mPhysicsRep->setTransform(mOwner->getTransform()); + } + } + + mOwner->enableCollision(); + + onCollisionChanged.trigger(colShape); +} + +void CollisionComponent::processTick() +{ + if (!isActive()) + return; + + //ProcessTick is where our collision testing begins! + + //callback if we have a persisting contact + if (mContactInfo.contactObject) + { + if (mContactInfo.contactTimer > 0) + { + if (isMethod("updateContact")) + Con::executef(this, "updateContact"); + + if (mOwner->isMethod("updateContact")) + Con::executef(mOwner, "updateContact"); + } + + ++mContactInfo.contactTimer; + } + else if (mContactInfo.contactTimer != 0) + mContactInfo.clear(); +} + +void CollisionComponent::updatePhysics() +{ + +} + +PhysicsCollision* CollisionComponent::getCollisionData() +{ + if ((!PHYSICSMGR || mCollisionType == None) || mOwnerRenderInterface == NULL) + return NULL; + + PhysicsCollision *colShape = NULL; + if (mCollisionType == Bounds) + { + MatrixF offset(true); + offset.setPosition(mOwnerRenderInterface->getShape()->center); + colShape = PHYSICSMGR->createCollision(); + colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset); + } + else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh/* && !mOwner->getComponent()*/)) + { + colShape = buildColShapes(); + //colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale()); + } + /*else if (mCollisionType == VisibleMesh && !mOwner->getComponent()) + { + //We don't have support for visible mesh collisions with animated meshes currently in the physics abstraction layer + //so we don't generate anything if we're set to use a visible mesh but have an animated mesh component. + colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale()); + }*/ + else if (mCollisionType == VisibleMesh/* && mOwner->getComponent()*/) + { + Con::printf("CollisionComponent::updatePhysics: Cannot use visible mesh collisions with an animated mesh!"); + } + + return colShape; +} + +bool CollisionComponent::castRay(const Point3F &start, const Point3F &end, RayInfo* info) +{ + if (!mCollisionType == None) + { + if (mPhysicsWorld) + { + return mPhysicsWorld->castRay(start, end, info, Point3F::Zero); + } + } + + return false; +} + +PhysicsCollision* CollisionComponent::buildColShapes() +{ + PROFILE_SCOPE(CollisionComponent_buildColShapes); + + PhysicsCollision *colShape = NULL; + U32 surfaceKey = 0; + + TSShape* shape = mOwnerRenderInterface->getShape(); + + if (mCollisionType == VisibleMesh) + { + // Here we build triangle collision meshes from the + // visible detail levels. + + // A negative subshape on the detail means we don't have geometry. + const TSShape::Detail &detail = shape->details[0]; + if (detail.subShapeNum < 0) + return NULL; + + // We don't try to optimize the triangles we're given + // and assume the art was created properly for collision. + ConcretePolyList polyList; + polyList.setTransform(&MatrixF::Identity, mOwner->getScale()); + + // Create the collision meshes. + S32 start = shape->subShapeFirstObject[detail.subShapeNum]; + S32 end = start + shape->subShapeNumObjects[detail.subShapeNum]; + for (S32 o = start; o < end; o++) + { + const TSShape::Object &object = shape->objects[o]; + if (detail.objectDetailNum >= object.numMeshes) + continue; + + // No mesh or no verts.... nothing to do. + TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum]; + if (!mesh || mesh->mNumVerts == 0) + continue; + + // Gather the mesh triangles. + polyList.clear(); + mesh->buildPolyList(0, &polyList, surfaceKey, NULL); + + // Create the collision shape if we haven't already. + if (!colShape) + colShape = PHYSICSMGR->createCollision(); + + // Get the object space mesh transform. + MatrixF localXfm; + shape->getNodeWorldTransform(object.nodeIndex, &localXfm); + + colShape->addTriangleMesh(polyList.mVertexList.address(), + polyList.mVertexList.size(), + polyList.mIndexList.address(), + polyList.mIndexList.size() / 3, + localXfm); + } + + // Return what we built... if anything. + return colShape; + } + else if (mCollisionType == CollisionMesh) + { + + // Scan out the collision hulls... + // + // TODO: We need to support LOS collision for physics. + // + for (U32 i = 0; i < shape->details.size(); i++) + { + const TSShape::Detail &detail = shape->details[i]; + const String &name = shape->names[detail.nameIndex]; + + // Is this a valid collision detail. + if (!dStrStartsWith(name, colisionMeshPrefix) || detail.subShapeNum < 0) + continue; + + // Now go thru the meshes for this detail. + S32 start = shape->subShapeFirstObject[detail.subShapeNum]; + S32 end = start + shape->subShapeNumObjects[detail.subShapeNum]; + if (start >= end) + continue; + + for (S32 o = start; o < end; o++) + { + const TSShape::Object &object = shape->objects[o]; + const String &meshName = shape->names[object.nameIndex]; + + if (object.numMeshes <= detail.objectDetailNum) + continue; + + // No mesh, a flat bounds, or no verts.... nothing to do. + TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum]; + if (!mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0) + continue; + + // We need the default mesh transform. + MatrixF localXfm; + shape->getNodeWorldTransform(object.nodeIndex, &localXfm); + + // We have some sort of collision shape... so allocate it. + if (!colShape) + colShape = PHYSICSMGR->createCollision(); + + // Any other mesh name we assume as a generic convex hull. + // + // Collect the verts using the vertex polylist which will + // filter out duplicates. This is importaint as the convex + // generators can sometimes fail with duplicate verts. + // + VertexPolyList polyList; + MatrixF meshMat(localXfm); + + Point3F t = meshMat.getPosition(); + t.convolve(mOwner->getScale()); + meshMat.setPosition(t); + + polyList.setTransform(&MatrixF::Identity, mOwner->getScale()); + mesh->buildPolyList(0, &polyList, surfaceKey, NULL); + colShape->addConvex(polyList.getVertexList().address(), + polyList.getVertexList().size(), + meshMat); + } // objects + } // details + } + + return colShape; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Collision/collisionComponent.h b/Engine/source/T3D/components/Collision/collisionComponent.h new file mode 100644 index 000000000..aa05dc109 --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionComponent.h @@ -0,0 +1,208 @@ +//----------------------------------------------------------------------------- +// 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 COLLISION_COMPONENT_H +#define COLLISION_COMPONENT_H + +#ifndef __RESOURCE_H__ +#include "core/resource.h" +#endif +#ifndef _TSSHAPE_H_ +#include "ts/tsShape.h" +#endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif +#ifndef COLLISION_INTERFACES_H +#include "T3D/Components/collision/collisionInterfaces.h" +#endif +#ifndef RENDER_COMPONENT_INTERFACE_H +#include "T3D/Components/render/renderComponentInterface.h" +#endif +#ifndef PHYSICS_COMPONENT_INTERFACE_H +#include "T3D/Components/physics/physicsComponentInterface.h" +#endif +#ifndef _T3D_PHYSICSCOMMON_H_ +#include "T3D/physics/physicsCommon.h" +#endif +#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_ +#include "T3D/physics/physicsWorld.h" +#endif + +class TSShapeInstance; +class SceneRenderState; +class CollisionComponent; +class PhysicsBody; +class PhysicsWorld; + +class CollisionComponent : public Component, + public CollisionInterface, + public CastRayInterface +{ + typedef Component Parent; +public: + enum MeshType + { + None = 0, ///< No mesh + Bounds = 1, ///< Bounding box of the shape + CollisionMesh = 2, ///< Specifically designated collision meshes + VisibleMesh = 3 ///< Rendered mesh polygons + }; + + PhysicsWorld* mPhysicsWorld; + PhysicsBody* mPhysicsRep; + +protected: + MeshType mCollisionType; + MeshType mDecalType; + MeshType mLOSType; + + Vector mCollisionDetails; + Vector mLOSDetails; + + StringTableEntry colisionMeshPrefix; + + RenderComponentInterface* mOwnerRenderInterface; + + PhysicsComponentInterface* mOwnerPhysicsInterface; + + //only really relevent for the collision mesh type + //if we note an animation component is added, we flag as being animated. + //This way, if we're using collision meshes, we can set it up to update their transforms + //as needed + bool mAnimated; + + enum + { + ColliderMask = Parent::NextFreeMask, + }; + +public: + CollisionComponent(); + virtual ~CollisionComponent(); + DECLARE_CONOBJECT(CollisionComponent); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + virtual void ownerTransformSet(MatrixF *mat); + void targetShapeChanged(RenderComponentInterface* instanceInterface); + + virtual void onComponentRemove(); + virtual void onComponentAdd(); + + virtual void checkDependencies(); + + static void initPersistFields(); + + void inspectPostApply(); + + virtual void processTick(); + + void prepCollision(); + + PhysicsCollision* buildColShapes(); + + void updatePhysics(); + + virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); + + virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere){ return false; } + + virtual PhysicsCollision* getCollisionData(); + + //Utility functions, mostly for script + Point3F getContactNormal() { return mContactInfo.contactNormal; } + bool hasContact() + { + if (mContactInfo.contactObject) + return true; + else + return false; + } + S32 getCollisionCount() + { + return mCollisionList.getCount(); + } + + Point3F getCollisionNormal(S32 collisionIndex) + { + if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex) + return Point3F::Zero; + + return mCollisionList[collisionIndex].normal; + } + + F32 getCollisionAngle(S32 collisionIndex, Point3F upVector) + { + if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex) + return 0.0f; + + return mRadToDeg(mAcos(mDot(mCollisionList[collisionIndex].normal, upVector))); + } + + S32 getBestCollision(Point3F upVector) + { + S32 bestCollision = -1; + + F32 bestAngle = 360.f; + S32 count = mCollisionList.getCount(); + for (U32 i = 0; i < count; ++i) + { + F32 angle = mRadToDeg(mAcos(mDot(mCollisionList[i].normal, upVector))); + + if (angle < bestAngle) + { + bestCollision = i; + bestAngle = angle; + } + } + + return bestCollision; + } + + F32 getBestCollisionAngle(VectorF upVector) + { + S32 bestCol = getBestCollision(upVector); + + if (bestCol == -1) + return 0; + + return getCollisionAngle(bestCol, upVector); + } +}; + +typedef CollisionComponent::MeshType CollisionMeshMeshType; +DefineEnumType(CollisionMeshMeshType); + +#endif // COLLISION_COMPONENT_H diff --git a/Engine/source/T3D/components/Collision/collisionInterfaces.cpp b/Engine/source/T3D/components/Collision/collisionInterfaces.cpp new file mode 100644 index 000000000..4fba3e3c0 --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionInterfaces.cpp @@ -0,0 +1,258 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/collision/collisionInterfaces.h" +#include "scene/sceneObject.h" +#include "T3D/Entity.h" +#include "console/engineAPI.h" +#include "T3D/trigger.h" +#include "materials/baseMatInstance.h" + +void CollisionInterface::handleCollisionList( CollisionList &collisionList, VectorF velocity ) +{ + Collision bestCol; + + mCollisionList = collisionList; + + for (U32 i=0; i < collisionList.getCount(); ++i) + { + Collision& colCheck = collisionList[i]; + + if (colCheck.object) + { + if (colCheck.object->getTypeMask() & PlayerObjectType) + { + handleCollision( colCheck, velocity ); + } + else if (colCheck.object->getTypeMask() & TriggerObjectType) + { + // We've hit it's bounding box, that's close enough for triggers + Trigger* pTrigger = static_cast(colCheck.object); + + Component *comp = dynamic_cast(this); + pTrigger->potentialEnterObject(comp->getOwner()); + } + else if (colCheck.object->getTypeMask() & DynamicShapeObjectType) + { + Con::printf("HIT A GENERICALLY DYNAMIC OBJECT"); + handleCollision(colCheck, velocity); + } + else if(colCheck.object->getTypeMask() & EntityObjectType) + { + Entity* ent = dynamic_cast(colCheck.object); + if (ent) + { + CollisionInterface *colObjectInterface = ent->getComponent(); + if (colObjectInterface) + { + //convert us to our component + Component *thisComp = dynamic_cast(this); + if (thisComp) + { + colObjectInterface->onCollisionSignal.trigger(thisComp->getOwner()); + + //TODO: properly do this + Collision oppositeCol = colCheck; + oppositeCol.object = thisComp->getOwner(); + + colObjectInterface->handleCollision(oppositeCol, velocity); + } + } + } + } + else + { + handleCollision(colCheck, velocity); + } + } + } +} + +void CollisionInterface::handleCollision( Collision &col, VectorF velocity ) +{ + if (col.object && (mContactInfo.contactObject == NULL || + col.object->getId() != mContactInfo.contactObject->getId())) + { + queueCollision(col.object, velocity - col.object->getVelocity()); + + //do the callbacks to script for this collision + Component *comp = dynamic_cast(this); + if (comp->isMethod("onCollision")) + { + S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0; + Con::executef(comp, "onCollision", col.object, col.normal, col.point, matId, velocity); + } + + if (comp->getOwner()->isMethod("onCollisionEvent")) + { + S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0; + Con::executef(comp->getOwner(), "onCollisionEvent", col.object, col.normal, col.point, matId, velocity); + } + } +} + +void CollisionInterface::handleCollisionNotifyList() +{ + //special handling for any collision components we should notify that a collision happened. + for (U32 i = 0; i < mCollisionNotifyList.size(); ++i) + { + //convert us to our component + Component *thisComp = dynamic_cast(this); + if (thisComp) + { + mCollisionNotifyList[i]->onCollisionSignal.trigger(thisComp->getOwner()); + } + } + + mCollisionNotifyList.clear(); +} + +Chunker sTimeoutChunker; +CollisionInterface::CollisionTimeout* CollisionInterface::sFreeTimeoutList = 0; + +void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec) +{ + // Add object to list of collisions. + SimTime time = Sim::getCurrentTime(); + S32 num = obj->getId(); + + CollisionTimeout** adr = &mTimeoutList; + CollisionTimeout* ptr = mTimeoutList; + while (ptr) + { + if (ptr->objectNumber == num) + { + if (ptr->expireTime < time) + { + ptr->expireTime = time + CollisionTimeoutValue; + ptr->object = obj; + ptr->vector = vec; + } + return; + } + // Recover expired entries + if (ptr->expireTime < time) + { + CollisionTimeout* cur = ptr; + *adr = ptr->next; + ptr = ptr->next; + cur->next = sFreeTimeoutList; + sFreeTimeoutList = cur; + } + else + { + adr = &ptr->next; + ptr = ptr->next; + } + } + + // New entry for the object + if (sFreeTimeoutList != NULL) + { + ptr = sFreeTimeoutList; + sFreeTimeoutList = ptr->next; + ptr->next = NULL; + } + else + { + ptr = sTimeoutChunker.alloc(); + } + + ptr->object = obj; + ptr->objectNumber = obj->getId(); + ptr->vector = vec; + ptr->expireTime = time + CollisionTimeoutValue; + ptr->next = mTimeoutList; + + mTimeoutList = ptr; +} + +bool CollisionInterface::checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale, + Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList) +{ + Point3F end = start + velocity * time; + Point3F distance = end - start; + + Box3F scaledBox = objectBox; + scaledBox.minExtents.convolve(objectScale); + scaledBox.maxExtents.convolve(objectScale); + + if (mFabs(distance.x) < objectBox.len_x() && + mFabs(distance.y) < objectBox.len_y() && + mFabs(distance.z) < objectBox.len_z()) + { + // We can potentially early out of this. If there are no polys in the clipped polylist at our + // end position, then we can bail, and just set start = end; + Box3F wBox = scaledBox; + wBox.minExtents += end; + wBox.maxExtents += end; + + static EarlyOutPolyList eaPolyList; + eaPolyList.clear(); + eaPolyList.mNormal.set(0.0f, 0.0f, 0.0f); + eaPolyList.mPlaneList.clear(); + eaPolyList.mPlaneList.setSize(6); + eaPolyList.mPlaneList[0].set(wBox.minExtents,VectorF(-1.0f, 0.0f, 0.0f)); + eaPolyList.mPlaneList[1].set(wBox.maxExtents,VectorF(0.0f, 1.0f, 0.0f)); + eaPolyList.mPlaneList[2].set(wBox.maxExtents,VectorF(1.0f, 0.0f, 0.0f)); + eaPolyList.mPlaneList[3].set(wBox.minExtents,VectorF(0.0f, -1.0f, 0.0f)); + eaPolyList.mPlaneList[4].set(wBox.minExtents,VectorF(0.0f, 0.0f, -1.0f)); + eaPolyList.mPlaneList[5].set(wBox.maxExtents,VectorF(0.0f, 0.0f, 1.0f)); + + // Build list from convex states here... + CollisionWorkingList& rList = colWorkingList; + CollisionWorkingList* pList = rList.wLink.mNext; + while (pList != &rList) + { + Convex* pConvex = pList->mConvex; + + if (pConvex->getObject()->getTypeMask() & collisionMask) + { + Box3F convexBox = pConvex->getBoundingBox(); + + if (wBox.isOverlapped(convexBox)) + { + // No need to separate out the physical zones here, we want those + // to cause a fallthrough as well... + pConvex->getPolyList(&eaPolyList); + } + } + pList = pList->wLink.mNext; + } + + if (eaPolyList.isEmpty()) + { + return true; + } + } + + return false; +} + + +Collision* CollisionInterface::getCollision(S32 col) +{ + if(col < mCollisionList.getCount() && col >= 0) + return &mCollisionList[col]; + else + return NULL; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Collision/collisionInterfaces.h b/Engine/source/T3D/components/Collision/collisionInterfaces.h new file mode 100644 index 000000000..675230e07 --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionInterfaces.h @@ -0,0 +1,167 @@ +//----------------------------------------------------------------------------- +// 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 COLLISION_INTERFACES_H +#define COLLISION_INTERFACES_H + +#ifndef _CONVEX_H_ +#include "collision/convex.h" +#endif +#ifndef _COLLISION_H_ +#include "collision/collision.h" +#endif +#ifndef _EARLYOUTPOLYLIST_H_ +#include "collision/earlyOutPolyList.h" +#endif +#ifndef _SIM_H_ +#include "console/sim.h" +#endif +#ifndef _SCENECONTAINER_H_ +#include "scene/sceneContainer.h" +#endif +#ifndef _T3D_PHYSICSCOMMON_H_ +#include "T3D/physics/physicsCommon.h" +#endif + +struct ContactInfo +{ + bool contacted, move; + SceneObject *contactObject; + VectorF idealContactNormal; + VectorF contactNormal; + Point3F contactPoint; + F32 contactTime; + S32 contactTimer; + BaseMatInstance *contactMaterial; + + void clear() + { + contacted=move=false; + contactObject = NULL; + contactNormal.set(0,0,0); + contactTime = 0.f; + contactTimer = 0; + idealContactNormal.set(0, 0, 1); + contactMaterial = NULL; + } + + ContactInfo() { clear(); } + +}; + +class CollisionInterface// : public Interface +{ +public: + // CollisionTimeout + // This struct lets us track our collisions and estimate when they've have timed out and we'll need to act on it. + struct CollisionTimeout + { + CollisionTimeout* next; + SceneObject* object; + U32 objectNumber; + SimTime expireTime; + VectorF vector; + }; + + Signal< void( SceneObject* ) > CollisionInterface::onCollisionSignal; + Signal< void( SceneObject* ) > CollisionInterface::onContactSignal; + +protected: + CollisionTimeout* mTimeoutList; + static CollisionTimeout* sFreeTimeoutList; + + CollisionList mCollisionList; + Vector mCollisionNotifyList; + + ContactInfo mContactInfo; + + Box3F mWorkingQueryBox; + + U32 CollisionMoveMask; + + Convex *mConvexList; + + bool mBlockColliding; + + void handleCollisionNotifyList(); + + void queueCollision( SceneObject *obj, const VectorF &vec); + + /// checkEarlyOut + /// This function lets you trying and early out of any expensive collision checks by using simple extruded poly boxes representing our objects + /// If it returns true, we know we won't hit with the given parameters and can successfully early out. If it returns false, our test case collided + /// and we should do the full collision sim. + bool checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale, + Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList); + +public: + /// checkCollisions + // This is our main function for checking if a collision is happening based on the start point, velocity and time + // We do the bulk of the collision checking in here + //virtual bool checkCollisions( const F32 travelTime, Point3F *velocity, Point3F start )=0; + + CollisionList *getCollisionList() { return &mCollisionList; } + + void clearCollisionList() { mCollisionList.clear(); } + + void clearCollisionNotifyList() { mCollisionNotifyList.clear(); } + + Collision *getCollision(S32 col); + + ContactInfo* getContactInfo() { return &mContactInfo; } + + Convex *getConvexList() { return mConvexList; } + + virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) = 0; + + enum PublicConstants { + CollisionTimeoutValue = 250 + }; + + bool doesBlockColliding() { return mBlockColliding; } + + /// handleCollisionList + /// This basically takes in a CollisionList and calls handleCollision for each. + void handleCollisionList(CollisionList &collisionList, VectorF velocity); + + /// handleCollision + /// This will take a collision and queue the collision info for the object so that in knows about the collision. + void handleCollision(Collision &col, VectorF velocity); + + virtual PhysicsCollision* getCollisionData() = 0; + + Signal< void(PhysicsCollision* collision) > CollisionInterface::onCollisionChanged; +}; + +class BuildConvexInterface //: public Interface +{ +public: + virtual void buildConvex(const Box3F& box, Convex* convex)=0; +}; + +class BuildPolyListInterface// : public Interface +{ +public: + virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) = 0; +}; + +#endif \ No newline at end of file diff --git a/Engine/source/T3D/components/Collision/collisionTrigger.cpp b/Engine/source/T3D/components/Collision/collisionTrigger.cpp new file mode 100644 index 000000000..ed1e86675 --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionTrigger.cpp @@ -0,0 +1,619 @@ +//----------------------------------------------------------------------------- +// 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 "T3D/Components/Collision/CollisionTrigger.h" + +#include "scene/sceneRenderState.h" +#include "console/consoleTypes.h" +#include "console/engineAPI.h" +#include "collision/boxConvex.h" + +#include "core/stream/bitStream.h" +#include "math/mathIO.h" +#include "gfx/gfxTransformSaver.h" +#include "renderInstance/renderPassManager.h" +#include "gfx/gfxDrawUtil.h" +#include "T3D/physics/physicsPlugin.h" +#include "T3D/physics/physicsBody.h" +#include "T3D/physics/physicsCollision.h" + + +bool CollisionTrigger::smRenderCollisionTriggers = false; + +//----------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + +IMPLEMENT_CO_NETOBJECT_V1(CollisionTrigger); + +ConsoleDocClass(CollisionTrigger, + "@brief A CollisionTrigger is a volume of space that initiates script callbacks " + "when objects pass through the CollisionTrigger.\n\n" + + "CollisionTriggerData provides the callbacks for the CollisionTrigger when an object enters, stays inside " + "or leaves the CollisionTrigger's volume.\n\n" + + "@see CollisionTriggerData\n" + "@ingroup gameObjects\n" + ); + +IMPLEMENT_CALLBACK(CollisionTrigger, onAdd, void, (U32 objectId), (objectId), + "@brief Called when the CollisionTrigger is being created.\n\n" + "@param objectId the object id of the CollisionTrigger being created\n"); + +IMPLEMENT_CALLBACK(CollisionTrigger, onRemove, void, (U32 objectId), (objectId), + "@brief Called just before the CollisionTrigger is deleted.\n\n" + "@param objectId the object id of the CollisionTrigger being deleted\n"); + +CollisionTrigger::CollisionTrigger() +{ + // Don't ghost by default. + mNetFlags.set(Ghostable | ScopeAlways); + + mTypeMask |= TriggerObjectType; + + mObjScale.set(1, 1, 1); + mObjToWorld.identity(); + mWorldToObj.identity(); + + mLastThink = 0; + mCurrTick = 0; + + mConvexList = new Convex; + + mPhysicsRep = NULL; +} + +CollisionTrigger::~CollisionTrigger() +{ + delete mConvexList; + mConvexList = NULL; + SAFE_DELETE(mPhysicsRep); +} + +bool CollisionTrigger::castRay(const Point3F &start, const Point3F &end, RayInfo* info) +{ + // Collide against bounding box + F32 st, et, fst = 0, fet = 1; + F32 *bmin = &mObjBox.minExtents.x; + F32 *bmax = &mObjBox.maxExtents.x; + F32 const *si = &start.x; + F32 const *ei = &end.x; + + for (S32 i = 0; i < 3; i++) + { + if (*si < *ei) + { + if (*si > *bmax || *ei < *bmin) + return false; + F32 di = *ei - *si; + st = (*si < *bmin) ? (*bmin - *si) / di : 0; + et = (*ei > *bmax) ? (*bmax - *si) / di : 1; + } + else + { + if (*ei > *bmax || *si < *bmin) + return false; + F32 di = *ei - *si; + st = (*si > *bmax) ? (*bmax - *si) / di : 0; + et = (*ei < *bmin) ? (*bmin - *si) / di : 1; + } + if (st > fst) fst = st; + if (et < fet) fet = et; + if (fet < fst) + return false; + bmin++; bmax++; + si++; ei++; + } + + info->normal = start - end; + info->normal.normalizeSafe(); + getTransform().mulV(info->normal); + + info->t = fst; + info->object = this; + info->point.interpolate(start, end, fst); + info->material = 0; + return true; +} + +//----------------------------------------------------------------------------- +void CollisionTrigger::consoleInit() +{ + Con::addVariable("$CollisionTrigger::renderCollisionTriggers", TypeBool, &smRenderCollisionTriggers, + "@brief Forces all CollisionTrigger's to render.\n\n" + "Used by the Tools and debug render modes.\n" + "@ingroup gameObjects"); +} + +void CollisionTrigger::initPersistFields() +{ + addField("polyhedron", TypeTriggerPolyhedron, Offset(mCollisionTriggerPolyhedron, CollisionTrigger), + "@brief Defines a non-rectangular area for the CollisionTrigger.\n\n" + "Rather than the standard rectangular bounds, this optional parameter defines a quadrilateral " + "CollisionTrigger area. The quadrilateral is defined as a corner point followed by three vectors " + "representing the edges extending from the corner.\n"); + + addProtectedField("enterCommand", TypeCommand, Offset(mEnterCommand, CollisionTrigger), &setEnterCmd, &defaultProtectedGetFn, + "The command to execute when an object enters this CollisionTrigger. Object id stored in %%obj. Maximum 1023 characters."); + addProtectedField("leaveCommand", TypeCommand, Offset(mLeaveCommand, CollisionTrigger), &setLeaveCmd, &defaultProtectedGetFn, + "The command to execute when an object leaves this CollisionTrigger. Object id stored in %%obj. Maximum 1023 characters."); + addProtectedField("tickCommand", TypeCommand, Offset(mTickCommand, CollisionTrigger), &setTickCmd, &defaultProtectedGetFn, + "The command to execute while an object is inside this CollisionTrigger. Maximum 1023 characters."); + + Parent::initPersistFields(); +} + +bool CollisionTrigger::setEnterCmd(void *object, const char *index, const char *data) +{ + static_cast(object)->setMaskBits(EnterCmdMask); + return true; // to update the actual field +} + +bool CollisionTrigger::setLeaveCmd(void *object, const char *index, const char *data) +{ + static_cast(object)->setMaskBits(LeaveCmdMask); + return true; // to update the actual field +} + +bool CollisionTrigger::setTickCmd(void *object, const char *index, const char *data) +{ + static_cast(object)->setMaskBits(TickCmdMask); + return true; // to update the actual field +} + +//-------------------------------------------------------------------------- + +bool CollisionTrigger::onAdd() +{ + if (!Parent::onAdd()) + return false; + + onAdd_callback(getId()); + + Polyhedron temp = mCollisionTriggerPolyhedron; + setTriggerPolyhedron(temp); + + addToScene(); + + if (isServerObject()) + scriptOnAdd(); + + return true; +} + +void CollisionTrigger::onRemove() +{ + onRemove_callback(getId()); + + mConvexList->nukeList(); + + removeFromScene(); + Parent::onRemove(); +} + +bool CollisionTrigger::onNewDataBlock(GameBaseData *dptr, bool reload) +{ + return true; +} + +void CollisionTrigger::onDeleteNotify(SimObject *obj) +{ + GameBase* pScene = dynamic_cast(obj); + + if (pScene != NULL) + { + for (U32 i = 0; i < mObjects.size(); i++) + { + if (pScene == mObjects[i]) + { + mObjects.erase(i); + //onLeaveCollisionTrigger_callback(this, pScene); + break; + } + } + } + + Parent::onDeleteNotify(obj); +} + +void CollisionTrigger::inspectPostApply() +{ + setTriggerPolyhedron(mCollisionTriggerPolyhedron); + setMaskBits(PolyMask); + Parent::inspectPostApply(); +} + +//-------------------------------------------------------------------------- + +void CollisionTrigger::buildConvex(const Box3F& box, Convex* convex) +{ + // These should really come out of a pool + mConvexList->collectGarbage(); + + Box3F realBox = box; + mWorldToObj.mul(realBox); + realBox.minExtents.convolveInverse(mObjScale); + realBox.maxExtents.convolveInverse(mObjScale); + + if (realBox.isOverlapped(getObjBox()) == false) + return; + + // Just return a box convex for the entire shape... + Convex* cc = 0; + CollisionWorkingList& wl = convex->getWorkingList(); + for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) { + if (itr->mConvex->getType() == BoxConvexType && + itr->mConvex->getObject() == this) { + cc = itr->mConvex; + break; + } + } + if (cc) + return; + + // Create a new convex. + BoxConvex* cp = new BoxConvex; + mConvexList->registerObject(cp); + convex->addToWorkingList(cp); + cp->init(this); + + mObjBox.getCenter(&cp->mCenter); + cp->mSize.x = mObjBox.len_x() / 2.0f; + cp->mSize.y = mObjBox.len_y() / 2.0f; + cp->mSize.z = mObjBox.len_z() / 2.0f; +} + + +//------------------------------------------------------------------------------ + +void CollisionTrigger::setTransform(const MatrixF & mat) +{ + Parent::setTransform(mat); + + if (mPhysicsRep) + mPhysicsRep->setTransform(mat); + + if (isServerObject()) { + MatrixF base(true); + base.scale(Point3F(1.0 / mObjScale.x, + 1.0 / mObjScale.y, + 1.0 / mObjScale.z)); + base.mul(mWorldToObj); + mClippedList.setBaseTransform(base); + + setMaskBits(TransformMask | ScaleMask); + } +} + +void CollisionTrigger::prepRenderImage(SceneRenderState *state) +{ + // only render if selected or render flag is set + if (!smRenderCollisionTriggers && !isSelected()) + return; + + ObjectRenderInst *ri = state->getRenderPass()->allocInst(); + ri->renderDelegate.bind(this, &CollisionTrigger::renderObject); + ri->type = RenderPassManager::RIT_Editor; + ri->translucentSort = true; + ri->defaultKey = 1; + state->getRenderPass()->addInst(ri); +} + +void CollisionTrigger::renderObject(ObjectRenderInst *ri, + SceneRenderState *state, + BaseMatInstance *overrideMat) +{ + if (overrideMat) + return; + + GFXStateBlockDesc desc; + desc.setZReadWrite(true, false); + desc.setBlend(true); + + // CollisionTrigger polyhedrons are set up with outward facing normals and CCW ordering + // so can't enable backface culling. + desc.setCullMode(GFXCullNone); + + GFXTransformSaver saver; + + MatrixF mat = getRenderTransform(); + mat.scale(getScale()); + + GFX->multWorld(mat); + + GFXDrawUtil *drawer = GFX->getDrawUtil(); + + drawer->drawPolyhedron(desc, mCollisionTriggerPolyhedron, ColorI(255, 192, 0, 45)); + + // Render wireframe. + + desc.setFillModeWireframe(); + drawer->drawPolyhedron(desc, mCollisionTriggerPolyhedron, ColorI::BLACK); +} + +void CollisionTrigger::setTriggerPolyhedron(const Polyhedron& rPolyhedron) +{ + mCollisionTriggerPolyhedron = rPolyhedron; + + if (mCollisionTriggerPolyhedron.pointList.size() != 0) { + mObjBox.minExtents.set(1e10, 1e10, 1e10); + mObjBox.maxExtents.set(-1e10, -1e10, -1e10); + for (U32 i = 0; i < mCollisionTriggerPolyhedron.pointList.size(); i++) { + mObjBox.minExtents.setMin(mCollisionTriggerPolyhedron.pointList[i]); + mObjBox.maxExtents.setMax(mCollisionTriggerPolyhedron.pointList[i]); + } + } + else { + mObjBox.minExtents.set(-0.5, -0.5, -0.5); + mObjBox.maxExtents.set(0.5, 0.5, 0.5); + } + + MatrixF xform = getTransform(); + setTransform(xform); + + mClippedList.clear(); + mClippedList.mPlaneList = mCollisionTriggerPolyhedron.planeList; + // for (U32 i = 0; i < mClippedList.mPlaneList.size(); i++) + // mClippedList.mPlaneList[i].neg(); + + MatrixF base(true); + base.scale(Point3F(1.0 / mObjScale.x, + 1.0 / mObjScale.y, + 1.0 / mObjScale.z)); + base.mul(mWorldToObj); + + mClippedList.setBaseTransform(base); + + SAFE_DELETE(mPhysicsRep); + + if (PHYSICSMGR) + { + PhysicsCollision *colShape = PHYSICSMGR->createCollision(); + + MatrixF colMat(true); + colMat.displace(Point3F(0, 0, mObjBox.getExtents().z * 0.5f * mObjScale.z)); + + colShape->addBox(mObjBox.getExtents() * 0.5f * mObjScale, colMat); + //MatrixF colMat( true ); + //colMat.scale( mObjScale ); + //colShape->addConvex( mCollisionTriggerPolyhedron.pointList.address(), mCollisionTriggerPolyhedron.pointList.size(), colMat ); + + PhysicsWorld *world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + mPhysicsRep = PHYSICSMGR->createBody(); + mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world); + mPhysicsRep->setTransform(getTransform()); + } +} + + +//-------------------------------------------------------------------------- + +bool CollisionTrigger::testObject(GameBase* enter) +{ + if (mCollisionTriggerPolyhedron.pointList.size() == 0) + return false; + + mClippedList.clear(); + + SphereF sphere; + sphere.center = (mWorldBox.minExtents + mWorldBox.maxExtents) * 0.5; + VectorF bv = mWorldBox.maxExtents - sphere.center; + sphere.radius = bv.len(); + + enter->buildPolyList(PLC_Collision, &mClippedList, mWorldBox, sphere); + return mClippedList.isEmpty() == false; +} + + +void CollisionTrigger::potentialEnterObject(GameBase* enter) +{ + for (U32 i = 0; i < mObjects.size(); i++) { + if (mObjects[i] == enter) + return; + } + + if (testObject(enter) == true) { + mObjects.push_back(enter); + deleteNotify(enter); + + if (!mEnterCommand.isEmpty()) + { + String command = String("%obj = ") + enter->getIdString() + ";" + mEnterCommand; + Con::evaluate(command.c_str()); + } + + //onEnterCollisionTrigger_callback(this, enter); + } +} + + +void CollisionTrigger::processTick(const Move* move) +{ + Parent::processTick(move); + + // + if (mObjects.size() == 0) + return; + + if (mLastThink + 100 < mCurrTick) + { + mCurrTick = 0; + mLastThink = 0; + + for (S32 i = S32(mObjects.size() - 1); i >= 0; i--) + { + if (testObject(mObjects[i]) == false) + { + GameBase* remove = mObjects[i]; + mObjects.erase(i); + clearNotify(remove); + + if (!mLeaveCommand.isEmpty()) + { + String command = String("%obj = ") + remove->getIdString() + ";" + mLeaveCommand; + Con::evaluate(command.c_str()); + } + + //onLeaveCollisionTrigger_callback(this, remove); + } + } + + if (!mTickCommand.isEmpty()) + Con::evaluate(mTickCommand.c_str()); + + //if (mObjects.size() != 0) + // onTickCollisionTrigger_callback(this); + } + else + { + mCurrTick += TickMs; + } +} + +//-------------------------------------------------------------------------- + +U32 CollisionTrigger::packUpdate(NetConnection* con, U32 mask, BitStream* stream) +{ + U32 i; + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (stream->writeFlag(mask & TransformMask)) + { + stream->writeAffineTransform(mObjToWorld); + } + + // Write the polyhedron + if (stream->writeFlag(mask & PolyMask)) + { + stream->write(mCollisionTriggerPolyhedron.pointList.size()); + for (i = 0; i < mCollisionTriggerPolyhedron.pointList.size(); i++) + mathWrite(*stream, mCollisionTriggerPolyhedron.pointList[i]); + + stream->write(mCollisionTriggerPolyhedron.planeList.size()); + for (i = 0; i < mCollisionTriggerPolyhedron.planeList.size(); i++) + mathWrite(*stream, mCollisionTriggerPolyhedron.planeList[i]); + + stream->write(mCollisionTriggerPolyhedron.edgeList.size()); + for (i = 0; i < mCollisionTriggerPolyhedron.edgeList.size(); i++) { + const Polyhedron::Edge& rEdge = mCollisionTriggerPolyhedron.edgeList[i]; + + stream->write(rEdge.face[0]); + stream->write(rEdge.face[1]); + stream->write(rEdge.vertex[0]); + stream->write(rEdge.vertex[1]); + } + } + + if (stream->writeFlag(mask & EnterCmdMask)) + stream->writeLongString(CMD_SIZE - 1, mEnterCommand.c_str()); + if (stream->writeFlag(mask & LeaveCmdMask)) + stream->writeLongString(CMD_SIZE - 1, mLeaveCommand.c_str()); + if (stream->writeFlag(mask & TickCmdMask)) + stream->writeLongString(CMD_SIZE - 1, mTickCommand.c_str()); + + return retMask; +} + +void CollisionTrigger::unpackUpdate(NetConnection* con, BitStream* stream) +{ + Parent::unpackUpdate(con, stream); + + U32 i, size; + + // Transform + if (stream->readFlag()) + { + MatrixF temp; + stream->readAffineTransform(&temp); + setTransform(temp); + } + + // Read the polyhedron + if (stream->readFlag()) + { + Polyhedron tempPH; + stream->read(&size); + tempPH.pointList.setSize(size); + for (i = 0; i < tempPH.pointList.size(); i++) + mathRead(*stream, &tempPH.pointList[i]); + + stream->read(&size); + tempPH.planeList.setSize(size); + for (i = 0; i < tempPH.planeList.size(); i++) + mathRead(*stream, &tempPH.planeList[i]); + + stream->read(&size); + tempPH.edgeList.setSize(size); + for (i = 0; i < tempPH.edgeList.size(); i++) { + Polyhedron::Edge& rEdge = tempPH.edgeList[i]; + + stream->read(&rEdge.face[0]); + stream->read(&rEdge.face[1]); + stream->read(&rEdge.vertex[0]); + stream->read(&rEdge.vertex[1]); + } + setTriggerPolyhedron(tempPH); + } + + if (stream->readFlag()) + { + char buf[CMD_SIZE]; + stream->readLongString(CMD_SIZE - 1, buf); + mEnterCommand = buf; + } + if (stream->readFlag()) + { + char buf[CMD_SIZE]; + stream->readLongString(CMD_SIZE - 1, buf); + mLeaveCommand = buf; + } + if (stream->readFlag()) + { + char buf[CMD_SIZE]; + stream->readLongString(CMD_SIZE - 1, buf); + mTickCommand = buf; + } +} + +//ConsoleMethod( CollisionTrigger, getNumObjects, S32, 2, 2, "") +DefineEngineMethod(CollisionTrigger, getNumObjects, S32, (), , + "@brief Get the number of objects that are within the CollisionTrigger's bounds.\n\n" + "@see getObject()\n") +{ + return object->getNumCollisionTriggeringObjects(); +} + +//ConsoleMethod( CollisionTrigger, getObject, S32, 3, 3, "(int idx)") +DefineEngineMethod(CollisionTrigger, getObject, S32, (S32 index), , + "@brief Retrieve the requested object that is within the CollisionTrigger's bounds.\n\n" + "@param index Index of the object to get (range is 0 to getNumObjects()-1)\n" + "@returns The SimObjectID of the object, or -1 if the requested index is invalid.\n" + "@see getNumObjects()\n") +{ + if (index >= object->getNumCollisionTriggeringObjects() || index < 0) + return -1; + else + return object->getObject(U32(index))->getId(); +} diff --git a/Engine/source/T3D/components/Collision/collisionTrigger.h b/Engine/source/T3D/components/Collision/collisionTrigger.h new file mode 100644 index 000000000..5673d6162 --- /dev/null +++ b/Engine/source/T3D/components/Collision/collisionTrigger.h @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// 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 _H_CollisionTrigger +#define _H_CollisionTrigger + +#ifndef _GAMEBASE_H_ +#include "T3D/gameBase/gameBase.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef _EARLYOUTPOLYLIST_H_ +#include "collision/earlyOutPolyList.h" +#endif +#ifndef _MPOLYHEDRON_H_ +#include "math/mPolyhedron.h" +#endif +#ifndef _TRIGGER_H_ +#include "T3D/trigger.h" +#endif + +class Convex; +class PhysicsBody; +class TriggerPolyhedronType; + +class CollisionTrigger : public GameBase +{ + typedef GameBase Parent; + + /// CollisionTrigger polyhedron with *outward* facing normals and CCW ordered + /// vertices. + Polyhedron mCollisionTriggerPolyhedron; + + EarlyOutPolyList mClippedList; + Vector mObjects; + + PhysicsBody *mPhysicsRep; + + U32 mLastThink; + U32 mCurrTick; + Convex *mConvexList; + + String mEnterCommand; + String mLeaveCommand; + String mTickCommand; + + enum CollisionTriggerUpdateBits + { + TransformMask = Parent::NextFreeMask << 0, + PolyMask = Parent::NextFreeMask << 1, + EnterCmdMask = Parent::NextFreeMask << 2, + LeaveCmdMask = Parent::NextFreeMask << 3, + TickCmdMask = Parent::NextFreeMask << 4, + NextFreeMask = Parent::NextFreeMask << 5, + }; + + static const U32 CMD_SIZE = 1024; + +protected: + + static bool smRenderCollisionTriggers; + bool testObject(GameBase* enter); + void processTick(const Move *move); + + void buildConvex(const Box3F& box, Convex* convex); + + static bool setEnterCmd(void *object, const char *index, const char *data); + static bool setLeaveCmd(void *object, const char *index, const char *data); + static bool setTickCmd(void *object, const char *index, const char *data); + +public: + CollisionTrigger(); + ~CollisionTrigger(); + + // SimObject + DECLARE_CONOBJECT(CollisionTrigger); + + DECLARE_CALLBACK(void, onAdd, (U32 objectId)); + DECLARE_CALLBACK(void, onRemove, (U32 objectId)); + + static void consoleInit(); + static void initPersistFields(); + bool onAdd(); + void onRemove(); + void onDeleteNotify(SimObject*); + void inspectPostApply(); + + // NetObject + U32 packUpdate(NetConnection *conn, U32 mask, BitStream* stream); + void unpackUpdate(NetConnection *conn, BitStream* stream); + + // SceneObject + void setTransform(const MatrixF &mat); + void prepRenderImage(SceneRenderState* state); + + // GameBase + bool onNewDataBlock(GameBaseData *dptr, bool reload); + + // CollisionTrigger + void setTriggerPolyhedron(const Polyhedron&); + + void potentialEnterObject(GameBase*); + U32 getNumCollisionTriggeringObjects() const; + GameBase* getObject(const U32); + const Vector& getObjects() const { return mObjects; } + + void renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat); + + bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); +}; + +inline U32 CollisionTrigger::getNumCollisionTriggeringObjects() const +{ + return mObjects.size(); +} + +inline GameBase* CollisionTrigger::getObject(const U32 index) +{ + AssertFatal(index < getNumCollisionTriggeringObjects(), "Error, out of range object index"); + + return mObjects[index]; +} + +#endif // _H_CollisionTrigger + diff --git a/Engine/source/T3D/components/Component.cpp b/Engine/source/T3D/components/Component.cpp new file mode 100644 index 000000000..0c4475b79 --- /dev/null +++ b/Engine/source/T3D/components/Component.cpp @@ -0,0 +1,638 @@ +//----------------------------------------------------------------------------- +// 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 "console/simBase.h" +#include "console/consoleTypes.h" +#include "T3D/Components/Component.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "core/stream/bitStream.h" +#include "console/engineAPI.h" +#include "sim/netConnection.h" +#include "console/consoleInternal.h" + +#define DECLARE_NATIVE_COMPONENT( ComponentType ) \ + Component* staticComponentTemplate = new ComponentType; \ + Sim::gNativeComponentSet->addObject(staticComponentTemplate); + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// + +Component::Component() +{ + mFriendlyName = StringTable->lookup(""); + mFromResource = StringTable->lookup(""); + mComponentType = StringTable->lookup(""); + mComponentGroup = StringTable->lookup(""); + mNetworkType = StringTable->lookup(""); + mTemplateName = StringTable->lookup(""); + //mDependency = StringTable->lookup(""); + + mNetworked = false; + + + // [tom, 1/12/2007] We manage the memory for the description since it + // could be loaded from a file and thus massive. This is accomplished with + // protected fields, but since they still call Con::getData() the field + // needs to always be valid. This is pretty lame. + mDescription = new char[1]; + ((char *)mDescription)[0] = 0; + + mOwner = NULL; + + mCanSaveFieldDictionary = false; + + mNetFlags.set(Ghostable); +} + +Component::~Component() +{ + for (S32 i = 0; i < mFields.size(); ++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(Component); + +////////////////////////////////////////////////////////////////////////// + +void Component::initPersistFields() +{ + addGroup("Component"); + addField("componentType", TypeCaseString, Offset(mComponentType, Component), "The type of behavior.", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + addField("networkType", TypeCaseString, Offset(mNetworkType, Component), "The type of behavior.", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + addField("friendlyName", TypeCaseString, Offset(mFriendlyName, Component), "Human friendly name of this behavior", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + addProtectedField("description", TypeCaseString, Offset(mDescription, Component), &setDescription, &getDescription, + "The description of this behavior which can be set to a \"string\" or a fileName\n", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + + addField("networked", TypeBool, Offset(mNetworked, Component), "Is this behavior ghosted to clients?", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + + addProtectedField("Owner", TypeSimObjectPtr, Offset(mOwner, Component), &setOwner, &defaultProtectedGetFn, "", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + + //addField("hidden", TypeBool, Offset(mHidden, Component), "Flags if this behavior is shown in the editor or not", AbstractClassRep::FieldFlags::FIELD_HideInInspectors); + addProtectedField("enabled", TypeBool, Offset(mEnabled, Component), &_setEnabled, &defaultProtectedGetFn, ""); + endGroup("Component"); + + Parent::initPersistFields(); + + //clear out irrelevent fields + removeField("name"); + //removeField("internalName"); + removeField("parentGroup"); + //removeField("class"); + removeField("superClass"); + removeField("hidden"); + removeField("canSave"); + removeField("canSaveDynamicFields"); + removeField("persistentId"); +} + +bool Component::_setEnabled(void *object, const char *index, const char *data) +{ + Component *c = static_cast(object); + + c->mEnabled = dAtob(data); + c->setMaskBits(EnableMask); + + return true; +} + +////////////////////////////////////////////////////////////////////////// + +bool Component::setDescription(void *object, const char *index, const char *data) +{ + Component *bT = static_cast(object); + SAFE_DELETE_ARRAY(bT->mDescription); + bT->mDescription = bT->getDescriptionText(data); + + // We return false since we don't want the console to mess with the data + return false; +} + +const char * Component::getDescription(void* obj, const char* data) +{ + Component *object = static_cast(obj); + + return object->mDescription ? object->mDescription : ""; +} + +////////////////////////////////////////////////////////////////////////// +bool Component::onAdd() +{ + if (!Parent::onAdd()) + return false; + + setMaskBits(UpdateMask); + + return true; +} + +void Component::onRemove() +{ + onDataSet.removeAll(); + + if (mOwner) + { + //notify our removal to the owner, so we have no loose ends + mOwner->removeComponent(this, false); + } + + Parent::onRemove(); +} + +void Component::onComponentAdd() +{ + if (isServerObject()) + { + if (isMethod("onAdd")) + Con::executef(this, "onAdd"); + } + + mEnabled = true; +} + +void Component::onComponentRemove() +{ + mEnabled = false; + + if (isServerObject()) + { + if (isMethod("onRemove")) + Con::executef(this, "onRemove"); + } + + if (mOwner) + { + mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner); + mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner); + mOwner->onTransformSet.remove(this, &Component::ownerTransformSet); + } + + mOwner = NULL; + setDataField("owner", NULL, ""); +} + +void Component::setOwner(Entity* owner) +{ + //first, catch if we have an existing owner, and we're changing from it + if (mOwner && mOwner != owner) + { + mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner); + mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner); + mOwner->onTransformSet.remove(this, &Component::ownerTransformSet); + + mOwner->removeComponent(this, false); + } + + mOwner = owner; + + if (mOwner != NULL) + { + mOwner->onComponentAdded.notify(this, &Component::componentAddedToOwner); + mOwner->onComponentRemoved.notify(this, &Component::componentRemovedFromOwner); + mOwner->onTransformSet.notify(this, &Component::ownerTransformSet); + } + + if (isServerObject()) + setMaskBits(OwnerMask); +} + +void Component::componentAddedToOwner(Component *comp) +{ + return; +} + +void Component::componentRemovedFromOwner(Component *comp) +{ + return; +} + +void Component::ownerTransformSet(MatrixF *mat) +{ + return; +} + +U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (mask & OwnerMask) + { + if (mOwner != NULL) + { + S32 ghostIndex = con->getGhostIndex(mOwner); + + if (ghostIndex == -1) + { + stream->writeFlag(false); + retMask |= OwnerMask; + } + else + { + stream->writeFlag(true); + stream->writeFlag(true); + stream->writeInt(ghostIndex, NetConnection::GhostIdBitSize); + } + } + else + { + stream->writeFlag(true); + stream->writeFlag(false); + } + } + else + stream->writeFlag(false); + + if (stream->writeFlag(mask & EnableMask)) + { + stream->writeFlag(mEnabled); + } + + return retMask; +} + +void Component::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) + { + if (stream->readFlag()) + { + //we have an owner object, so fetch it + S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize); + + Entity *e = dynamic_cast(con->resolveGhost(gIndex)); + if (e) + e->addComponent(this); + } + else + { + //it's being nulled out + setOwner(NULL); + } + } + + if (stream->readFlag()) + { + mEnabled = stream->readFlag(); + } +} + +void Component::packToStream(Stream &stream, U32 tabStop, S32 behaviorID, U32 flags /* = 0 */) +{ + char buffer[1024]; + + writeFields(stream, tabStop); + + // Write out the fields which the behavior template knows about + for (int i = 0; i < getComponentFieldCount(); i++) + { + ComponentField *field = getComponentField(i); + const char *objFieldValue = getDataField(field->mFieldName, NULL); + + // If the field holds the same value as the template's default value than it + // will get initialized by the template, and so it won't be included just + // to try to keep the object files looking as non-horrible as possible. + if (dStrcmp(field->mDefaultValue, objFieldValue) != 0) + { + dSprintf(buffer, sizeof(buffer), "%s = \"%s\";\n", field->mFieldName, (dStrlen(objFieldValue) > 0 ? objFieldValue : "0")); + + stream.writeTabs(tabStop); + stream.write(dStrlen(buffer), buffer); + } + } +} + +void Component::processTick() +{ + if (isServerObject() && mEnabled) + { + if (mOwner != NULL && isMethod("Update")) + Con::executef(this, "Update"); + } +} + +void Component::setDataField(StringTableEntry slotName, const char *array, const char *value) +{ + Parent::setDataField(slotName, array, value); + + onDataSet.trigger(this, slotName, value); +} + + +//catch any behavior field updates +void Component::onStaticModified(const char* slotName, const char* newValue) +{ + Parent::onStaticModified(slotName, newValue); + + //If we don't have an owner yet, then this is probably the initial setup, so we don't need the console callbacks yet. + if (!mOwner) + return; + + onDataSet.trigger(this, slotName, newValue); + + checkComponentFieldModified(slotName, newValue); +} + +void Component::onDynamicModified(const char* slotName, const char* newValue) +{ + Parent::onDynamicModified(slotName, newValue); + + //If we don't have an owner yet, then this is probably the initial setup, so we don't need the console callbacks yet. + if (!mOwner) + return; + + checkComponentFieldModified(slotName, newValue); +} + +void Component::checkComponentFieldModified(const char* slotName, const char* newValue) +{ + StringTableEntry slotNameEntry = StringTable->insert(slotName); + + //find if it's a behavior field + for (int i = 0; i < mFields.size(); i++) + { + ComponentField *field = getComponentField(i); + if (field->mFieldName == slotNameEntry) + { + //we have a match, do the script callback that we updated a field + if (isMethod("onInspectorUpdate")) + Con::executef(this, "onInspectorUpdate", slotName); + + return; + } + } +} +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +void Component::addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue /* = NULL */, const char *userData /* = NULL */, /*const char* dependency /* = NULL *//*,*/ bool hidden /* = false */) +{ + StringTableEntry stFieldName = StringTable->insert(fieldName); + + for (S32 i = 0; i < mFields.size(); ++i) + { + if (mFields[i].mFieldName == stFieldName) + return; + } + + ComponentField field; + field.mFieldName = stFieldName; + + //find the field type + S32 fieldTypeMask = -1; + StringTableEntry fieldType = StringTable->insert(type); + + if (fieldType == StringTable->insert("TypeS32")) + fieldTypeMask = TypeS32; + else if (fieldType == StringTable->insert("TypeF32")) + fieldTypeMask = TypeF32; + else if (fieldType == StringTable->insert("TypePoint3F")) + fieldTypeMask = TypePoint3F; + else if (fieldType == StringTable->insert("TypeMaterialName")) + fieldTypeMask = TypeMaterialName; + else if (fieldType == StringTable->insert("TypeImageFilename")) + fieldTypeMask = TypeImageFilename; + else if (fieldType == StringTable->insert("TypeShapeFilename")) + fieldTypeMask = TypeShapeFilename; + else if (fieldType == StringTable->insert("TypeBool")) + fieldTypeMask = TypeBool; + else + fieldTypeMask = TypeString; + + field.mFieldType = fieldTypeMask; + + field.mUserData = StringTable->insert(userData ? userData : ""); + field.mDefaultValue = StringTable->insert(defaultValue ? defaultValue : ""); + field.mFieldDescription = getDescriptionText(desc); + + field.mGroup = mComponentGroup; + + field.mHidden = hidden; + + mFields.push_back(field); + + //Before we set this, we need to do a test to see if this field was already set, like from the mission file or a taml file + const char* curFieldData = getDataField(field.mFieldName, NULL); + + if (dStrIsEmpty(curFieldData)) + setDataField(field.mFieldName, NULL, field.mDefaultValue); +} + +ComponentField* Component::getComponentField(const char *fieldName) +{ + StringTableEntry stFieldName = StringTable->insert(fieldName); + + for (S32 i = 0; i < mFields.size(); ++i) + { + if (mFields[i].mFieldName == stFieldName) + return &mFields[i]; + } + + return NULL; +} + +////////////////////////////////////////////////////////////////////////// + +const char * Component::getDescriptionText(const char *desc) +{ + if (desc == NULL) + return NULL; + + char *newDesc; + + // [tom, 1/12/2007] If it isn't a file, just do it the easy way + if (!Platform::isFile(desc)) + { + newDesc = new char[dStrlen(desc) + 1]; + dStrcpy(newDesc, desc); + + return newDesc; + } + + FileStream str; + str.open(desc, Torque::FS::File::Read); + + Stream *stream = &str; + if (stream == NULL){ + str.close(); + return NULL; + } + + U32 size = stream->getStreamSize(); + if (size > 0) + { + newDesc = new char[size + 1]; + if (stream->read(size, (void *)newDesc)) + newDesc[size] = 0; + else + { + SAFE_DELETE_ARRAY(newDesc); + } + } + + str.close(); + delete stream; + + return newDesc; +} +////////////////////////////////////////////////////////////////////////// +void Component::beginFieldGroup(const char* groupName) +{ + if (dStrcmp(mComponentGroup, "")) + { + Con::errorf("Component: attempting to begin new field group with a group already begun!"); + return; + } + + mComponentGroup = StringTable->insert(groupName); +} + +void Component::endFieldGroup() +{ + mComponentGroup = StringTable->insert(""); +} + +void Component::addDependency(StringTableEntry name) +{ + mDependencies.push_back_unique(name); +} + +////////////////////////////////////////////////////////////////////////// +// Console Methods +////////////////////////////////////////////////////////////////////////// +ConsoleMethod(Component, beginGroup, void, 3, 3, "(groupName)\n" + "Starts the grouping for following fields being added to be grouped into\n" + "@param groupName The name of this group\n" + "@param desc The Description of this field\n" + "@param type The DataType for this field (default, int, float, Point2F, bool, enum, Object, keybind, color)\n" + "@param defaultValue The Default value for this field\n" + "@param userData An extra data field that can be used for custom data on a per-field basis
Usage for default types
" + "-enum: a TAB separated list of possible values
" + "-object: the T2D object type that are valid choices for the field. The object types observe inheritance, so if you have a t2dSceneObject field you will be able to choose t2dStaticSrpites, t2dAnimatedSprites, etc.\n" + "@return Nothing\n") +{ + object->beginFieldGroup(argv[2]); +} + +ConsoleMethod(Component, endGroup, void, 2, 2, "()\n" + "Ends the grouping for prior fields being added to be grouped into\n" + "@param groupName The name of this group\n" + "@param desc The Description of this field\n" + "@param type The DataType for this field (default, int, float, Point2F, bool, enum, Object, keybind, color)\n" + "@param defaultValue The Default value for this field\n" + "@param userData An extra data field that can be used for custom data on a per-field basis
Usage for default types
" + "-enum: a TAB separated list of possible values
" + "-object: the T2D object type that are valid choices for the field. The object types observe inheritance, so if you have a t2dSceneObject field you will be able to choose t2dStaticSrpites, t2dAnimatedSprites, etc.\n" + "@return Nothing\n") +{ + object->endFieldGroup(); +} + +DefineConsoleMethod(Component, addComponentField, void, (String fieldName, String fieldDesc, String fieldType, String defValue, String userData, bool hidden), + ("", "", "", "", "", false), + "Get the number of static fields on the object.\n" + "@return The number of static fields defined on the object.") +{ + object->addComponentField(fieldName, fieldDesc, fieldType, defValue, userData, hidden); +} + +ConsoleMethod(Component, getComponentFieldCount, S32, 2, 2, "() - Get the number of ComponentField's on this object\n" + "@return Returns the number of BehaviorFields as a nonnegative integer\n") +{ + return object->getComponentFieldCount(); +} + +// [tom, 1/12/2007] Field accessors split into multiple methods to allow space +// for long descriptions and type data. + +ConsoleMethod(Component, getComponentField, const char *, 3, 3, "(int index) - Gets a Tab-Delimited list of information about a ComponentField specified by Index\n" + "@param index The index of the behavior\n" + "@return FieldName, FieldType and FieldDefaultValue, each separated by a TAB character.\n") +{ + ComponentField *field = object->getComponentField(dAtoi(argv[2])); + if (field == NULL) + return ""; + + char *buf = Con::getReturnBuffer(1024); + dSprintf(buf, 1024, "%s\t%s\t%s\t%s", field->mFieldName, field->mFieldType, field->mDefaultValue, field->mGroup); + + return buf; +} + +ConsoleMethod(Component, setComponentield, const char *, 3, 3, "(int index) - Gets a Tab-Delimited list of information about a ComponentField specified by Index\n" + "@param index The index of the behavior\n" + "@return FieldName, FieldType and FieldDefaultValue, each separated by a TAB character.\n") +{ + ComponentField *field = object->getComponentField(dAtoi(argv[2])); + if (field == NULL) + return ""; + + char *buf = Con::getReturnBuffer(1024); + dSprintf(buf, 1024, "%s\t%s\t%s", field->mFieldName, field->mFieldType, field->mDefaultValue); + + return buf; +} + +ConsoleMethod(Component, getBehaviorFieldUserData, const char *, 3, 3, "(int index) - Gets the UserData associated with a field by index in the field list\n" + "@param index The index of the behavior\n" + "@return Returns a string representing the user data of this field\n") +{ + ComponentField *field = object->getComponentField(dAtoi(argv[2])); + if (field == NULL) + return ""; + + return field->mUserData; +} + +ConsoleMethod(Component, getComponentFieldDescription, const char *, 3, 3, "(int index) - Gets a field description by index\n" + "@param index The index of the behavior\n" + "@return Returns a string representing the description of this field\n") +{ + ComponentField *field = object->getComponentField(dAtoi(argv[2])); + if (field == NULL) + return ""; + + return field->mFieldDescription ? field->mFieldDescription : ""; +} + +ConsoleMethod(Component, addDependency, void, 3, 3, "(string behaviorName) - Gets a field description by index\n" + "@param index The index of the behavior\n" + "@return Returns a string representing the description of this field\n") +{ + object->addDependency(argv[2]); +} + +ConsoleMethod(Component, setDirty, void, 2, 2, "() - Gets a field description by index\n" + "@param index The index of the behavior\n" + "@return Returns a string representing the description of this field\n") +{ + object->setMaskBits(Component::OwnerMask); +} diff --git a/Engine/source/T3D/components/Component.h b/Engine/source/T3D/components/Component.h new file mode 100644 index 000000000..98eea53bc --- /dev/null +++ b/Engine/source/T3D/components/Component.h @@ -0,0 +1,197 @@ +//----------------------------------------------------------------------------- +// 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 COMPONENT_H +#define COMPONENT_H + +#ifndef _NETOBJECT_H_ +#include "sim/netObject.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif + +class Entity; + +struct ComponentField +{ + StringTableEntry mFieldName; + StringTableEntry mFieldDescription; + + S32 mFieldType; + StringTableEntry mUserData; + + StringTableEntry mDefaultValue; + + StringTableEntry mGroup; + + StringTableEntry mDependency; + + bool mHidden; +}; + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class Component : public NetObject, public UpdateInterface +{ + typedef NetObject Parent; + +protected: + StringTableEntry mFriendlyName; + StringTableEntry mDescription; + + StringTableEntry mFromResource; + StringTableEntry mComponentGroup; + StringTableEntry mComponentType; + StringTableEntry mNetworkType; + StringTableEntry mTemplateName; + + Vector mDependencies; + Vector mFields; + + bool mNetworked; + + U32 componentIdx; + + Entity* mOwner; + bool mHidden; + bool mEnabled; + +public: + Component(); + virtual ~Component(); + DECLARE_CONOBJECT(Component); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void packToStream(Stream &stream, U32 tabStop, S32 behaviorID, U32 flags = 0); + + //This is called when we are added to an entity + virtual void onComponentAdd(); + //This is called when we are removed from an entity + virtual void onComponentRemove(); + + //This is called when a different component is added to our owner entity + virtual void componentAddedToOwner(Component *comp); + //This is called when a different component is removed from our owner entity + virtual void componentRemovedFromOwner(Component *comp); + + virtual void ownerTransformSet(MatrixF *mat); + + void setOwner(Entity* pOwner); + inline Entity *getOwner() { return mOwner ? mOwner : NULL; } + static bool setOwner(void *object, const char *index, const char *data) { return true; } + + bool isEnabled() { return mEnabled; } + void setEnabled(bool toggle) { mEnabled = toggle; setMaskBits(EnableMask); } + + bool isActive() { return mEnabled && mOwner != NULL; } + + static bool _setEnabled(void *object, const char *index, const char *data); + + virtual void processTick(); + virtual void interpolateTick(F32 dt){} + virtual void advanceTime(F32 dt){} + + /// @name Adding Named Fields + /// @{ + + /// Adds a named field to a Component that can specify a description, data type, default value and userData + /// + /// @param fieldName The name of the Field + /// @param desc The Description of the Field + /// @param type The Type of field that this is, example 'Text' or 'Bool' + /// @param defaultValue The Default value of this field + /// @param userData An extra optional field that can be used for user data + void addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue = NULL, const char *userData = NULL, bool hidden = false); + + /// Returns the number of ComponentField's on this template + inline S32 getComponentFieldCount() { return mFields.size(); }; + + /// Gets a ComponentField by its index in the mFields vector + /// @param idx The index of the field in the mField vector + inline ComponentField *getComponentField(S32 idx) + { + if (idx < 0 || idx >= mFields.size()) + return NULL; + + return &mFields[idx]; + } + + ComponentField *getComponentField(const char* fieldName); + + const char* getComponentType() { return mComponentType; } + + const char *getDescriptionText(const char *desc); + + const char *getName() { return mTemplateName; } + + const char *getFriendlyName() { return mFriendlyName; } + + bool isNetworked() { return mNetworked; } + + void beginFieldGroup(const char* groupName); + void endFieldGroup(); + + void addDependency(StringTableEntry name); + /// @} + + /// @name Description + /// @{ + static bool setDescription(void *object, const char *index, const char *data); + static const char* getDescription(void* obj, const char* data); + + /// @Primary usage functions + /// @These are used by the various engine-based behaviors to integrate with the component classes + enum NetMaskBits + { + InitialUpdateMask = BIT(0), + OwnerMask = BIT(1), + UpdateMask = BIT(2), + EnableMask = BIT(3), + NextFreeMask = BIT(4) + }; + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + /// @} + + Signal< void(SimObject*, String, String) > onDataSet; + virtual void setDataField(StringTableEntry slotName, const char *array, const char *value); + + virtual void onStaticModified(const char* slotName, const char* newValue); ///< Called when a static field is modified. + virtual void onDynamicModified(const char* slotName, const char*newValue = NULL); ///< Called when a dynamic field is modified. + + /// This is what we actually use to check if the modified field is one of our behavior fields. If it is, we update and make the correct callbacks + void checkComponentFieldModified(const char* slotName, const char* newValue); + + virtual void checkDependencies(){} +}; + +#endif // COMPONENT_H diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.cpp b/Engine/source/T3D/components/Game/StateMachineComponent.cpp new file mode 100644 index 000000000..68058af59 --- /dev/null +++ b/Engine/source/T3D/components/Game/StateMachineComponent.cpp @@ -0,0 +1,215 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/game/StateMachineComponent.h" + +#include "platform/platform.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "ts/tsShapeInstance.h" +#include "core/stream/bitStream.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" + +IMPLEMENT_CALLBACK( StateMachineComponent, onStateChange, void, (), (), + "@brief Called when we collide with another object.\n\n" + "@param obj The ShapeBase object\n" + "@param collObj The object we collided with\n" + "@param vec Collision impact vector\n" + "@param len Length of the impact vector\n" ); + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// + +StateMachineComponent::StateMachineComponent() : Component() +{ + mFriendlyName = "State Machine"; + mComponentType = "Game"; + + mDescription = getDescriptionText("A generic state machine."); + + mStateMachineFile = ""; + + //doesn't need to be networked + mNetworked = false; + mNetFlags.clear(); +} + +StateMachineComponent::~StateMachineComponent() +{ + for(S32 i = 0;i < mFields.size();++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(StateMachineComponent); + +bool StateMachineComponent::onAdd() +{ + if(! Parent::onAdd()) + return false; + + // Register for the resource change signal. + ResourceManager::get().getChangedSignal().notify(this, &StateMachineComponent::_onResourceChanged); + + mStateMachine.onStateChanged.notify(this, &StateMachineComponent::onStateChanged); + + return true; +} + +void StateMachineComponent::onRemove() +{ + Parent::onRemove(); +} + +U32 StateMachineComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + return retMask; +} + +void StateMachineComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); +} + +//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior +void StateMachineComponent::onComponentAdd() +{ + Parent::onComponentAdd(); +} + +void StateMachineComponent::onComponentRemove() +{ + Parent::onComponentRemove(); +} + +void StateMachineComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addProtectedField("stateMachineFile", TypeFilename, Offset(mStateMachineFile, StateMachineComponent), + &_setSMFile, &defaultProtectedGetFn, "The sim time of when we started this state"); +} + +bool StateMachineComponent::_setSMFile(void *object, const char *index, const char *data) +{ + StateMachineComponent* smComp = static_cast(object); + if (smComp) + { + smComp->setStateMachineFile(data); + smComp->loadStateMachineFile(); + + return true; + } + + return false; +} + +void StateMachineComponent::_onResourceChanged(const Torque::Path &path) +{ + if (path != Torque::Path(mStateMachineFile)) + return; + + loadStateMachineFile(); +} + +void StateMachineComponent::loadStateMachineFile() +{ + if (!dStrIsEmpty(mStateMachineFile)) + { + mStateMachine.mStateMachineFile = mStateMachineFile; + mStateMachine.loadStateMachineFile(); + + //now that it's loaded, we need to parse the SM's fields and set them as script vars on ourselves + S32 smFieldCount = mStateMachine.getFieldsCount(); + + for (U32 i = 0; i < smFieldCount; i++) + { + StateMachine::StateField field = mStateMachine.getField(i); + + char buffer[128]; + + if (field.fieldType == StateMachine::StateField::BooleanType) + { + dSprintf(buffer, sizeof(buffer), "%b", field.triggerBoolVal); + setDataField(field.name, NULL, buffer); + } + else if (field.fieldType == StateMachine::StateField::NumberType) + { + dSprintf(buffer, sizeof(buffer), "%g", field.triggerNumVal); + setDataField(field.name, NULL, buffer); + } + else if (field.fieldType == StateMachine::StateField::StringType) + { + setDataField(field.name, NULL, field.triggerStringVal); + } + } + } +} + +void StateMachineComponent::processTick() +{ + if (!isServerObject() || !isActive()) + return; + + mStateMachine.update(); +} + +void StateMachineComponent::onDynamicModified( const char* slotName, const char* newValue ) +{ + Parent::onDynamicModified(slotName, newValue); + + StringTableEntry fieldName = StringTable->insert(slotName); + mStateMachine.checkTransitions(fieldName, newValue); +} + +void StateMachineComponent::onStaticModified( const char* slotName, const char* newValue ) +{ + Parent::onStaticModified(slotName, newValue); + + StringTableEntry fieldName = StringTable->insert(slotName); + mStateMachine.checkTransitions(fieldName, newValue); +} + +void StateMachineComponent::onStateChanged(StateMachine* sm, S32 stateIdx) +{ + //do a script callback, if we have one + //check if we have a function for that, and then also check if our owner does + StringTableEntry callbackName = mStateMachine.getCurrentState().callbackName; + + if (isMethod(callbackName)) + Con::executef(this, callbackName); + + if (mOwner->isMethod(callbackName)) + Con::executef(mOwner, callbackName); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.h b/Engine/source/T3D/components/Game/StateMachineComponent.h new file mode 100644 index 000000000..00fc4c27e --- /dev/null +++ b/Engine/source/T3D/components/Game/StateMachineComponent.h @@ -0,0 +1,81 @@ +//----------------------------------------------------------------------------- +// 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 STATE_MACHINE_COMPONENT_H +#define STATE_MACHINE_COMPONENT_H + +#ifndef COMPONENT_H + #include "T3D/Components/Component.h" +#endif +#ifndef STATE_MACHINE_H +#include "T3D/components/Game/stateMachine.h" +#endif + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class StateMachineComponent : public Component +{ + typedef Component Parent; + +public: + StateMachine mStateMachine; + +protected: + StringTableEntry mStateMachineFile; + +public: + StateMachineComponent(); + virtual ~StateMachineComponent(); + DECLARE_CONOBJECT(StateMachineComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + virtual void onComponentRemove(); + + void _onResourceChanged(const Torque::Path &path); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + virtual void processTick(); + + virtual void onDynamicModified(const char* slotName, const char* newValue); + virtual void onStaticModified(const char* slotName, const char* newValue); + + virtual void loadStateMachineFile(); + + void setStateMachineFile(const char* fileName) { mStateMachineFile = StringTable->insert(fileName); } + + static bool _setSMFile(void *object, const char *index, const char *data); + + void onStateChanged(StateMachine* sm, S32 stateIdx); + + //Callbacks + DECLARE_CALLBACK(void, onStateChange, ()); +}; + +#endif \ No newline at end of file diff --git a/Engine/source/T3D/components/Game/stateMachine.cpp b/Engine/source/T3D/components/Game/stateMachine.cpp new file mode 100644 index 000000000..867e9cb19 --- /dev/null +++ b/Engine/source/T3D/components/Game/stateMachine.cpp @@ -0,0 +1,434 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Game/stateMachine.h" + +StateMachine::StateMachine() +{ + mStateStartTime = -1; + mStateTime = 0; + + mStartingState = ""; + + mCurCreateState = NULL; +} + +StateMachine::~StateMachine() +{ +} + +void StateMachine::loadStateMachineFile() +{ + if (!mXMLReader) + { + SimXMLDocument *xmlrdr = new SimXMLDocument(); + xmlrdr->registerObject(); + + mXMLReader = xmlrdr; + } + + bool hasStartState = false; + + if (!dStrIsEmpty(mStateMachineFile)) + { + //use our xml reader to parse the file! + SimXMLDocument *reader = mXMLReader.getObject(); + if (!reader->loadFile(mStateMachineFile)) + Con::errorf("Could not load state machine file: &s", mStateMachineFile); + + if (!reader->pushFirstChildElement("StateMachine")) + return; + + //find our starting state + if (reader->pushFirstChildElement("StartingState")) + { + mStartingState = reader->getData(); + reader->popElement(); + hasStartState = true; + } + + readStates(); + } + + if (hasStartState) + mCurrentState = getStateByName(mStartingState); + + mStateStartTime = -1; + mStateTime = 0; +} + +void StateMachine::readStates() +{ + SimXMLDocument *reader = mXMLReader.getObject(); + + //iterate through our states now! + if (reader->pushFirstChildElement("State")) + { + //get our first state + State firstState; + + readStateName(&firstState, reader); + readStateScriptFunction(&firstState, reader); + + readTransitions(firstState); + + mStates.push_back(firstState); + + //now, iterate the siblings + while (reader->nextSiblingElement("State")) + { + State newState; + readStateName(&newState, reader); + readStateScriptFunction(&newState, reader); + + readTransitions(newState); + + mStates.push_back(newState); + } + } +} + +void StateMachine::readTransitions(State ¤tState) +{ + SimXMLDocument *reader = mXMLReader.getObject(); + + //iterate through our states now! + if (reader->pushFirstChildElement("Transition")) + { + //get our first state + StateTransition firstTransition; + + readTransitonTarget(&firstTransition, reader); + + readConditions(firstTransition); + + currentState.mTransitions.push_back(firstTransition); + + //now, iterate the siblings + while (reader->nextSiblingElement("Transition")) + { + StateTransition newTransition; + readTransitonTarget(&newTransition, reader); + + readConditions(newTransition); + + currentState.mTransitions.push_back(newTransition); + } + + reader->popElement(); + } +} + +void StateMachine::readConditions(StateTransition ¤tTransition) +{ + SimXMLDocument *reader = mXMLReader.getObject(); + + //iterate through our states now! + if (reader->pushFirstChildElement("Rule")) + { + //get our first state + StateTransition::Condition firstCondition; + StateField firstField; + bool fieldRead = false; + + readFieldName(&firstField, reader); + firstCondition.field = firstField; + + readFieldComparitor(&firstCondition, reader); + + readFieldValue(&firstCondition.field, reader); + + currentTransition.mTransitionRules.push_back(firstCondition); + + //now, iterate the siblings + while (reader->nextSiblingElement("Transition")) + { + StateTransition::Condition newCondition; + StateField newField; + + readFieldName(&newField, reader); + newCondition.field = newField; + + readFieldComparitor(&newCondition, reader); + + readFieldValue(&newCondition.field, reader); + + currentTransition.mTransitionRules.push_back(newCondition); + } + + reader->popElement(); + } +} + +S32 StateMachine::parseComparitor(const char* comparitorName) +{ + S32 targetType = -1; + + if (!dStrcmp("GreaterThan", comparitorName)) + targetType = StateMachine::StateTransition::Condition::GeaterThan; + else if (!dStrcmp("GreaterOrEqual", comparitorName)) + targetType = StateMachine::StateTransition::Condition::GreaterOrEqual; + else if (!dStrcmp("LessThan", comparitorName)) + targetType = StateMachine::StateTransition::Condition::LessThan; + else if (!dStrcmp("LessOrEqual", comparitorName)) + targetType = StateMachine::StateTransition::Condition::LessOrEqual; + else if (!dStrcmp("Equals", comparitorName)) + targetType = StateMachine::StateTransition::Condition::Equals; + else if (!dStrcmp("True", comparitorName)) + targetType = StateMachine::StateTransition::Condition::True; + else if (!dStrcmp("False", comparitorName)) + targetType = StateMachine::StateTransition::Condition::False; + else if (!dStrcmp("Negative", comparitorName)) + targetType = StateMachine::StateTransition::Condition::Negative; + else if (!dStrcmp("Positive", comparitorName)) + targetType = StateMachine::StateTransition::Condition::Positive; + else if (!dStrcmp("DoesNotEqual", comparitorName)) + targetType = StateMachine::StateTransition::Condition::DoesNotEqual; + + return targetType; +} + +void StateMachine::update() +{ + //we always check if there's a timout transition, as that's the most generic transition possible. + F32 curTime = Sim::getCurrentTime(); + + if (mStateStartTime == -1) + mStateStartTime = curTime; + + mStateTime = curTime - mStateStartTime; + + char buffer[64]; + dSprintf(buffer, sizeof(buffer), "%g", mStateTime); + + checkTransitions("stateTime", buffer); +} + +void StateMachine::checkTransitions(const char* slotName, const char* newValue) +{ + //because we use our current state's fields as dynamic fields on the instance + //we'll want to catch any fields being set so we can treat changes as transition triggers if + //any of the transitions on this state call for it + + //One example would be in order to implement burst fire on a weapon state machine. + //The behavior instance has a dynamic variable set up like: GunStateMachine.burstShotCount = 0; + + //We also have a transition in our fire state, as: GunStateMachine.addTransition("FireState", "burstShotCount", "DoneShooting", 3); + //What that does is for our fire state, we check the dynamicField burstShotCount if it's equal or greater than 3. If it is, we perform the transition. + + //As state fields are handled as dynamicFields for the instance, regular dynamicFields are processed as well as state fields. So we can use the regular + //dynamic fields for our transitions, to act as 'global' variables that are state-agnostic. Alternately, we can use state-specific fields, such as a transition + //like this: + //GunStateMachine.addTransition("IdleState", "Fidget", "Timeout", ">=", 5000); + + //That uses the the timeout field, which is reset each time the state changes, and so state-specific, to see if it's been 5 seconds. If it has been, we transition + //to our fidget state + + //so, lets check our current transitions + //now that we have the type, check our transitions! + for (U32 t = 0; t < mCurrentState.mTransitions.size(); t++) + { + //if (!dStrcmp(mCurrentState.mTransitions[t]., slotName)) + { + //found a transition looking for this variable, so do work + //first, figure out what data type thie field is + //S32 type = getVariableType(newValue); + + bool fail = false; + bool match = false; + S32 ruleCount = mCurrentState.mTransitions[t].mTransitionRules.size(); + + for (U32 r = 0; r < ruleCount; r++) + { + const char* fieldName = mCurrentState.mTransitions[t].mTransitionRules[r].field.name; + if (!dStrcmp(fieldName, slotName)) + { + match = true; + //now, check the value with the comparitor and see if we do the transition. + if (!passComparitorCheck(newValue, mCurrentState.mTransitions[t].mTransitionRules[r])) + { + fail = true; + break; + } + } + } + + //If we do have a transition rule for this field, and we didn't fail on the condition, go ahead and switch states + if (match && !fail) + { + setState(mCurrentState.mTransitions[t].mStateTarget); + + return; + } + } + } +} + +bool StateMachine::passComparitorCheck(const char* var, StateTransition::Condition transitionRule) +{ + F32 num = dAtof(var); + switch (transitionRule.field.fieldType) + { + case StateField::Type::VectorType: + switch (transitionRule.triggerComparitor) + { + case StateTransition::Condition::Equals: + case StateTransition::Condition::GeaterThan: + case StateTransition::Condition::GreaterOrEqual: + case StateTransition::Condition::LessThan: + case StateTransition::Condition::LessOrEqual: + case StateTransition::Condition::DoesNotEqual: + //do + break; + default: + return false; + }; + case StateField::Type::StringType: + switch (transitionRule.triggerComparitor) + { + case StateTransition::Condition::Equals: + if (!dStrcmp(var, transitionRule.field.triggerStringVal)) + return true; + else + return false; + case StateTransition::Condition::DoesNotEqual: + if (dStrcmp(var, transitionRule.field.triggerStringVal)) + return true; + else + return false; + default: + return false; + }; + case StateField::Type::BooleanType: + switch (transitionRule.triggerComparitor) + { + case StateTransition::Condition::TriggerValueTarget::True: + if (dAtob(var)) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::False: + if (dAtob(var)) + return false; + else + return true; + default: + return false; + }; + case StateField::Type::NumberType: + switch (transitionRule.triggerComparitor) + { + case StateTransition::Condition::TriggerValueTarget::Equals: + if (num == transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::GeaterThan: + if (num > transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::GreaterOrEqual: + if (num >= transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::LessThan: + if (num < transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::LessOrEqual: + if (num <= transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::DoesNotEqual: + if (num != transitionRule.field.triggerNumVal) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::Positive: + if (num > 0) + return true; + else + return false; + case StateTransition::Condition::TriggerValueTarget::Negative: + if (num < 0) + return true; + else + return false; + default: + return false; + }; + default: + return false; + }; +} + +void StateMachine::setState(const char* stateName, bool clearFields) +{ + State oldState = mCurrentState; + StringTableEntry sName = StringTable->insert(stateName); + for (U32 i = 0; i < mStates.size(); i++) + { + //if(!dStrcmp(mStates[i]->stateName, stateName)) + if (!dStrcmp(mStates[i].stateName,sName)) + { + mCurrentState = mStates[i]; + mStateStartTime = Sim::getCurrentTime(); + + onStateChanged.trigger(this, i); + return; + } + } +} + +const char* StateMachine::getStateByIndex(S32 index) +{ + if (index >= 0 && mStates.size() > index) + return mStates[index].stateName; + else + return ""; +} + +StateMachine::State& StateMachine::getStateByName(const char* name) +{ + StringTableEntry stateName = StringTable->insert(name); + + for (U32 i = 0; i < mStates.size(); i++) + { + if (!dStrcmp(stateName, mStates[i].stateName)) + return mStates[i]; + } +} + +S32 StateMachine::findFieldByName(const char* name) +{ + for (U32 i = 0; i < mFields.size(); i++) + { + if (!dStrcmp(mFields[i].name, name)) + return i; + } + + return -1; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Game/stateMachine.h b/Engine/source/T3D/components/Game/stateMachine.h new file mode 100644 index 000000000..8bf7b15fb --- /dev/null +++ b/Engine/source/T3D/components/Game/stateMachine.h @@ -0,0 +1,259 @@ +//----------------------------------------------------------------------------- +// 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 STATE_MACHINE_H +#define STATE_MACHINE_H + +#ifndef _SIMBASE_H_ +#include "console/simBase.h" +#endif +#ifndef _OBJECTTYPES_H_ +#include "T3D/objectTypes.h" +#endif +#ifndef _MMATH_H_ +#include "math/mMath.h" +#endif +#ifndef _XMLDOC_H_ +#include "console/SimXMLDocument.h" +#endif + +class StateMachine +{ +public: + struct StateField + { + StringTableEntry name; + + bool triggerBoolVal; + float triggerNumVal; + Point3F triggerVectorVal; + String triggerStringVal; + + enum Type + { + BooleanType = 0, + NumberType, + VectorType, + StringType + }fieldType; + }; + + struct UniqueReference + { + SimObject* referenceObj; + const char* referenceVar; + const char* uniqueName; + }; + + struct StateTransition + { + struct Condition + { + enum TriggerValueTarget + { + Equals = 0, + GeaterThan, + LessThan, + GreaterOrEqual, + LessOrEqual, + True, + False, + Positive, + Negative, + DoesNotEqual + }; + + StateField field; + + TriggerValueTarget triggerComparitor; + + UniqueReference *valUniqueRef; + }; + + StringTableEntry mName; + StringTableEntry mStateTarget; + Vector mTransitionRules; + }; + + struct State + { + Vector mTransitions; + + StringTableEntry stateName; + + StringTableEntry callbackName; + }; + + StringTableEntry mStateMachineFile; + +protected: + Vector mStates; + + Vector mFields; + + Vector mUniqueReferences; + + State mCurrentState; + + F32 mStateStartTime; + F32 mStateTime; + + StringTableEntry mStartingState; + + State *mCurCreateSuperState; + State *mCurCreateState; + + SimObjectPtr mXMLReader; + +public: + StateMachine(); + virtual ~StateMachine(); + + void update(); + + void loadStateMachineFile(); + void readStates(); + void readTransitions(State ¤tState); + void readConditions(StateTransition &newTransition); + + void setState(const char* stateName, bool clearFields = true); + + const char* getCurrentStateName() { return mCurrentState.stateName; } + State& getCurrentState() { + return mCurrentState; + } + + S32 getStateCount() { return mStates.size(); } + const char* getStateByIndex(S32 index); + State& getStateByName(const char* name); + + void checkTransitions(const char* slotName, const char* newValue); + + bool passComparitorCheck(const char* var, StateTransition::Condition transitionRule); + + S32 findFieldByName(const char* name); + + S32 getFieldsCount() { return mFields.size(); } + + StateField getField(U32 index) + { + if (index <= mFields.size()) + return mFields[index]; + } + + Signal< void(StateMachine*, S32 stateIdx) > StateMachine::onStateChanged; + + // + inline bool readStateName(State* state, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("Name")) + { + state->stateName = reader->getData(); + reader->popElement(); + + return true; + } + + return false; + } + inline bool readStateScriptFunction(State* state, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("ScriptFunction")) + { + state->callbackName = reader->getData(); + reader->popElement(); + + return true; + } + + return false; + } + inline bool readTransitonTarget(StateTransition* transition, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("StateTarget")) + { + transition->mStateTarget = reader->getData(); + reader->popElement(); + + return true; + } + + return false; + } + // + inline bool readFieldName(StateField* newField, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("FieldName")) + { + newField->name = reader->getData(); + reader->popElement(); + + return true; + } + + return false; + } + inline bool readFieldComparitor(StateTransition::Condition* condition, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("Comparitor")) + { + S32 compIdx = parseComparitor(reader->getData()); + condition->triggerComparitor = static_cast(compIdx); + reader->popElement(); + + return true; + } + + return false; + } + inline bool readFieldValue(StateField* field, SimXMLDocument* reader) + { + if (reader->pushFirstChildElement("NumValue")) + { + field->fieldType = StateField::NumberType; + field->triggerNumVal = dAtof(reader->getData()); + reader->popElement(); + return true; + } + else if (reader->pushFirstChildElement("StringValue")) + { + field->fieldType = StateField::StringType; + field->triggerStringVal = reader->getData(); + reader->popElement(); + return true; + } + else if (reader->pushFirstChildElement("BoolValue")) + { + field->fieldType = StateField::BooleanType; + field->triggerBoolVal = dAtob(reader->getData()); + reader->popElement(); + return true; + } + + return false; + } + +private: + S32 parseComparitor(const char* comparitorName); +}; + +#endif \ No newline at end of file diff --git a/Engine/source/T3D/components/Game/triggerComponent.cpp b/Engine/source/T3D/components/Game/triggerComponent.cpp new file mode 100644 index 000000000..df61859ce --- /dev/null +++ b/Engine/source/T3D/components/Game/triggerComponent.cpp @@ -0,0 +1,358 @@ +//----------------------------------------------------------------------------- +// Torque Game Engine +// Copyright (C) GarageGames.com, Inc. +//----------------------------------------------------------------------------- +#include "console/consoleTypes.h" +#include "T3D/Components/game/TriggerComponent.h" +#include "core/util/safeDelete.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "core/stream/bitStream.h" +#include "console/engineAPI.h" +#include "sim/netConnection.h" +#include "T3D/gameBase/gameConnection.h" +#include "T3D/Components/coreInterfaces.h" +#include "math/mathUtils.h" +#include "collision/concretePolyList.h" +#include "collision/clippedPolyList.h" + +#include "gfx/sim/debugDraw.h" + +IMPLEMENT_CALLBACK( TriggerComponent, onEnterViewCmd, void, + ( Entity* cameraEnt, bool firstTimeSeeing ), ( cameraEnt, firstTimeSeeing ), + "@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n" + + "@param trigger the Trigger instance whose volume the object entered\n" + "@param obj the object that entered the volume of the Trigger instance\n" ); + +IMPLEMENT_CALLBACK( TriggerComponent, onExitViewCmd, void, + ( Entity* cameraEnt ), ( cameraEnt ), + "@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n" + + "@param trigger the Trigger instance whose volume the object entered\n" + "@param obj the object that entered the volume of the Trigger instance\n" ); + +IMPLEMENT_CALLBACK( TriggerComponent, onUpdateInViewCmd, void, + ( Entity* cameraEnt ), ( cameraEnt ), + "@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n" + + "@param trigger the Trigger instance whose volume the object entered\n" + "@param obj the object that entered the volume of the Trigger instance\n" ); + +IMPLEMENT_CALLBACK( TriggerComponent, onUpdateOutOfViewCmd, void, + ( Entity* cameraEnt ), ( cameraEnt ), + "@brief Called when an object enters the volume of the Trigger instance using this TriggerData.\n\n" + + "@param trigger the Trigger instance whose volume the object entered\n" + "@param obj the object that entered the volume of the Trigger instance\n" ); + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// + +TriggerComponent::TriggerComponent() : Component() +{ + mObjectList.clear(); + + mVisible = false; + + mFriendlyName = "Trigger"; + mComponentType = "Trigger"; + + mDescription = getDescriptionText("Calls trigger events when a client starts and stops seeing it. Also ticks while visible to clients."); +} + +TriggerComponent::~TriggerComponent() +{ + for(S32 i = 0;i < mFields.size();++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(TriggerComponent); + + +bool TriggerComponent::onAdd() +{ + if(! Parent::onAdd()) + return false; + + return true; +} + +void TriggerComponent::onRemove() +{ + Parent::onRemove(); +} + +//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior +void TriggerComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + CollisionInterface *colInt = mOwner->getComponent(); + + if(colInt) + { + colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject); + } +} + +void TriggerComponent::onComponentRemove() +{ + CollisionInterface *colInt = mOwner->getComponent(); + + if(colInt) + { + colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject); + } + + Parent::onComponentRemove(); +} + +void TriggerComponent::componentAddedToOwner(Component *comp) +{ + if (comp->getId() == getId()) + return; + + CollisionInterface *colInt = mOwner->getComponent(); + + if (colInt) + { + colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject); + } +} + +void TriggerComponent::componentRemovedFromOwner(Component *comp) +{ + if (comp->getId() == getId()) //????????? + return; + + CollisionInterface *colInt = mOwner->getComponent(); + + if (colInt) + { + colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject); + } +} + +void TriggerComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addField("visibile", TypeBool, Offset( mVisible, TriggerComponent ), "" ); + + addField("onEnterViewCmd", TypeCommand, Offset(mEnterCommand, TriggerComponent), ""); + addField("onExitViewCmd", TypeCommand, Offset(mOnExitCommand, TriggerComponent), ""); + addField("onUpdateInViewCmd", TypeCommand, Offset(mOnUpdateInViewCmd, TriggerComponent), ""); +} + +U32 TriggerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + return retMask; +} + +void TriggerComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); +} + +void TriggerComponent::potentialEnterObject(SceneObject *collider) +{ + if(testObject(collider)) + { + bool found = false; + for(U32 i=0; i < mObjectList.size(); i++) + { + if(mObjectList[i]->getId() == collider->getId()) + { + found = true; + break; + } + } + + if (!found) + { + mObjectList.push_back(collider); + + if (!mEnterCommand.isEmpty()) + { + String command = String("%obj = ") + collider->getIdString() + ";" + + String("%this = ") + getIdString() + ";" + mEnterCommand; + Con::evaluate(command.c_str()); + } + + //onEnterTrigger_callback(this, enter); + } + } +} + +bool TriggerComponent::testObject(SceneObject* enter) +{ + //First, test to early out + Box3F enterBox = enter->getWorldBox(); + + //if(!mOwner->getWorldBox().intersect(enterBox) || !) + // return false; + + //We're still here, so we should do actual work + //We're going to be + ConcretePolyList mClippedList; + + SphereF sphere; + sphere.center = (mOwner->getWorldBox().minExtents + mOwner->getWorldBox().maxExtents) * 0.5; + VectorF bv = mOwner->getWorldBox().maxExtents - sphere.center; + sphere.radius = bv.len(); + + Entity* enterEntity = dynamic_cast(enter); + if(enterEntity) + { + //quick early out. If the bounds don't overlap, it cannot be colliding or inside + if (!mOwner->getWorldBox().isOverlapped(enterBox)) + return false; + + //check if the entity has a collision shape + CollisionInterface *cI = enterEntity->getComponent(); + if (cI) + { + cI->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere); + + if (!mClippedList.isEmpty()) + { + //well, it's clipped with, or inside, our bounds + //now to test the clipped list against our own collision mesh + CollisionInterface *myCI = mOwner->getComponent(); + + //wait, how would we NOT have this? + if (myCI) + { + //anywho, build our list and then we'll check intersections + ClippedPolyList myList; + + myList.setTransform(&(mOwner->getTransform()), mOwner->getScale()); + myList.setObject(mOwner); + + myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere); + + bool test = true; + } + } + } + } + + return mClippedList.isEmpty() == false; +} + +void TriggerComponent::processTick() +{ + Parent::processTick(); + + if (!isActive()) + return; + + //get our list of active clients, and see if they have cameras, if they do, build a frustum and see if we exist inside that + mVisible = false; + if(isServerObject()) + { + for(U32 i=0; i < mObjectList.size(); i++) + { + if(!testObject(mObjectList[i])) + { + if (!mOnExitCommand.isEmpty()) + { + String command = String("%obj = ") + mObjectList[i]->getIdString() + ";" + + String("%this = ") + getIdString() + ";" + mOnExitCommand; + Con::evaluate(command.c_str()); + } + + mObjectList.erase(i); + //mDataBlock->onLeaveTrigger_callback( this, remove ); + //onLeaveTrigger_callback(this, remove); + } + } + + /*if (!mTickCommand.isEmpty()) + Con::evaluate(mTickCommand.c_str()); + + if (mObjects.size() != 0) + onTickTrigger_callback(this);*/ + } +} + +void TriggerComponent::visualizeFrustums(F32 renderTimeMS) +{ + +} + +GameConnection* TriggerComponent::getConnection(S32 connectionID) +{ + for(NetConnection *conn = NetConnection::getConnectionList(); conn; conn = conn->getNext()) + { + GameConnection* gameConn = dynamic_cast(conn); + + if (!gameConn || (gameConn && gameConn->isAIControlled())) + continue; + + if(connectionID == gameConn->getId()) + return gameConn; + } + + return NULL; +} + +void TriggerComponent::addClient(S32 clientID) +{ + +} + +void TriggerComponent::removeClient(S32 clientID) +{ + +} + +DefineEngineMethod( TriggerComponent, addClient, void, + ( S32 clientID ), ( -1 ), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)" ) +{ + if(clientID == -1) + return; + + object->addClient( clientID ); +} + +DefineEngineMethod( TriggerComponent, removeClient, void, + ( S32 clientID ), ( -1 ), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)" ) +{ + if(clientID == -1) + return; + + object->removeClient( clientID ); +} + +DefineEngineMethod( TriggerComponent, visualizeFrustums, void, + (F32 renderTime), (1000), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)" ) +{ + object->visualizeFrustums(renderTime); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Game/triggerComponent.h b/Engine/source/T3D/components/Game/triggerComponent.h new file mode 100644 index 000000000..3b790f27e --- /dev/null +++ b/Engine/source/T3D/components/Game/triggerComponent.h @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// Torque Game Engine +// Copyright (C) GarageGames.com, Inc. +//----------------------------------------------------------------------------- +#ifndef _TRIGGER_COMPONENT_H_ +#define _TRIGGER_COMPONENT_H_ + +#ifndef _COMPONENT_H_ +#include "T3D/Components/Component.h" +#endif + +#ifndef _ENTITY_H_ +#include "T3D/Entity.h" +#endif + +#ifndef _COLLISION_INTERFACES_H_ +#include "T3D/Components/collision/collisionInterfaces.h" +#endif + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class TriggerComponent : public Component +{ + typedef Component Parent; + +protected: + Vector mObjectList; + + bool mVisible; + + String mEnterCommand; + String mOnExitCommand; + String mOnUpdateInViewCmd; + +public: + TriggerComponent(); + virtual ~TriggerComponent(); + DECLARE_CONOBJECT(TriggerComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + virtual void onComponentRemove(); + + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + void potentialEnterObject(SceneObject *collider); + + bool testObject(SceneObject* enter); + + virtual void processTick(); + + GameConnection* getConnection(S32 connectionID); + + void addClient(S32 clientID); + void removeClient(S32 clientID); + + void visualizeFrustums(F32 renderTimeMS); + + DECLARE_CALLBACK(void, onEnterViewCmd, (Entity* cameraEnt, bool firstTimeSeeing)); + DECLARE_CALLBACK(void, onExitViewCmd, (Entity* cameraEnt)); + DECLARE_CALLBACK(void, onUpdateInViewCmd, (Entity* cameraEnt)); + DECLARE_CALLBACK(void, onUpdateOutOfViewCmd, (Entity* cameraEnt)); +}; + +#endif // _EXAMPLEBEHAVIOR_H_ diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.cpp b/Engine/source/T3D/components/Physics/physicsBehavior.cpp new file mode 100644 index 000000000..3737abc56 --- /dev/null +++ b/Engine/source/T3D/components/Physics/physicsBehavior.cpp @@ -0,0 +1,368 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Physics/physicsBehavior.h" +#include "platform/platform.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "ts/tsShapeInstance.h" +#include "core/stream/bitStream.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" +#include "T3D/gameBase/gameConnection.h" +#include "T3D/containerQuery.h" +#include "math/mathIO.h" + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +PhysicsComponent::PhysicsComponent() : Component() +{ + addComponentField("isStatic", "If enabled, object will not simulate physics", "bool", "0", ""); + addComponentField("gravity", "The direction of gravity affecting this object, as a vector", "vector", "0 0 -9", ""); + addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", ""); + addComponentField("mass", "The mass of the object", "float", "1", ""); + + mStatic = false; + mAtRest = false; + mAtRestCounter = 0; + + mGravity = VectorF(0, 0, 0); + mVelocity = VectorF(0, 0, 0); + mDrag = 0.7f; + mMass = 1.f; + + mGravityMod = 1.f; + + csmAtRestTimer = 64; + sAtRestVelocity = 0.15f; + + mDelta.pos = Point3F(0, 0, 0); + mDelta.posVec = Point3F(0, 0, 0); + mDelta.warpTicks = mDelta.warpCount = 0; + mDelta.dt = 1; + mDelta.move = NullMove; + mPredictionCount = 0; +} + +PhysicsComponent::~PhysicsComponent() +{ + for(S32 i = 0;i < mFields.size();++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(PhysicsComponent); + +void PhysicsComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + // Initialize interpolation vars. + mDelta.rot[1] = mDelta.rot[0] = QuatF(mOwner->getTransform()); + mDelta.pos = mOwner->getPosition(); + mDelta.posVec = Point3F(0,0,0); +} + +void PhysicsComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addField("gravity", TypePoint3F, Offset(mGravity, PhysicsComponent)); + addField("velocity", TypePoint3F, Offset(mVelocity, PhysicsComponent)); + addField("isStatic", TypeBool, Offset(mStatic, PhysicsComponent)); +} + +U32 PhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if(stream->writeFlag(mask & VelocityMask)) + mathWrite( *stream, mVelocity ); + + if(stream->writeFlag(mask & UpdateMask)) + { + stream->writeFlag(mStatic); + stream->writeFlag(mAtRest); + stream->writeInt(mAtRestCounter,8); + + mathWrite( *stream, mGravity ); + + stream->writeFloat(mDrag, 12); + //stream->writeFloat(mMass, 12); + + stream->writeFloat(mGravityMod, 12); + } + return retMask; +} + +void PhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if(stream->readFlag()) + mathRead( *stream, &mVelocity ); + + if(stream->readFlag()) + { + mStatic = stream->readFlag(); + mAtRest = stream->readFlag(); + mAtRestCounter = stream->readInt(8); + + mathRead( *stream, &mGravity ); + + mDrag = stream->readFloat(12); + //mMass = stream->readFloat(12); + + mGravityMod = stream->readFloat(12); + } +} + +// +void PhysicsComponent::interpolateTick(F32 dt) +{ + Point3F pos = mDelta.pos + mDelta.posVec * dt; + //Point3F rot = mDelta.rot + mDelta.rotVec * dt; + + setRenderPosition(pos,dt); +} + +// +void PhysicsComponent::updateContainer() +{ + PROFILE_SCOPE( PhysicsBehaviorInstance_updateContainer ); + + // Update container drag and buoyancy properties + + // Set default values. + //mDrag = mDataBlock->drag; + //mBuoyancy = 0.0f; + //mGravityMod = 1.0; + //mAppliedForce.set(0,0,0); + + ContainerQueryInfo info; + info.box = mOwner->getWorldBox(); + info.mass = mMass; + + mOwner->getContainer()->findObjects(info.box, WaterObjectType|PhysicalZoneObjectType,findRouter,&info); + + //mWaterCoverage = info.waterCoverage; + //mLiquidType = info.liquidType; + //mLiquidHeight = info.waterHeight; + //setCurrentWaterObject( info.waterObject ); + + // This value might be useful as a datablock value, + // This is what allows the player to stand in shallow water (below this coverage) + // without jiggling from buoyancy + if (info.waterCoverage >= 0.25f) + { + // water viscosity is used as drag for in water. + // ShapeBaseData drag is used for drag outside of water. + // Combine these two components to calculate this ShapeBase object's + // current drag. + mDrag = ( info.waterCoverage * info.waterViscosity ) + + ( 1.0f - info.waterCoverage ) * mDrag; + //mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage; + } + + //mAppliedForce = info.appliedForce; + mGravityMod = info.gravityScale; +} +// +void PhysicsComponent::_updatePhysics() +{ + /*SAFE_DELETE( mOwner->mPhysicsRep ); + + if ( !PHYSICSMGR ) + return; + + if (mDataBlock->simpleServerCollision) + { + // We only need the trigger on the server. + if ( isServerObject() ) + { + PhysicsCollision *colShape = PHYSICSMGR->createCollision(); + colShape->addBox( mObjBox.getExtents() * 0.5f, MatrixF::Identity ); + + PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); + mPhysicsRep = PHYSICSMGR->createBody(); + mPhysicsRep->init( colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world ); + mPhysicsRep->setTransform( getTransform() ); + } + } + else + { + if ( !mShapeInstance ) + return; + + PhysicsCollision* colShape = mShapeInstance->getShape()->buildColShape( false, getScale() ); + + if ( colShape ) + { + PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ); + mPhysicsRep = PHYSICSMGR->createBody(); + mPhysicsRep->init( colShape, 0, PhysicsBody::BF_KINEMATIC, this, world ); + mPhysicsRep->setTransform( getTransform() ); + } + }*/ + return; +} + +PhysicsBody *PhysicsComponent::getPhysicsRep() +{ + /*if(mOwner) + { + Entity* ac = dynamic_cast(mOwner); + if(ac) + return ac->mPhysicsRep; + }*/ + return NULL; +} +// +void PhysicsComponent::setTransform(const MatrixF& mat) +{ + mOwner->setTransform(mat); + + if (!mStatic) + { + mAtRest = false; + mAtRestCounter = 0; + } + + if ( getPhysicsRep() ) + getPhysicsRep()->setTransform( mOwner->getTransform() ); + + setMaskBits(UpdateMask); +} + +void PhysicsComponent::setPosition(const Point3F& pos) +{ + MatrixF mat = mOwner->getTransform(); + if (mOwner->isMounted()) { + // Use transform from mounted object + //mOwner->getObjectMount()->getMountTransform( mOwner->getMountNode(), mMount.xfm, &mat ); + return; + } + else { + mat.setColumn(3,pos); + } + + mOwner->setTransform(mat); + + if ( getPhysicsRep() ) + getPhysicsRep()->setTransform( mat ); +} + + +void PhysicsComponent::setRenderPosition(const Point3F& pos, F32 dt) +{ + MatrixF mat = mOwner->getRenderTransform(); + if (mOwner->isMounted()) { + // Use transform from mounted object + //mOwner->getObjectMount()->getMountRenderTransform( dt, mOwner->getMountNode(), mMount.xfm, &mat ); + return; + } + else { + mat.setColumn(3,pos); + } + + mOwner->setRenderTransform(mat); +} + +void PhysicsComponent::updateVelocity(const F32 dt) +{ +} + +void PhysicsComponent::setVelocity(const VectorF& vel) +{ + mVelocity = vel; + + mAtRest = false; + mAtRestCounter = 0; + setMaskBits(VelocityMask); +} + +void PhysicsComponent::getVelocity(const Point3F& r, Point3F* v) +{ + *v = mVelocity; +} + +void PhysicsComponent::getOriginVector(const Point3F &p,Point3F* r) +{ + *r = p - mOwner->getObjBox().getCenter(); +} + +F32 PhysicsComponent::getZeroImpulse(const Point3F& r,const Point3F& normal) +{ + Point3F a,b,c; + + //set up our inverse matrix + MatrixF iv,qmat; + MatrixF inverse = MatrixF::Identity; + qmat = mOwner->getTransform(); + iv.mul(qmat,inverse); + qmat.transpose(); + inverse.mul(iv,qmat); + + mCross(r, normal, &a); + inverse.mulV(a, &b); + mCross(b, r, &c); + + return 1 / ((1/mMass) + mDot(c, normal)); +} + +void PhysicsComponent::accumulateForce(F32 dt, Point3F force) +{ + mVelocity += force * dt; +} + +void PhysicsComponent::applyImpulse(const Point3F&,const VectorF& vec) +{ + // Items ignore angular velocity + VectorF vel; + vel.x = vec.x / mMass; + vel.y = vec.y / mMass; + vel.z = vec.z / mMass; + setVelocity(mVelocity + vel); +} + +DefineEngineMethod( PhysicsComponent, applyImpulse, bool, ( Point3F pos, VectorF vel ),, + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + object->applyImpulse(pos,vel); + return true; +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.h b/Engine/source/T3D/components/Physics/physicsBehavior.h new file mode 100644 index 000000000..707fc15e5 --- /dev/null +++ b/Engine/source/T3D/components/Physics/physicsBehavior.h @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// Torque Game Engine +// Copyright (C) GarageGames.com, Inc. +//----------------------------------------------------------------------------- + +#ifndef _PHYSICSBEHAVIOR_H_ +#define _PHYSICSBEHAVIOR_H_ +#include "T3D/Components/Component.h" + +#ifndef __RESOURCE_H__ +#include "core/resource.h" +#endif +#ifndef _TSSHAPE_H_ +#include "ts/tsShape.h" +#endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef _ENTITY_H_ +#include "T3D/Entity.h" +#endif +#ifndef _CONVEX_H_ +#include "collision/convex.h" +#endif +#ifndef _BOXCONVEX_H_ +#include "collision/boxConvex.h" +#endif +#ifndef _RIGID_H_ +#include "T3D/rigid.h" +#endif +#ifndef _T3D_PHYSICS_PHYSICSBODY_H_ +#include "T3D/physics/physicsBody.h" +#endif + +#ifndef _RENDER_COMPONENT_INTERFACE_H_ +#include "T3D/Components/render/renderComponentInterface.h" +#endif + +class TSShapeInstance; +class SceneRenderState; +class PhysicsBody; +class PhysicsBehaviorInstance; +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class PhysicsComponent : public Component +{ + typedef Component Parent; + +protected: + bool mStatic; + bool mAtRest; + S32 mAtRestCounter; + + VectorF mGravity; + VectorF mVelocity; + F32 mDrag; + F32 mMass; + + F32 mGravityMod; + + S32 csmAtRestTimer; + F32 sAtRestVelocity; // Min speed after collisio + +public: + enum MaskBits { + PositionMask = Parent::NextFreeMask << 0, + FreezeMask = Parent::NextFreeMask << 1, + ForceMoveMask = Parent::NextFreeMask << 2, + VelocityMask = Parent::NextFreeMask << 3, + NextFreeMask = Parent::NextFreeMask << 4 + }; + + struct StateDelta + { + Move move; ///< Last move from server + F32 dt; ///< Last interpolation time + // Interpolation data + Point3F pos; + Point3F posVec; + QuatF rot[2]; + // Warp data + S32 warpTicks; ///< Number of ticks to warp + S32 warpCount; ///< Current pos in warp + Point3F warpOffset; + QuatF warpRot[2]; + }; + + StateDelta mDelta; + S32 mPredictionCount; ///< Number of ticks to predict + +public: + PhysicsComponent(); + virtual ~PhysicsComponent(); + DECLARE_CONOBJECT(PhysicsComponent); + + static void initPersistFields(); + + virtual void interpolateTick(F32 dt); + virtual void updatePos(const U32 /*mask*/, const F32 dt){} + virtual void _updatePhysics(); + virtual PhysicsBody *getPhysicsRep(); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + virtual void onComponentAdd(); + + void updateContainer(); + + virtual void updateVelocity(const F32 dt); + virtual Point3F getVelocity() { return mVelocity; } + virtual void getOriginVector(const Point3F &p, Point3F* r); + virtual void getVelocity(const Point3F& r, Point3F* v); + virtual void setVelocity(const VectorF& vel); + virtual void setTransform(const MatrixF& mat); + virtual void setPosition(const Point3F& pos); + void setRenderPosition(const Point3F& pos, F32 dt); + + virtual void applyImpulse(const Point3F&, const VectorF& vec); + virtual F32 getZeroImpulse(const Point3F& r, const Point3F& normal); + virtual void accumulateForce(F32 dt, Point3F force); + + //Rigid Body Collision Conveinence Hooks + virtual bool updateCollision(F32 dt, Rigid& ns, CollisionList &cList) { return false; } + virtual bool resolveContacts(Rigid& ns, CollisionList& cList, F32 dt) { return false; } + //virtual bool resolveCollision(Rigid& ns, CollisionList& cList) { return false; } + virtual bool resolveCollision(const Point3F& p, const Point3F &normal) { return false; } +}; + +#endif // _COMPONENT_H_ diff --git a/Engine/source/T3D/components/Physics/physicsComponentInterface.cpp b/Engine/source/T3D/components/Physics/physicsComponentInterface.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/Engine/source/T3D/components/Physics/physicsComponentInterface.h b/Engine/source/T3D/components/Physics/physicsComponentInterface.h new file mode 100644 index 000000000..0f5234816 --- /dev/null +++ b/Engine/source/T3D/components/Physics/physicsComponentInterface.h @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// 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 PHYSICS_COMPONENT_INTERFACE_H +#define PHYSICS_COMPONENT_INTERFACE_H + +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif + +class PhysicsComponentInterface : public Interface +{ +protected: + VectorF mVelocity; + F32 mMass; + + F32 mGravityMod; + +public: + void updateForces(); + + VectorF getVelocity() { return mVelocity; } + void setVelocity(VectorF vel) { mVelocity = vel; } + + F32 getMass() { return mMass; } + + Signal< void(VectorF normal, Vector overlappedObjects) > PhysicsComponentInterface::onPhysicsCollision; +}; + +#endif \ No newline at end of file diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.cpp b/Engine/source/T3D/components/Physics/playerControllerComponent.cpp new file mode 100644 index 000000000..bb5217659 --- /dev/null +++ b/Engine/source/T3D/components/Physics/playerControllerComponent.cpp @@ -0,0 +1,863 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/Physics/playerControllerComponent.h" +#include "platform/platform.h" +#include "console/consoleTypes.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "ts/tsShapeInstance.h" +#include "core/stream/bitStream.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" +#include "T3D/gameBase/gameConnection.h" +#include "collision/collision.h" +#include "T3D/physics/physicsPlayer.h" +#include "T3D/physics/physicsPlugin.h" +#include "T3D/Components/Collision/collisionInterfaces.h" +#include "T3D/trigger.h" +#include "T3D/components/collision/collisionTrigger.h" + +// Movement constants +static F32 sVerticalStepDot = 0.173f; // 80 +static F32 sMinFaceDistance = 0.01f; +static F32 sTractionDistance = 0.04f; +static F32 sNormalElasticity = 0.01f; +static U32 sMoveRetryCount = 5; +static F32 sMaxImpulseVelocity = 200.0f; + +////////////////////////////////////////////////////////////////////////// +// Callbacks +IMPLEMENT_CALLBACK(PlayerControllerComponent, updateMove, void, (PlayerControllerComponent* obj), (obj), + "Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n" + "@param obj the Player object\n"); + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +PlayerControllerComponent::PlayerControllerComponent() : Component() +{ + addComponentField("isStatic", "If enabled, object will not simulate physics", "bool", "0", ""); + addComponentField("gravity", "The direction of gravity affecting this object, as a vector", "vector", "0 0 -9", ""); + addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", ""); + addComponentField("mass", "The mass of the object", "float", "1", ""); + + mBuoyancy = 0.f; + mFriction = 0.3f; + mElasticity = 0.4f; + mMaxVelocity = 3000.f; + mSticky = false; + + mFalling = false; + mSwimming = false; + mInWater = false; + + mDelta.pos = mDelta.posVec = Point3F::Zero; + mDelta.warpTicks = mDelta.warpCount = 0; + mDelta.rot[0].identity(); + mDelta.rot[1].identity(); + mDelta.dt = 1; + + mUseDirectMoveInput = false; + + mFriendlyName = "Player Controller"; + mComponentType = "Physics"; + + mDescription = getDescriptionText("A general-purpose physics player controller."); + + mNetFlags.set(Ghostable | ScopeAlways); + + mMass = 9.0f; // from ShapeBase + mDrag = 1.0f; // from ShapeBase + + maxStepHeight = 1.0f; + moveSurfaceAngle = 60.0f; + contactSurfaceAngle = 85.0f; + + fallingSpeedThreshold = -10.0f; + + horizMaxSpeed = 80.0f; + horizMaxAccel = 100.0f; + horizResistSpeed = 38.0f; + horizResistFactor = 1.0f; + + upMaxSpeed = 80.0f; + upMaxAccel = 100.0f; + upResistSpeed = 38.0f; + upResistFactor = 1.0f; + + // Air control + airControl = 0.0f; + + //Grav mod + mGravityMod = 1; + + mInputVelocity = Point3F(0, 0, 0); + + mPhysicsRep = NULL; + mPhysicsWorld = NULL; +} + +PlayerControllerComponent::~PlayerControllerComponent() +{ + for (S32 i = 0; i < mFields.size(); ++i) + { + ComponentField &field = mFields[i]; + SAFE_DELETE_ARRAY(field.mFieldDescription); + } + + SAFE_DELETE_ARRAY(mDescription); +} + +IMPLEMENT_CO_NETOBJECT_V1(PlayerControllerComponent); + +////////////////////////////////////////////////////////////////////////// + +bool PlayerControllerComponent::onAdd() +{ + if (!Parent::onAdd()) + return false; + + return true; +} + +void PlayerControllerComponent::onRemove() +{ + Parent::onRemove(); + + SAFE_DELETE(mPhysicsRep); +} + +void PlayerControllerComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + updatePhysics(); +} + +void PlayerControllerComponent::componentAddedToOwner(Component *comp) +{ + if (comp->getId() == getId()) + return; + + //test if this is a shape component! + CollisionInterface *collisionInterface = dynamic_cast(comp); + if (collisionInterface) + { + collisionInterface->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics); + mOwnerCollisionInterface = collisionInterface; + updatePhysics(); + } +} + +void PlayerControllerComponent::componentRemovedFromOwner(Component *comp) +{ + if (comp->getId() == getId()) //????????? + return; + + //test if this is a shape component! + CollisionInterface *collisionInterface = dynamic_cast(comp); + if (collisionInterface) + { + collisionInterface->onCollisionChanged.remove(this, &PlayerControllerComponent::updatePhysics); + mOwnerCollisionInterface = NULL; + updatePhysics(); + } +} + +void PlayerControllerComponent::updatePhysics(PhysicsCollision *collision) +{ + if (!PHYSICSMGR) + return; + + mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + + //first, clear the old physRep + SAFE_DELETE(mPhysicsRep); + + mPhysicsRep = PHYSICSMGR->createPlayer(); + + F32 runSurfaceCos = mCos(mDegToRad(moveSurfaceAngle)); + + Point3F ownerBounds = mOwner->getObjBox().getExtents() * mOwner->getScale(); + + mPhysicsRep->init("", ownerBounds, runSurfaceCos, maxStepHeight, mOwner, mPhysicsWorld); + + mPhysicsRep->setTransform(mOwner->getTransform()); +} + +void PlayerControllerComponent::initPersistFields() +{ + Parent::initPersistFields(); + + addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), ""); + addField("useDirectMoveInput", TypePoint3F, Offset(mUseDirectMoveInput, PlayerControllerComponent), ""); +} + +U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + return retMask; +} + +void PlayerControllerComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); +} + +// +void PlayerControllerComponent::processTick() +{ + Parent::processTick(); + + if (!isServerObject() || !isActive()) + return; + + // Warp to catch up to server + if (mDelta.warpCount < mDelta.warpTicks) + { + mDelta.warpCount++; + + // Set new pos. + mDelta.pos = mOwner->getPosition(); + mDelta.pos += mDelta.warpOffset; + mDelta.rot[0] = mDelta.rot[1]; + mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks); + + MatrixF trans; + mDelta.rot[1].setMatrix(&trans); + trans.setPosition(mDelta.pos); + + mOwner->setTransform(trans); + + // Pos backstepping + mDelta.posVec.x = -mDelta.warpOffset.x; + mDelta.posVec.y = -mDelta.warpOffset.y; + mDelta.posVec.z = -mDelta.warpOffset.z; + } + else + { + // Save current rigid state interpolation + mDelta.posVec = mOwner->getPosition(); + mDelta.rot[0] = mOwner->getTransform(); + + updateMove(); + updatePos(TickSec); + + // Wrap up interpolation info + mDelta.pos = mOwner->getPosition(); + mDelta.posVec -= mOwner->getPosition(); + mDelta.rot[1] = mOwner->getTransform(); + + // Update container database + setTransform(mOwner->getTransform()); + + setMaskBits(VelocityMask); + setMaskBits(PositionMask); + } +} + +void PlayerControllerComponent::interpolateTick(F32 dt) +{ +} + +void PlayerControllerComponent::ownerTransformSet(MatrixF *mat) +{ + if (mPhysicsRep) + mPhysicsRep->setTransform(mOwner->getTransform()); +} + +void PlayerControllerComponent::setTransform(const MatrixF& mat) +{ + mOwner->setTransform(mat); + + setMaskBits(UpdateMask); +} + +// +void PlayerControllerComponent::updateMove() +{ + if (!PHYSICSMGR) + return; + + Move *move = &mOwner->lastMove; + + //If we're not set to use mUseDirectMoveInput, then we allow for an override in the form of mInputVelocity + if (!mUseDirectMoveInput) + { + move->x = mInputVelocity.x; + move->y = mInputVelocity.y; + move->z = mInputVelocity.z; + } + + // Is waterCoverage high enough to be 'swimming'? + { + bool swimming = mOwner->getContainerInfo().waterCoverage > 0.65f/* && canSwim()*/; + + if (swimming != mSwimming) + { + mSwimming = swimming; + } + } + + // Update current orientation + bool doStandardMove = true; + GameConnection* con = mOwner->getControllingClient(); + +#ifdef TORQUE_EXTENDED_MOVE + // Work with an absolute rotation from the ExtendedMove class? + if (con && con->getControlSchemeAbsoluteRotation()) + { + doStandardMove = false; + const ExtendedMove* emove = dynamic_cast(move); + U32 emoveIndex = smExtendedMoveHeadPosRotIndex; + if (emoveIndex >= ExtendedMove::MaxPositionsRotations) + emoveIndex = 0; + + if (emove->EulerBasedRotation[emoveIndex]) + { + // Head pitch + mHead.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch); + + // Do we also include the relative yaw value? + if (con->getControlSchemeAddPitchToAbsRot()) + { + F32 x = move->pitch; + if (x > M_PI_F) + x -= M_2PI_F; + + mHead.x += x; + } + + // Constrain the range of mHead.x + while (mHead.x < -M_PI_F) + mHead.x += M_2PI_F; + while (mHead.x > M_PI_F) + mHead.x -= M_2PI_F; + + // Rotate (heading) head or body? + if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson()))) + { + // Rotate head + mHead.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw); + + // Do we also include the relative yaw value? + if (con->getControlSchemeAddYawToAbsRot()) + { + F32 z = move->yaw; + if (z > M_PI_F) + z -= M_2PI_F; + + mHead.z += z; + } + + // Constrain the range of mHead.z + while (mHead.z < 0.0f) + mHead.z += M_2PI_F; + while (mHead.z > M_2PI_F) + mHead.z -= M_2PI_F; + } + else + { + // Rotate body + mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw); + + // Do we also include the relative yaw value? + if (con->getControlSchemeAddYawToAbsRot()) + { + F32 z = move->yaw; + if (z > M_PI_F) + z -= M_2PI_F; + + mRot.z += z; + } + + // 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; + } + mLastAbsoluteYaw = emove->rotZ[emoveIndex]; + mLastAbsolutePitch = emove->rotX[emoveIndex]; + + // Head bank + mHead.y = emove->rotY[emoveIndex]; + + // Constrain the range of mHead.y + while (mHead.y > M_PI_F) + mHead.y -= M_2PI_F; + } + } +#endif + + MatrixF zRot; + zRot.set(EulerF(0.0f, 0.0f, mOwner->getRotation().asEulerF().z)); + + // Desired move direction & speed + VectorF moveVec; + F32 moveSpeed = mInputVelocity.len(); + + zRot.getColumn(0, &moveVec); + moveVec *= move->x; + VectorF tv; + zRot.getColumn(1, &tv); + moveVec += tv * move->y; + + // Acceleration due to gravity + VectorF acc(mPhysicsWorld->getGravity() * mGravityMod * TickSec); + + // Determine ground contact normal. Only look for contacts if + // we can move and aren't mounted. + mContactInfo.contactNormal = VectorF::Zero; + mContactInfo.jump = false; + mContactInfo.run = false; + + bool jumpSurface = false, runSurface = false; + if (!mOwner->isMounted()) + findContact(&mContactInfo.run, &mContactInfo.jump, &mContactInfo.contactNormal); + if (mContactInfo.jump) + mJumpSurfaceNormal = mContactInfo.contactNormal; + + // If we don't have a runSurface but we do have a contactNormal, + // then we are standing on something that is too steep. + // Deflect the force of gravity by the normal so we slide. + // We could also try aligning it to the runSurface instead, + // but this seems to work well. + if (!mContactInfo.run && !mContactInfo.contactNormal.isZero()) + acc = (acc - 2 * mContactInfo.contactNormal * mDot(acc, mContactInfo.contactNormal)); + + // Acceleration on run surface + if (mContactInfo.run && !mSwimming) + { + mContactTimer = 0; + + VectorF pv = moveVec; + + // Adjust the player's requested dir. to be parallel + // to the contact surface. + F32 pvl = pv.len(); + + // Convert to acceleration + if (pvl) + pv *= moveSpeed / pvl; + VectorF runAcc = pv - (mVelocity + acc); + F32 runSpeed = runAcc.len(); + + // Clamp acceleration, player also accelerates faster when + // in his hard landing recover state. + F32 maxAcc; + + maxAcc = (horizMaxAccel / mMass) * TickSec; + + if (runSpeed > maxAcc) + runAcc *= maxAcc / runSpeed; + + acc += runAcc; + } + else if (!mSwimming && airControl > 0.0f) + { + VectorF pv; + pv = moveVec; + F32 pvl = pv.len(); + + if (pvl) + pv *= moveSpeed / pvl; + + VectorF runAcc = pv - (mVelocity + acc); + runAcc.z = 0; + runAcc.x = runAcc.x * airControl; + runAcc.y = runAcc.y * airControl; + F32 runSpeed = runAcc.len(); + + // We don't test for sprinting when performing air control + F32 maxAcc = (horizMaxAccel / mMass) * TickSec * 0.3f; + + if (runSpeed > maxAcc) + runAcc *= maxAcc / runSpeed; + + acc += runAcc; + + // There are no special air control animations + // so... increment this unless you really want to + // play the run anims in the air. + mContactTimer++; + } + else if (mSwimming) + { + // Remove acc into contact surface (should only be gravity) + // Clear out floating point acc errors, this will allow + // the player to "rest" on the ground. + F32 vd = -mDot(acc, mContactInfo.contactNormal); + if (vd > 0.0f) + { + VectorF dv = mContactInfo.contactNormal * (vd + 0.002f); + acc += dv; + if (acc.len() < 0.0001f) + acc.set(0.0f, 0.0f, 0.0f); + } + + // get the head pitch and add it to the moveVec + // This more accurate swim vector calc comes from Matt Fairfax + MatrixF xRot, zRot; + xRot.set(EulerF(mOwner->getRotation().asEulerF().x, 0, 0)); + zRot.set(EulerF(0, 0, mOwner->getRotation().asEulerF().z)); + MatrixF rot; + rot.mul(zRot, xRot); + rot.getColumn(0, &moveVec); + + moveVec *= move->x; + VectorF tv; + rot.getColumn(1, &tv); + moveVec += tv * move->y; + rot.getColumn(2, &tv); + moveVec += tv * move->z; + + // Force a 0 move if there is no energy, and only drain + // move energy if we're moving. + VectorF swimVec = moveVec; + + // If we are swimming but close enough to the shore/ground + // we can still have a surface-normal. In this case align the + // velocity to the normal to make getting out of water easier. + + moveVec.normalize(); + F32 isSwimUp = mDot(moveVec, mContactInfo.contactNormal); + + if (!mContactInfo.contactNormal.isZero() && isSwimUp < 0.1f) + { + F32 pvl = swimVec.len(); + + if (pvl) + { + VectorF nn; + mCross(swimVec, VectorF(0.0f, 0.0f, 1.0f), &nn); + nn *= 1.0f / pvl; + VectorF cv = mContactInfo.contactNormal; + cv -= nn * mDot(nn, cv); + swimVec -= cv * mDot(swimVec, cv); + } + } + + F32 swimVecLen = swimVec.len(); + + // Convert to acceleration. + if (swimVecLen) + swimVec *= moveSpeed / swimVecLen; + VectorF swimAcc = swimVec - (mVelocity + acc); + F32 swimSpeed = swimAcc.len(); + + // Clamp acceleration. + F32 maxAcc = (horizMaxAccel / mMass) * TickSec; + if (swimSpeed > maxAcc) + swimAcc *= maxAcc / swimSpeed; + + acc += swimAcc; + + mContactTimer++; + } + else + mContactTimer++; + + // Add in force from physical zones... + acc += (mOwner->getContainerInfo().appliedForce / mMass) * TickSec; + + // Adjust velocity with all the move & gravity acceleration + // TG: I forgot why doesn't the TickSec multiply happen here... + mVelocity += acc; + + // apply horizontal air resistance + + F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y); + + if (hvel > horizResistSpeed) + { + F32 speedCap = hvel; + if (speedCap > horizMaxSpeed) + speedCap = horizMaxSpeed; + speedCap -= horizResistFactor * TickSec * (speedCap - horizResistSpeed); + F32 scale = speedCap / hvel; + mVelocity.x *= scale; + mVelocity.y *= scale; + } + if (mVelocity.z > upResistSpeed) + { + if (mVelocity.z > upMaxSpeed) + mVelocity.z = upMaxSpeed; + mVelocity.z -= upResistFactor * TickSec * (mVelocity.z - upResistSpeed); + } + + // Apply drag + mVelocity -= mVelocity * mDrag * TickSec; + + // Clamp very small velocity to zero + if (mVelocity.isZero()) + mVelocity = Point3F::Zero; + + // If we are not touching anything and have sufficient -z vel, + // we are falling. + if (mContactInfo.run) + { + mFalling = false; + } + else + { + VectorF vel; + mOwner->getWorldToObj().mulV(mVelocity, &vel); + mFalling = vel.z < fallingSpeedThreshold; + } + + // Enter/Leave Liquid + if (!mInWater && mOwner->getContainerInfo().waterCoverage > 0.0f) + { + mInWater = true; + } + else if (mInWater && mOwner->getContainerInfo().waterCoverage <= 0.0f) + { + mInWater = false; + } +} + +void PlayerControllerComponent::updatePos(const F32 travelTime) +{ + if (!PHYSICSMGR) + return; + + PROFILE_SCOPE(PlayerControllerComponent_UpdatePos); + + Point3F newPos; + + Collision col; + dMemset(&col, 0, sizeof(col)); + + static CollisionList collisionList; + collisionList.clear(); + + newPos = mPhysicsRep->move(mVelocity * travelTime, collisionList); + + bool haveCollisions = false; + bool wasFalling = mFalling; + if (collisionList.getCount() > 0) + { + mFalling = false; + haveCollisions = true; + + //TODO: clean this up so the phys component doesn't have to tell the col interface to do this + CollisionInterface* colInterface = mOwner->getComponent(); + if (colInterface) + { + colInterface->handleCollisionList(collisionList, mVelocity); + } + } + + if (haveCollisions) + { + // Pick the collision that most closely matches our direction + VectorF velNormal = mVelocity; + velNormal.normalizeSafe(); + const Collision *collision = &collisionList[0]; + F32 collisionDot = mDot(velNormal, collision->normal); + const Collision *cp = collision + 1; + const Collision *ep = collision + collisionList.getCount(); + for (; cp != ep; cp++) + { + F32 dp = mDot(velNormal, cp->normal); + if (dp < collisionDot) + { + collisionDot = dp; + collision = cp; + } + } + + // Modify our velocity based on collisions + for (U32 i = 0; i 0) + col = collisionList[collisionList.getCount() - 1]; + + // We'll handle any player-to-player collision, and the last collision + // with other obejct types. + for (U32 i = 0; isetTransform(newMat); + + mOwner->setPosition(newPos); +} + +// +void PlayerControllerComponent::setVelocity(const VectorF& vel) +{ + mVelocity = vel; + + // Clamp against the maximum velocity. + if (mMaxVelocity > 0) + { + F32 len = mVelocity.magnitudeSafe(); + if (len > mMaxVelocity) + { + Point3F excess = mVelocity * (1.0f - (mMaxVelocity / len)); + mVelocity -= excess; + } + } + + setMaskBits(VelocityMask); +} + +void PlayerControllerComponent::findContact(bool *run, bool *jump, VectorF *contactNormal) +{ + SceneObject *contactObject = NULL; + + Vector overlapObjects; + + mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects); + + F32 vd = (*contactNormal).z; + *run = vd > mCos(mDegToRad(moveSurfaceAngle)); + *jump = vd > mCos(mDegToRad(contactSurfaceAngle)); + + // Check for triggers + for (U32 i = 0; i < overlapObjects.size(); i++) + { + SceneObject *obj = overlapObjects[i]; + U32 objectMask = obj->getTypeMask(); + + // Check: triggers, corpses and items... + // + if (objectMask & TriggerObjectType) + { + if (Trigger* pTrigger = dynamic_cast(obj)) + { + pTrigger->potentialEnterObject(mOwner); + } + else if (CollisionTrigger* pTriggerEx = dynamic_cast(obj)) + { + if (pTriggerEx) + pTriggerEx->potentialEnterObject(mOwner); + } + //Add any other custom classes and the sort here that should be filtered against + /*else if (TriggerExample* pTriggerEx = dynamic_cast(obj)) + { + if (pTriggerEx) + pTriggerEx->potentialEnterObject(mOwner); + }*/ + } + } + + mContactInfo.contacted = contactObject != NULL; + mContactInfo.contactObject = contactObject; + + if (mContactInfo.contacted) + mContactInfo.contactNormal = *contactNormal; +} + +void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec) +{ + + AssertFatal(!mIsNaN(vec), "Player::applyImpulse() - The vector is NaN!"); + + // Players ignore angular velocity + VectorF vel; + vel.x = vec.x / getMass(); + vel.y = vec.y / getMass(); + vel.z = vec.z / getMass(); + + // Make sure the impulse isn't too bigg + F32 len = vel.magnitudeSafe(); + if (len > sMaxImpulseVelocity) + { + Point3F excess = vel * (1.0f - (sMaxImpulseVelocity / len)); + vel -= excess; + } + + setVelocity(mVelocity + vel); +} + +DefineEngineMethod(PlayerControllerComponent, applyImpulse, bool, (Point3F pos, VectorF vel), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + object->applyImpulse(pos, vel); + return true; +} + +DefineEngineMethod(PlayerControllerComponent, getContactNormal, Point3F, (), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getContactNormal(); +} + +DefineEngineMethod(PlayerControllerComponent, getContactObject, SceneObject*, (), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->getContactObject(); +} + +DefineEngineMethod(PlayerControllerComponent, isContacted, bool, (), , + "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n" + + "@param pos impulse world position\n" + "@param vel impulse velocity (impulse force F = m * v)\n" + "@return Always true\n" + + "@note Not all objects that derrive from GameBase have this defined.\n") +{ + return object->isContacted(); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.h b/Engine/source/T3D/components/Physics/playerControllerComponent.h new file mode 100644 index 000000000..903d0f118 --- /dev/null +++ b/Engine/source/T3D/components/Physics/playerControllerComponent.h @@ -0,0 +1,212 @@ +//----------------------------------------------------------------------------- +// 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 PLAYER_CONTORLLER_COMPONENT_H +#define PLAYER_CONTORLLER_COMPONENT_H + +#ifndef PHYSICSBEHAVIOR_H +#include "T3D/Components/Physics/physicsBehavior.h" +#endif +#ifndef __RESOURCE_H__ +#include "core/resource.h" +#endif +#ifndef _TSSHAPE_H_ +#include "ts/tsShape.h" +#endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef _CONVEX_H_ +#include "collision/convex.h" +#endif +#ifndef _BOXCONVEX_H_ +#include "collision/boxConvex.h" +#endif +#ifndef _T3D_PHYSICSCOMMON_H_ +#include "T3D/physics/physicsCommon.h" +#endif +#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_ +#include "T3D/physics/physicsWorld.h" +#endif +#ifndef PHYSICS_COMPONENT_INTERFACE_H +#include "T3D/Components/physics/physicsComponentInterface.h" +#endif +#ifndef COLLISION_INTERFACES_H +#include "T3D/Components/collision/collisionInterfaces.h" +#endif + +class SceneRenderState; +class PhysicsWorld; +class PhysicsPlayer; +class SimplePhysicsBehaviorInstance; +class CollisionInterface; + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class PlayerControllerComponent : public Component, + public PhysicsComponentInterface +{ + typedef Component Parent; + + enum MaskBits { + VelocityMask = Parent::NextFreeMask << 0, + PositionMask = Parent::NextFreeMask << 1, + NextFreeMask = Parent::NextFreeMask << 2 + }; + + struct StateDelta + { + Move move; ///< Last move from server + F32 dt; ///< Last interpolation time + // Interpolation data + Point3F pos; + Point3F posVec; + QuatF rot[2]; + // Warp data + S32 warpTicks; ///< Number of ticks to warp + S32 warpCount; ///< Current pos in warp + Point3F warpOffset; + QuatF warpRot[2]; + }; + + StateDelta mDelta; + + PhysicsPlayer *mPhysicsRep; + PhysicsWorld *mPhysicsWorld; + + CollisionInterface* mOwnerCollisionInterface; + + struct ContactInfo + { + bool contacted, jump, run; + SceneObject *contactObject; + VectorF contactNormal; + F32 contactTime; + + void clear() + { + contacted = jump = run = false; + contactObject = NULL; + contactNormal.set(1, 1, 1); + } + + ContactInfo() { clear(); } + + } mContactInfo; + +protected: + F32 mDrag; + F32 mBuoyancy; + F32 mFriction; + F32 mElasticity; + F32 mMaxVelocity; + bool mSticky; + + bool mFalling; + bool mSwimming; + bool mInWater; + + S32 mContactTimer; ///< Ticks since last contact + + U32 mIntegrationCount; + + Point3F mJumpSurfaceNormal; ///< Normal of the surface the player last jumped on + + F32 maxStepHeight; ///< Maximum height the player can step up + F32 moveSurfaceAngle; ///< Maximum angle from vertical in degrees the player can run up + F32 contactSurfaceAngle; ///< Maximum angle from vertical in degrees we consider having real 'contact' + + F32 horizMaxSpeed; ///< Max speed attainable in the horizontal + F32 horizMaxAccel; + F32 horizResistSpeed; ///< Speed at which resistance will take place + F32 horizResistFactor; ///< Factor of resistance once horizResistSpeed has been reached + + F32 upMaxSpeed; ///< Max vertical speed attainable + F32 upMaxAccel; + F32 upResistSpeed; ///< Speed at which resistance will take place + F32 upResistFactor; ///< Factor of resistance once upResistSpeed has been reached + + F32 fallingSpeedThreshold; ///< Downward speed at which we consider the player falling + + // Air control + F32 airControl; + + Point3F mInputVelocity; + + bool mUseDirectMoveInput; + +public: + PlayerControllerComponent(); + virtual ~PlayerControllerComponent(); + DECLARE_CONOBJECT(PlayerControllerComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + + virtual void ownerTransformSet(MatrixF *mat); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + void updatePhysics(PhysicsCollision *collision = NULL); + + virtual void processTick(); + virtual void interpolateTick(F32 dt); + virtual void updatePos(const F32 dt); + void updateMove(); + + virtual VectorF getVelocity() { return mVelocity; } + virtual void setVelocity(const VectorF& vel); + virtual void setTransform(const MatrixF& mat); + + void findContact(bool *run, bool *jump, VectorF *contactNormal); + Point3F getContactNormal() { return mContactInfo.contactNormal; } + SceneObject* getContactObject() { return mContactInfo.contactObject; } + bool isContacted() { return mContactInfo.contacted; } + + // + void applyImpulse(const Point3F &pos, const VectorF &vec); + + //This is a weird artifact of the PhysicsReps. We want the collision component to be privvy to any events that happen + //so when the physics components do a findContact test during their update, they'll have a signal collision components + //can be listening to to update themselves with that info + Signal< void(SceneObject*) > PlayerControllerComponent::onContactSignal; + + // + DECLARE_CALLBACK(void, updateMove, (PlayerControllerComponent* obj)); +}; + +#endif // _COMPONENT_H_ diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp b/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp new file mode 100644 index 000000000..e2d22fa25 --- /dev/null +++ b/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp @@ -0,0 +1,467 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "T3D/Components/physics/RigidBodyComponent.h" +#include "core/util/safeDelete.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "core/stream/bitStream.h" +#include "console/engineAPI.h" +#include "sim/netConnection.h" +#include "T3D/physics/physicsBody.h" +#include "T3D/physics/physicsPlugin.h" +#include "T3D/physics/physicsWorld.h" +#include "T3D/physics/physicsCollision.h" +#include "T3D/Components/Collision/collisionComponent.h" + +bool RigidBodyComponent::smNoCorrections = false; +bool RigidBodyComponent::smNoSmoothing = false; + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +RigidBodyComponent::RigidBodyComponent() : Component() +{ + mMass = 20; + mDynamicFriction = 1; + mStaticFriction = 0.1f; + mRestitution = 10; + mLinearDamping = 0; + mAngularDamping = 0; + mLinearSleepThreshold = 1; + mAngularSleepThreshold = 1; + mWaterDampingScale = 0.1f; + mBuoyancyDensity = 1; + + mSimType = SimType_ServerOnly; + + mPhysicsRep = NULL; + mResetPos = MatrixF::Identity; + + mOwnerColComponent = NULL; + + mFriendlyName = "RigidBody(Component)"; +} + +RigidBodyComponent::~RigidBodyComponent() +{ +} + +IMPLEMENT_CO_NETOBJECT_V1(RigidBodyComponent); + +bool RigidBodyComponent::onAdd() +{ + if(! Parent::onAdd()) + return false; + + return true; +} + +void RigidBodyComponent::onRemove() +{ + Parent::onRemove(); +} +void RigidBodyComponent::initPersistFields() +{ + Parent::initPersistFields(); +} + +//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior +void RigidBodyComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + if (isServerObject()) + { + storeRestorePos(); + PhysicsPlugin::getPhysicsResetSignal().notify(this, &RigidBodyComponent::_onPhysicsReset); + } + + CollisionComponent *colComp = mOwner->getComponent(); + if (colComp) + { + colComp->onCollisionChanged.notify(this, &RigidBodyComponent::updatePhysics); + updatePhysics(colComp->getCollisionData()); + } + else + updatePhysics(); +} + +void RigidBodyComponent::onComponentRemove() +{ + Parent::onComponentRemove(); + + if (isServerObject()) + { + PhysicsPlugin::getPhysicsResetSignal().remove(this, &RigidBodyComponent::_onPhysicsReset); + } + + CollisionComponent *colComp = mOwner->getComponent(); + if (colComp) + { + colComp->onCollisionChanged.remove(this, &RigidBodyComponent::updatePhysics); + } + + SAFE_DELETE(mPhysicsRep); +} + +void RigidBodyComponent::componentAddedToOwner(Component *comp) +{ + CollisionComponent *colComp = dynamic_cast(comp); + if (colComp) + { + colComp->onCollisionChanged.notify(this, &RigidBodyComponent::updatePhysics); + updatePhysics(colComp->getCollisionData()); + } +} + +void RigidBodyComponent::componentRemovedFromOwner(Component *comp) +{ + //test if this is a shape component! + CollisionComponent *colComp = dynamic_cast(comp); + if (colComp) + { + colComp->onCollisionChanged.remove(this, &RigidBodyComponent::updatePhysics); + updatePhysics(); + } +} + +void RigidBodyComponent::ownerTransformSet(MatrixF *mat) +{ + if (mPhysicsRep) + mPhysicsRep->setTransform(mOwner->getTransform()); +} + +void RigidBodyComponent::updatePhysics(PhysicsCollision* collision) +{ + SAFE_DELETE(mPhysicsRep); + + if (!PHYSICSMGR) + return; + + mWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + + if (!collision) + return; + + mPhysicsRep = PHYSICSMGR->createBody(); + + mPhysicsRep->init(collision, mMass, 0, mOwner, mWorld); + + mPhysicsRep->setMaterial(mRestitution, mDynamicFriction, mStaticFriction); + + mPhysicsRep->setDamping(mLinearDamping, mAngularDamping); + mPhysicsRep->setSleepThreshold(mLinearSleepThreshold, mAngularSleepThreshold); + + mPhysicsRep->setTransform(mOwner->getTransform()); + + // The reset position is the transform on the server + // at creation time... its not used on the client. + if (isServerObject()) + { + storeRestorePos(); + PhysicsPlugin::getPhysicsResetSignal().notify(this, &RigidBodyComponent::_onPhysicsReset); + } +} + +U32 RigidBodyComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (stream->writeFlag(mask & StateMask)) + { + // This will encode the position relative to the control + // object position. + // + // This will compress the position to as little as 6.25 + // bytes if the position is within about 30 meters of the + // control object. + // + // Worst case its a full 12 bytes + 2 bits if the position + // is more than 500 meters from the control object. + // + stream->writeCompressedPoint(mState.position); + + // Use only 3.5 bytes to send the orientation. + stream->writeQuat(mState.orientation, 9); + + // If the server object has been set to sleep then + // we don't need to send any velocity. + if (!stream->writeFlag(mState.sleeping)) + { + // This gives me ~0.015f resolution in velocity magnitude + // while only costing me 1 bit of the velocity is zero length, + // <5 bytes in normal cases, and <8 bytes if the velocity is + // greater than 1000. + AssertWarn(mState.linVelocity.len() < 1000.0f, + "PhysicsShape::packUpdate - The linVelocity is out of range!"); + stream->writeVector(mState.linVelocity, 1000.0f, 16, 9); + + // For angular velocity we get < 0.01f resolution in magnitude + // with the most common case being under 4 bytes. + AssertWarn(mState.angVelocity.len() < 10.0f, + "PhysicsShape::packUpdate - The angVelocity is out of range!"); + stream->writeVector(mState.angVelocity, 10.0f, 10, 9); + } + } + + return retMask; +} + +void RigidBodyComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if (stream->readFlag()) // StateMask + { + PhysicsState state; + + // Read the encoded and compressed position... commonly only 6.25 bytes. + stream->readCompressedPoint(&state.position); + + // Read the compressed quaternion... 3.5 bytes. + stream->readQuat(&state.orientation, 9); + + state.sleeping = stream->readFlag(); + if (!state.sleeping) + { + stream->readVector(&state.linVelocity, 1000.0f, 16, 9); + stream->readVector(&state.angVelocity, 10.0f, 10, 9); + } + + if (!smNoCorrections && mPhysicsRep && mPhysicsRep->isDynamic()) + { + // Set the new state on the physics object immediately. + mPhysicsRep->applyCorrection(state.getTransform()); + + mPhysicsRep->setSleeping(state.sleeping); + if (!state.sleeping) + { + mPhysicsRep->setLinVelocity(state.linVelocity); + mPhysicsRep->setAngVelocity(state.angVelocity); + } + + mPhysicsRep->getState(&mState); + } + + // If there is no physics object then just set the + // new state... the tick will take care of the + // interpolation and extrapolation. + if (!mPhysicsRep || !mPhysicsRep->isDynamic()) + mState = state; + } +} + +void RigidBodyComponent::processTick() +{ + Parent::processTick(); + + if (!mPhysicsRep || !PHYSICSMGR) + return; + + // Note that unlike TSStatic, the serverside PhysicsShape does not + // need to play the ambient animation because even if the animation were + // to move collision shapes it would not affect the physx representation. + + PROFILE_START(RigidBodyComponent_ProcessTick); + + if (!mPhysicsRep->isDynamic()) + return; + + // SINGLE PLAYER HACK!!!! + if (PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject()) + { + RigidBodyComponent *servObj = (RigidBodyComponent*)getServerObject(); + mOwner->setTransform(servObj->mState.getTransform()); + mRenderState[0] = servObj->mRenderState[0]; + mRenderState[1] = servObj->mRenderState[1]; + + return; + } + + // Store the last render state. + mRenderState[0] = mRenderState[1]; + + // If the last render state doesn't match the last simulation + // state then we got a correction and need to + Point3F errorDelta = mRenderState[1].position - mState.position; + const bool doSmoothing = !errorDelta.isZero() && !smNoSmoothing; + + const bool wasSleeping = mState.sleeping; + + // Get the new physics state. + mPhysicsRep->getState(&mState); + updateContainerForces(); + + // Smooth the correction back into the render state. + mRenderState[1] = mState; + if (doSmoothing) + { + F32 correction = mClampF(errorDelta.len() / 20.0f, 0.1f, 0.9f); + mRenderState[1].position.interpolate(mState.position, mRenderState[0].position, correction); + mRenderState[1].orientation.interpolate(mState.orientation, mRenderState[0].orientation, correction); + } + + //Check if any collisions occured + findContact(); + + // If we haven't been sleeping then update our transform + // and set ourselves as dirty for the next client update. + if (!wasSleeping || !mState.sleeping) + { + // Set the transform on the parent so that + // the physics object isn't moved. + mOwner->setTransform(mState.getTransform()); + + // If we're doing server simulation then we need + // to send the client a state update. + if (isServerObject() && mPhysicsRep && !smNoCorrections && + !PHYSICSMGR->isSinglePlayer() // SINGLE PLAYER HACK!!!! + ) + setMaskBits(StateMask); + } + + PROFILE_END(); +} + +void RigidBodyComponent::findContact() +{ + SceneObject *contactObject = NULL; + + VectorF *contactNormal = new VectorF(0, 0, 0); + + Vector overlapObjects; + + mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects); + + if (!overlapObjects.empty()) + { + //fire our signal that the physics sim said collisions happened + onPhysicsCollision.trigger(*contactNormal, overlapObjects); + } +} + +void RigidBodyComponent::_onPhysicsReset(PhysicsResetEvent reset) +{ + if (reset == PhysicsResetEvent_Store) + mResetPos = mOwner->getTransform(); + + else if (reset == PhysicsResetEvent_Restore) + { + mOwner->setTransform(mResetPos); + } +} + +void RigidBodyComponent::storeRestorePos() +{ + mResetPos = mOwner->getTransform(); +} + +void RigidBodyComponent::applyImpulse(const Point3F &pos, const VectorF &vec) +{ + if (mPhysicsRep && mPhysicsRep->isDynamic()) + mPhysicsRep->applyImpulse(pos, vec); +} + +void RigidBodyComponent::applyRadialImpulse(const Point3F &origin, F32 radius, F32 magnitude) +{ + if (!mPhysicsRep || !mPhysicsRep->isDynamic()) + return; + + // TODO: Find a better approximation of the + // force vector using the object box. + + VectorF force = mOwner->getWorldBox().getCenter() - origin; + F32 dist = force.magnitudeSafe(); + force.normalize(); + + if (dist == 0.0f) + force *= magnitude; + else + force *= mClampF(radius / dist, 0.0f, 1.0f) * magnitude; + + mPhysicsRep->applyImpulse(origin, force); + + // TODO: There is no simple way to really sync this sort of an + // event with the client. + // + // The best is to send the current physics snapshot, calculate the + // time difference from when this event occured and the time when the + // client recieves it, and then extrapolate where it should be. + // + // Even then its impossible to be absolutely sure its synced. + // + // Bottom line... you shouldn't use physics over the network like this. + // +} + +void RigidBodyComponent::updateContainerForces() +{ + PROFILE_SCOPE(RigidBodyComponent_updateContainerForces); + + // If we're not simulating don't update forces. + PhysicsWorld *world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + if (!world || !world->isEnabled()) + return; + + ContainerQueryInfo info; + info.box = mOwner->getWorldBox(); + info.mass = mMass; + + // Find and retreive physics info from intersecting WaterObject(s) + mOwner->getContainer()->findObjects(mOwner->getWorldBox(), WaterObjectType | PhysicalZoneObjectType, findRouter, &info); + + // Calculate buoyancy and drag + F32 angDrag = mAngularDamping; + F32 linDrag = mLinearDamping; + F32 buoyancy = 0.0f; + Point3F cmass = mPhysicsRep->getCMassPosition(); + + F32 density = mBuoyancyDensity; + if (density > 0.0f) + { + if (info.waterCoverage > 0.0f) + { + F32 waterDragScale = info.waterViscosity * mWaterDampingScale; + F32 powCoverage = mPow(info.waterCoverage, 0.25f); + + angDrag = mLerp(angDrag, angDrag * waterDragScale, powCoverage); + linDrag = mLerp(linDrag, linDrag * waterDragScale, powCoverage); + } + + buoyancy = (info.waterDensity / density) * mPow(info.waterCoverage, 2.0f); + + // A little hackery to prevent oscillation + // Based on this blog post: + // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html) + // JCF: disabled! + Point3F buoyancyForce = buoyancy * -world->getGravity() * TickSec * mMass; + mPhysicsRep->applyImpulse(cmass, buoyancyForce); + } + + // Update the dampening as the container might have changed. + mPhysicsRep->setDamping(linDrag, angDrag); + + // Apply physical zone forces. + if (!info.appliedForce.isZero()) + mPhysicsRep->applyImpulse(cmass, info.appliedForce); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.h b/Engine/source/T3D/components/Physics/rigidBodyComponent.h new file mode 100644 index 000000000..85b98379d --- /dev/null +++ b/Engine/source/T3D/components/Physics/rigidBodyComponent.h @@ -0,0 +1,183 @@ +//----------------------------------------------------------------------------- +// 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 RIGID_BODY_COMPONENT_H +#define RIGID_BODY_COMPONENT_H + +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef _T3D_PHYSICSCOMMON_H_ +#include "T3D/physics/physicsCommon.h" +#endif +#ifndef COLLISION_COMPONENT_H +#include "T3D/Components/collision/collisionComponent.h" +#endif +#ifndef PHYSICS_COMPONENT_INTERFACE_H +#include "T3D/Components/physics/physicsComponentInterface.h" +#endif + +class PhysicsBody; + +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class RigidBodyComponent : public Component, public PhysicsComponentInterface +{ + typedef Component Parent; + + enum SimType + { + /// This physics representation only exists on the client + /// world and the server only does ghosting. + SimType_ClientOnly, + + /// The physics representation only exists on the server world + /// and the client gets delta updates for rendering. + SimType_ServerOnly, + + /// The physics representation exists on the client and the server + /// worlds with corrections occuring when the client gets out of sync. + SimType_ClientServer, + + /// The bits used to pack the SimType field. + SimType_Bits = 3, + + } mSimType; + + // + // + /// The current physics state. + PhysicsState mState; + + /// The previous and current render states. + PhysicsState mRenderState[2]; + + /// The abstracted physics actor. + PhysicsBody *mPhysicsRep; + + PhysicsWorld *mWorld; + + /// The starting position to place the shape when + /// the level begins or is reset. + MatrixF mResetPos; + // + // + + /// If true then no corrections are sent from the server + /// and/or applied from the client. + /// + /// This is only ment for debugging. + /// + static bool smNoCorrections; + + /// If true then no smoothing is done on the client when + /// applying server corrections. + /// + /// This is only ment for debugging. + /// + static bool smNoSmoothing; + + /// + F32 mMass; + + /// + F32 mDynamicFriction; + + /// + F32 mStaticFriction; + + /// + F32 mRestitution; + + /// + F32 mLinearDamping; + + /// + F32 mAngularDamping; + + /// + F32 mLinearSleepThreshold; + + /// + F32 mAngularSleepThreshold; + + // A scale applied to the normal linear and angular damping + // when the object enters a water volume. + F32 mWaterDampingScale; + + // The density of this object used for water buoyancy effects. + F32 mBuoyancyDensity; + + CollisionComponent* mOwnerColComponent; + + enum MaskBits { + PositionMask = Parent::NextFreeMask << 0, + FreezeMask = Parent::NextFreeMask << 1, + StateMask = Parent::NextFreeMask << 2, + VelocityMask = Parent::NextFreeMask << 3, + NextFreeMask = Parent::NextFreeMask << 4 + }; + +public: + RigidBodyComponent(); + virtual ~RigidBodyComponent(); + DECLARE_CONOBJECT(RigidBodyComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void onComponentAdd(); + virtual void onComponentRemove(); + + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + + virtual void ownerTransformSet(MatrixF *mat); + + inline F32 getMass() { return mMass; } + Point3F getVelocity() const { return mState.linVelocity; } + void applyImpulse(const Point3F &pos, const VectorF &vec); + void applyRadialImpulse(const Point3F &origin, F32 radius, F32 magnitude); + + void updateContainerForces(); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + virtual void processTick(); + + void findContact(); + + /// Save the current transform as where we return to when a physics reset + /// event occurs. This is automatically set in onAdd but some manipulators + /// such as Prefab need to make use of this. + void storeRestorePos(); + + void updatePhysics(PhysicsCollision *collision = NULL); + + void _onPhysicsReset(PhysicsResetEvent reset); +}; + +#endif // _RIGID_BODY_COMPONENT_H_ diff --git a/Engine/source/T3D/components/Render/MeshComponent.cpp b/Engine/source/T3D/components/Render/MeshComponent.cpp new file mode 100644 index 000000000..9444fa917 --- /dev/null +++ b/Engine/source/T3D/components/Render/MeshComponent.cpp @@ -0,0 +1,524 @@ +//----------------------------------------------------------------------------- +// 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 "console/consoleTypes.h" +#include "T3D/Components/Render/MeshComponent.h" +#include "core/util/safeDelete.h" +#include "core/resourceManager.h" +#include "core/stream/fileStream.h" +#include "console/consoleTypes.h" +#include "console/consoleObject.h" +#include "core/stream/bitStream.h" +#include "sim/netConnection.h" +#include "gfx/gfxTransformSaver.h" +#include "console/engineAPI.h" +#include "lighting/lightQuery.h" +#include "scene/sceneManager.h" +#include "gfx/bitmap/ddsFile.h" +#include "gfx/bitmap/ddsUtils.h" +#include "gfx/gfxTextureManager.h" +#include "materials/materialFeatureTypes.h" +#include "renderInstance/renderImposterMgr.h" +#include "util/imposterCapture.h" +#include "gfx/sim/debugDraw.h" +#include "gfx/gfxDrawUtil.h" +#include "materials/materialManager.h" +#include "materials/matInstance.h" +#include "core/strings/findMatch.h" +#include "T3D/components/Render/MeshComponent_ScriptBinding.h" + +////////////////////////////////////////////////////////////////////////// +// Constructor/Destructor +////////////////////////////////////////////////////////////////////////// +MeshComponent::MeshComponent() : Component() +{ + mShapeName = StringTable->insert(""); + mShapeAsset = StringTable->insert(""); + + mChangingMaterials.clear(); + + mMaterials.clear(); + + mFriendlyName = "Mesh Component"; + mComponentType = "Render"; + + mDescription = getDescriptionText("Causes the object to render a non-animating 3d shape using the file provided."); + + mNetworked = true; + mNetFlags.set(Ghostable | ScopeAlways); +} + +MeshComponent::~MeshComponent(){} + +IMPLEMENT_CO_NETOBJECT_V1(MeshComponent); + +//========================================================================================== +void MeshComponent::boneObject::addObject(SimObject* object) +{ + SceneObject* sc = dynamic_cast(object); + + if(sc && mOwner) + { + if(TSShape* shape = mOwner->getShape()) + { + S32 nodeID = shape->findNode(mBoneName); + + //we may have a offset on the shape's center + //so make sure we accomodate for that when setting up the mount offsets + MatrixF mat = mOwner->getNodeTransform(nodeID); + + mOwner->getOwner()->mountObject(sc, nodeID, mat); + } + } +} + +bool MeshComponent::onAdd() +{ + if(! Parent::onAdd()) + return false; + + // Register for the resource change signal. + ResourceManager::get().getChangedSignal().notify( this, &MeshComponent::_onResourceChanged ); + + return true; +} + +void MeshComponent::onComponentAdd() +{ + Parent::onComponentAdd(); + + //get the default shape, if any + updateShape(); +} + +void MeshComponent::onRemove() +{ + Parent::onRemove(); + + SAFE_DELETE(mShapeInstance); +} + +void MeshComponent::onComponentRemove() +{ + if(mOwner) + { + Point3F pos = mOwner->getPosition(); //store our center pos + mOwner->setObjectBox(Box3F(Point3F(-1,-1,-1), Point3F(1,1,1))); + mOwner->setPosition(pos); + } + + Parent::onComponentRemove(); +} + +void MeshComponent::initPersistFields() +{ + Parent::initPersistFields(); + + //create a hook to our internal variables + addGroup("Model"); + addProtectedField("MeshAsset", TypeAssetId, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, + "The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors); + endGroup("Model"); +} + +bool MeshComponent::_setMesh(void *object, const char *index, const char *data) +{ + MeshComponent *rbI = static_cast(object); + + // Sanity! + AssertFatal(data != NULL, "Cannot use a NULL asset Id."); + + return rbI->setMeshAsset(data); +} + +bool MeshComponent::_setShape( void *object, const char *index, const char *data ) +{ + MeshComponent *rbI = static_cast(object); + rbI->mShapeName = StringTable->insert(data); + rbI->updateShape(); //make sure we force the update to resize the owner bounds + rbI->setMaskBits(ShapeMask); + + return true; +} + +bool MeshComponent::setMeshAsset(const char* assetName) +{ + // Fetch the asset Id. + mMeshAssetId = StringTable->insert(assetName); + mMeshAsset.setAssetId(mMeshAssetId); + + if (mMeshAsset.isNull()) + { + Con::errorf("[MeshComponent] Failed to load mesh asset."); + return false; + } + + mShapeName = mMeshAssetId; + mShapeAsset = mShapeName; + updateShape(); //make sure we force the update to resize the owner bounds + setMaskBits(ShapeMask); + + return true; +} + +void MeshComponent::_onResourceChanged( const Torque::Path &path ) +{ + if ( path != Torque::Path( mShapeName ) ) + return; + + updateShape(); + setMaskBits(ShapeMask); +} + +void MeshComponent::inspectPostApply() +{ + Parent::inspectPostApply(); +} + +U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) +{ + U32 retMask = Parent::packUpdate(con, mask, stream); + + if (!mOwner || con->getGhostIndex(mOwner) == -1) + { + stream->writeFlag(false); + stream->writeFlag(false); + + if (mask & ShapeMask) + retMask |= ShapeMask; + if (mask & MaterialMask) + retMask |= MaterialMask; + return retMask; + } + + if (stream->writeFlag(mask & ShapeMask)) + { + stream->writeString(mShapeName); + } + + if (stream->writeFlag( mask & MaterialMask )) + { + stream->writeInt(mChangingMaterials.size(), 16); + + for(U32 i=0; i < mChangingMaterials.size(); i++) + { + stream->writeInt(mChangingMaterials[i].slot, 16); + con->packNetStringHandleU(stream, NetStringHandle(mChangingMaterials[i].matName)); + } + + mChangingMaterials.clear(); + } + + return retMask; +} + +void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream) +{ + Parent::unpackUpdate(con, stream); + + if(stream->readFlag()) + { + mShapeName = stream->readSTString(); + setMeshAsset(mShapeName); + updateShape(); + } + + 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.matName = String(con->unpackNetStringHandleU(stream).getString()); + + mChangingMaterials.push_back(newMatMap); + } + + updateMaterials(); + } +} + +void MeshComponent::prepRenderImage( SceneRenderState *state ) +{ + if (!mEnabled || !mOwner || !mShapeInstance) + return; + + Point3F cameraOffset; + mOwner->getRenderTransform().getColumn(3, &cameraOffset); + cameraOffset -= state->getDiffuseCameraPosition(); + F32 dist = cameraOffset.len(); + if (dist < 0.01f) + dist = 0.01f; + + Point3F objScale = getOwner()->getScale(); + F32 invScale = (1.0f / getMax(getMax(objScale.x, objScale.y), objScale.z)); + + mShapeInstance->setDetailFromDistance(state, dist * invScale); + + if (mShapeInstance->getCurrentDetail() < 0) + return; + + GFXTransformSaver saver; + + // Set up our TS render state. + TSRenderState rdata; + rdata.setSceneState(state); + rdata.setFadeOverride(1.0f); + rdata.setOriginSort(false); + + // We might have some forward lit materials + // so pass down a query to gather lights. + LightQuery query; + query.init(mOwner->getWorldSphere()); + rdata.setLightQuery(&query); + + MatrixF mat = mOwner->getRenderTransform(); + Point3F renderPos = mat.getPosition(); + EulerF renderRot = mat.toEuler(); + mat.scale(objScale); + GFX->setWorldMatrix(mat); + + mShapeInstance->render(rdata); +} + +void MeshComponent::updateShape() +{ + bool isServer = isServerObject(); + + if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0')) + { + if (mMeshAsset == NULL) + return; + + mShape = mMeshAsset->getShape(); + + if (!mShape) + return; + + setupShape(); + + //Do this on both the server and client + S32 materialCount = mShape->materialList->getMaterialNameList().size(); + + if(isServerObject()) + { + //we need to update the editor + for (U32 i = 0; i < mFields.size(); i++) + { + //find any with the materialslot title and clear them out + if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false)) + { + setDataField(mFields[i].mFieldName, NULL, ""); + mFields.erase(i); + continue; + } + } + + //next, get a listing of our materials in the shape, and build our field list for them + char matFieldName[128]; + + if(materialCount > 0) + mComponentGroup = StringTable->insert("Materials"); + + for(U32 i=0; i < materialCount; i++) + { + String materialname = mShape->materialList->getMaterialName(i); + if(materialname == String("ShapeBounds")) + continue; + + dSprintf(matFieldName, 128, "MaterialSlot%d", i); + + addComponentField(matFieldName, "A material used in the shape file", "TypeAssetId", materialname, ""); + } + + if(materialCount > 0) + mComponentGroup = ""; + } + + if(mOwner != NULL) + { + Point3F min, max, pos; + pos = mOwner->getPosition(); + + mOwner->getWorldToObj().mulP(pos); + + min = mShape->bounds.minExtents; + max = mShape->bounds.maxExtents; + + mShapeBounds.set(min, max); + + mOwner->setObjectBox(Box3F(min, max)); + + if( mOwner->getSceneManager() != NULL ) + mOwner->getSceneManager()->notifyObjectDirty( mOwner ); + } + + //finally, notify that our shape was changed + onShapeInstanceChanged.trigger(this); + } +} + +void MeshComponent::setupShape() +{ + mShapeInstance = new TSShapeInstance(mShape, true); +} + +void MeshComponent::updateMaterials() +{ + if (mChangingMaterials.empty() || !mShape) + return; + + TSMaterialList* pMatList = mShapeInstance->getMaterialList(); + pMatList->setTextureLookupPath(getShapeResource().getPath().getPath()); + + const Vector &materialNames = pMatList->getMaterialNameList(); + for ( S32 i = 0; i < materialNames.size(); i++ ) + { + const String &pName = materialNames[i]; + + for(U32 m=0; m < mChangingMaterials.size(); m++) + { + if(mChangingMaterials[m].slot == i) + { + pMatList->renameMaterial( i, mChangingMaterials[m].matName ); + } + } + + mChangingMaterials.clear(); + } + + // Initialize the material instances + mShapeInstance->initMaterialList(); +} + +MatrixF MeshComponent::getNodeTransform(S32 nodeIdx) +{ + if (mShape) + { + S32 nodeCount = getShape()->nodes.size(); + + if(nodeIdx >= 0 && nodeIdx < nodeCount) + { + //animate(); + MatrixF mountTransform = mShapeInstance->mNodeTransforms[nodeIdx]; + mountTransform.mul(mOwner->getRenderTransform()); + + return mountTransform; + } + } + + return MatrixF::Identity; +} + +S32 MeshComponent::getNodeByName(String nodeName) +{ + if (mShape) + { + S32 nodeIdx = getShape()->findNode(nodeName); + + return nodeIdx; + } + + return -1; +} + +bool MeshComponent::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info) +{ + return false; +} + +void MeshComponent::mountObjectToNode(SceneObject* objB, String node, MatrixF txfm) +{ + const char* test; + test = node.c_str(); + if(dIsdigit(test[0])) + { + getOwner()->mountObject(objB, dAtoi(node), txfm); + } + else + { + if(TSShape* shape = getShape()) + { + S32 idx = shape->findNode(node); + getOwner()->mountObject(objB, idx, txfm); + } + } +} + +void MeshComponent::onDynamicModified(const char* slotName, const char* newValue) +{ + if(FindMatch::isMatch( "materialslot*", slotName, false )) + { + if(!getShape()) + return; + + S32 slot = -1; + String outStr( String::GetTrailingNumber( slotName, slot ) ); + + if(slot == -1) + return; + + bool found = false; + for(U32 i=0; i < mChangingMaterials.size(); i++) + { + if(mChangingMaterials[i].slot == slot) + { + mChangingMaterials[i].matName = String(newValue); + found = true; + } + } + + if(!found) + { + matMap newMatMap; + newMatMap.slot = slot; + newMatMap.matName = String(newValue); + + mChangingMaterials.push_back(newMatMap); + } + + setMaskBits(MaterialMask); + } + + Parent::onDynamicModified(slotName, newValue); +} + +void MeshComponent::changeMaterial(U32 slot, const char* newMat) +{ + + char fieldName[512]; + + //update our respective field + dSprintf(fieldName, 512, "materialSlot%d", slot); + setDataField(fieldName, NULL, newMat); +} + +void MeshComponent::onInspect() +{ +} + +void MeshComponent::onEndInspect() +{ +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Render/MeshComponent.h b/Engine/source/T3D/components/Render/MeshComponent.h new file mode 100644 index 000000000..e06a0ccee --- /dev/null +++ b/Engine/source/T3D/components/Render/MeshComponent.h @@ -0,0 +1,183 @@ +//----------------------------------------------------------------------------- +// 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 STATIC_MESH_COMPONENT_H +#define STATIC_MESH_COMPONENT_H + +#ifndef COMPONENT_H +#include "T3D/Components/Component.h" +#endif +#ifndef __RESOURCE_H__ +#include "core/resource.h" +#endif +#ifndef _TSSHAPE_H_ +#include "ts/tsShape.h" +#endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif +#ifndef _MBOX_H_ +#include "math/mBox.h" +#endif +#ifndef ENTITY_H +#include "T3D/Entity.h" +#endif +#ifndef _NETSTRINGTABLE_H_ + #include "sim/netStringTable.h" +#endif +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif +#ifndef RENDER_COMPONENT_INTERFACE_H +#include "T3D/Components/Render/renderComponentInterface.h" +#endif +#ifndef _ASSET_PTR_H_ +#include "assets/assetPtr.h" +#endif +#ifndef _SHAPE_ASSET_H_ +#include "T3D/assets/ShapeAsset.h" +#endif +#ifndef _GFXVERTEXFORMAT_H_ +#include "gfx/gfxVertexFormat.h" +#endif + +class TSShapeInstance; +class SceneRenderState; +////////////////////////////////////////////////////////////////////////// +/// +/// +////////////////////////////////////////////////////////////////////////// +class MeshComponent : public Component, + public RenderComponentInterface, + public CastRayRenderedInterface, + public EditorInspectInterface +{ + typedef Component Parent; + +protected: + enum + { + ShapeMask = Parent::NextFreeMask, + MaterialMask = Parent::NextFreeMask << 1, + NextFreeMask = Parent::NextFreeMask << 2, + }; + + StringTableEntry mShapeName; + StringTableEntry mShapeAsset; + TSShape* mShape; + Box3F mShapeBounds; + Point3F mCenterOffset; + + struct matMap + { + String matName; + U32 slot; + }; + + Vector mChangingMaterials; + Vector mMaterials; + + class boneObject : public SimGroup + { + MeshComponent *mOwner; + public: + boneObject(MeshComponent *owner){ mOwner = owner; } + + StringTableEntry mBoneName; + S32 mItemID; + + virtual void addObject(SimObject *obj); + }; + + Vector mNodesList; + +public: + StringTableEntry mMeshAssetId; + AssetPtr mMeshAsset; + + TSShapeInstance* mShapeInstance; + +public: + MeshComponent(); + virtual ~MeshComponent(); + DECLARE_CONOBJECT(MeshComponent); + + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + + virtual void inspectPostApply(); + + virtual void prepRenderImage(SceneRenderState *state); + + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); + virtual void unpackUpdate(NetConnection *con, BitStream *stream); + + Box3F getShapeBounds() { return mShapeBounds; } + + virtual MatrixF getNodeTransform(S32 nodeIdx); + S32 getNodeByName(String nodeName); + + void setupShape(); + void updateShape(); + void updateMaterials(); + + virtual void onComponentRemove(); + virtual void onComponentAdd(); + + static bool _setMesh(void *object, const char *index, const char *data); + static bool _setShape(void *object, const char *index, const char *data); + const char* _getShape(void *object, const char *data); + + bool setMeshAsset(const char* assetName); + + virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; } + virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; } + + Resource getShapeResource() { if (mMeshAsset) return mMeshAsset->getShapeResource(); else return NULL; } + + void _onResourceChanged(const Torque::Path &path); + + virtual bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info); + + void mountObjectToNode(SceneObject* objB, String node, MatrixF txfm); + + virtual void onDynamicModified(const char* slotName, const char* newValue); + + void changeMaterial(U32 slot, const char* newMat); + + virtual void onInspect(); + virtual void onEndInspect(); + + virtual Vector getNodeTransforms() + { + Vector bob; + return bob; + } + + virtual void setNodeTransforms(Vector transforms) + { + return; + } +}; + +#endif diff --git a/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h b/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h new file mode 100644 index 000000000..08dd6dbfd --- /dev/null +++ b/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h @@ -0,0 +1,155 @@ +//----------------------------------------------------------------------------- +// 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 "console/engineAPI.h" +#include "T3D/components/Render/MeshComponent.h" +#include "scene/sceneObject.h" +#include "math/mTransform.h" + +DefineEngineMethod(MeshComponent, getShapeBounds, Box3F, (), , + "@brief Get the cobject we're in contact with.\n\n" + + "The controlling client is the one that will send moves to us to act on.\n" + + "@return the ID of the controlling GameConnection, or 0 if this object is not " + "controlled by any client.\n" + + "@see GameConnection\n") +{ + return object->getShapeBounds(); +} + +DefineEngineMethod(MeshComponent, mountObject, bool, + (SceneObject* objB, String node, TransformF txfm), (MatrixF::Identity), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (objB) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + object->mountObjectToNode(objB, node, /*MatrixF::Identity*/txfm.getMatrix()); + return true; + } + return false; +} + +DefineEngineMethod(MeshComponent, getNodeTransform, TransformF, + (S32 node), (-1), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (node != -1) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + //object->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() ); + MatrixF mat = object->getNodeTransform(node); + return mat; + } + + return TransformF::Identity; +} + +DefineEngineMethod(MeshComponent, getNodeEulerRot, EulerF, + (S32 node, bool radToDeg), (-1, true), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (node != -1) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + //object->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() ); + MatrixF mat = object->getNodeTransform(node); + + EulerF eul = mat.toEuler(); + if (radToDeg) + eul = EulerF(mRadToDeg(eul.x), mRadToDeg(eul.y), mRadToDeg(eul.z)); + + return eul; + } + + return EulerF(0, 0, 0); +} + +DefineEngineMethod(MeshComponent, getNodePosition, Point3F, + (S32 node), (-1), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (node != -1) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + //object->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() ); + MatrixF mat = object->getNodeTransform(node); + + return mat.getPosition(); + } + + return Point3F(0, 0, 0); +} + +DefineEngineMethod(MeshComponent, getNodeByName, S32, + (String nodeName), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + if (!nodeName.isEmpty()) + { + //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen + //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity + //object->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() ); + S32 node = object->getNodeByName(nodeName); + + return node; + } + + return -1; +} + +DefineEngineMethod(MeshComponent, changeMaterial, void, (U32 slot, const char* newMat), (0, ""), + "@brief Change one of the materials on the shape.\n\n") +{ + object->changeMaterial(slot, newMat); +} \ No newline at end of file diff --git a/Engine/source/T3D/components/Render/renderComponentInterface.h b/Engine/source/T3D/components/Render/renderComponentInterface.h new file mode 100644 index 000000000..67d9a2f8f --- /dev/null +++ b/Engine/source/T3D/components/Render/renderComponentInterface.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// 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 RENDER_COMPONENT_INTERFACE_H +#define RENDER_COMPONENT_INTERFACE_H + +#ifndef _TSSHAPE_H_ +#include "ts/TSShape.h" +#endif +#ifndef _TSSHAPEINSTANCE_H_ +#include "ts/TSShapeInstance.h" +#endif +#ifndef CORE_INTERFACES_H +#include "T3D/Components/coreInterfaces.h" +#endif + +class RenderComponentInterface : public Interface < RenderComponentInterface > +{ +public: + virtual void prepRenderImage(SceneRenderState *state) = 0; + + virtual TSShape* getShape() = 0; + + Signal< void(RenderComponentInterface*) > RenderComponentInterface::onShapeChanged; + + virtual TSShapeInstance* getShapeInstance() = 0; + + virtual MatrixF getNodeTransform(S32 nodeIdx) = 0; + + virtual Vector getNodeTransforms() = 0; + + virtual void setNodeTransforms(Vector transforms) = 0; + + Signal< void(RenderComponentInterface*) > RenderComponentInterface::onShapeInstanceChanged; +}; + +class CastRayRenderedInterface// : public Interface +{ +public: + virtual bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo* info)=0; +}; + +#endif \ No newline at end of file diff --git a/Engine/source/T3D/components/coreInterfaces.h b/Engine/source/T3D/components/coreInterfaces.h new file mode 100644 index 000000000..852628778 --- /dev/null +++ b/Engine/source/T3D/components/coreInterfaces.h @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------------- +// 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 CORE_INTERFACES_H +#define CORE_INTERFACES_H + +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif + +template +class Interface +{ +public: + static Vector all; + + Interface() + { + all.push_back((T*)this); + } + virtual ~Interface() + { + for (U32 i = 0; i < all.size(); i++) + { + if (all[i] == (T*)this) + { + all.erase(i); + return; + } + } + } +}; +template Vector Interface::all(0); + +//Basically a file for generic interfaces that many behaviors may make use of +class SetTransformInterface// : public Interface +{ +public: + virtual void setTransform( MatrixF transform ); + virtual void setTransform( Point3F pos, EulerF rot ); +}; + +class UpdateInterface : public Interface +{ +public: + virtual void processTick(){} + virtual void interpolateTick(F32 dt){} + virtual void advanceTime(F32 dt){} +}; + +class BehaviorFieldInterface// : public Interface +{ +public: + virtual void onFieldChange(const char* fieldName, const char* newValue){}; +}; + +class CameraInterface// : public Interface +{ +public: + virtual bool getCameraTransform(F32* pos,MatrixF* mat)=0; + virtual void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery * query)=0; + virtual Frustum getFrustum()=0; + virtual F32 getCameraFov()=0; + virtual void setCameraFov(F32 fov)=0; + + virtual bool isValidCameraFov(F32 fov)=0; +}; + +class CastRayInterface// : public Interface +{ +public: + virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info)=0; +}; + +class EditorInspectInterface// : public Interface +{ +public: + virtual void onInspect()=0; + virtual void onEndInspect()=0; +}; + +#endif \ No newline at end of file diff --git a/Engine/source/console/consoleObject.h b/Engine/source/console/consoleObject.h index 8ecbb8031..749129ba1 100644 --- a/Engine/source/console/consoleObject.h +++ b/Engine/source/console/consoleObject.h @@ -473,6 +473,8 @@ public: enum FieldFlags { FIELD_HideInInspectors = BIT( 0 ), ///< Do not show the field in inspectors. + FIELD_ComponentInspectors = BIT(1), ///< Custom fields used by components. They are likely to be non-standard size/configuration, so + ///< They are handled specially }; struct Field From b3b50abd9bfd2293914b32499dbd31bae263c492 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 12:40:13 -0500 Subject: [PATCH 31/71] Integrates components into the update and render loop. --- Engine/source/T3D/gameBase/processList.cpp | 8 ++++++ .../T3D/gameBase/std/stdGameProcess.cpp | 25 +++++++++++++++++++ Engine/source/scene/sceneRenderState.cpp | 14 ++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Engine/source/T3D/gameBase/processList.cpp b/Engine/source/T3D/gameBase/processList.cpp index 32b04ca3c..1f891fe09 100644 --- a/Engine/source/T3D/gameBase/processList.cpp +++ b/Engine/source/T3D/gameBase/processList.cpp @@ -27,6 +27,9 @@ #include "platform/profiler.h" #include "console/consoleTypes.h" +#include "T3D/Components/coreInterfaces.h" + +#include "T3D/Components/Component.h" //---------------------------------------------------------------------------- ProcessObject::ProcessObject() @@ -268,6 +271,11 @@ void ProcessList::advanceObjects() onTickObject(pobj); } + for (U32 i = 0; i < UpdateInterface::all.size(); i++) + { + UpdateInterface::all[i]->processTick(); + } + mTotalTicks++; PROFILE_END(); diff --git a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp index 63122b223..51222568c 100644 --- a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp +++ b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp @@ -36,6 +36,8 @@ #include "T3D/gameBase/gameConnection.h" #include "T3D/gameBase/std/stdMoveList.h" #include "T3D/fx/cameraFXMgr.h" +#include "T3D/Components/coreInterfaces.h" +#include "T3D/Components/Component.h" MODULE_BEGIN( ProcessList ) @@ -132,6 +134,16 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) obj = obj->mProcessLink.next; } + for (U32 i = 0; i < UpdateInterface::all.size(); i++) + { + Component *comp = dynamic_cast(UpdateInterface::all[i]); + + if (!comp->isClientObject() || !comp->isActive()) + continue; + + UpdateInterface::all[i]->interpolateTick(mLastDelta); + } + // Inform objects of total elapsed delta so they can advance // client side animations. F32 dt = F32(timeDelta) / 1000; @@ -146,6 +158,19 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) obj = obj->mProcessLink.next; } + for (U32 i = 0; i < UpdateInterface::all.size(); i++) + { + Component *comp = dynamic_cast(UpdateInterface::all[i]); + + if (comp) + { + if (!comp->isClientObject() || !comp->isActive()) + continue; + } + + UpdateInterface::all[i]->advanceTime(dt); + } + return ret; } diff --git a/Engine/source/scene/sceneRenderState.cpp b/Engine/source/scene/sceneRenderState.cpp index 0aeb1d273..3d8db7c26 100644 --- a/Engine/source/scene/sceneRenderState.cpp +++ b/Engine/source/scene/sceneRenderState.cpp @@ -26,7 +26,8 @@ #include "renderInstance/renderPassManager.h" #include "math/util/matrixSet.h" - +#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/Components/Component.h" //----------------------------------------------------------------------------- @@ -104,6 +105,17 @@ void SceneRenderState::renderObjects( SceneObject** objects, U32 numObjects ) SceneObject* object = objects[ i ]; object->prepRenderImage( this ); } + + U32 interfaceCount = RenderComponentInterface::all.size(); + for (U32 i = 0; i < RenderComponentInterface::all.size(); i++) + { + Component* comp = dynamic_cast(RenderComponentInterface::all[i]); + + if (comp->isClientObject() && comp->isActive()) + { + RenderComponentInterface::all[i]->prepRenderImage(this); + } + } PROFILE_END(); // Render what the objects have batched. From 38c18870d396724d9d31cbe4493158ad3235482d Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 14:03:19 -0500 Subject: [PATCH 32/71] Adjustments to allow Entities/Components to act as cameras and control objects. --- Engine/source/T3D/gameBase/gameConnection.cpp | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/gameBase/gameConnection.cpp b/Engine/source/T3D/gameBase/gameConnection.cpp index 7aada8048..cb8a5c1af 100644 --- a/Engine/source/T3D/gameBase/gameConnection.cpp +++ b/Engine/source/T3D/gameBase/gameConnection.cpp @@ -38,6 +38,8 @@ #include "T3D/gameBase/gameConnectionEvents.h" #include "console/engineAPI.h" #include "math/mTransform.h" +#include "T3D/Entity.h" +#include "T3D/Components/coreInterfaces.h" #ifdef TORQUE_HIFI_NET #include "T3D/gameBase/hifi/hifiMoveList.h" @@ -551,7 +553,9 @@ void GameConnection::setControlObject(GameBase *obj) obj->setControllingClient(this); // Update the camera's FOV to match the new control object - setControlCameraFov( obj->getCameraFov() ); + //but only if we don't have a specific camera object + if (!mCameraObject) + setControlCameraFov(obj->getCameraFov()); } // Okay, set our control object. @@ -729,7 +733,17 @@ bool GameConnection::getControlCameraFov(F32 * fov) } if (cObj) { + if (Entity* ent = dynamic_cast(cObj)) + { + if (CameraInterface* camInterface = ent->getComponent()) + { + *fov = camInterface->getCameraFov(); + } + } + else + { *fov = cObj->getCameraFov(); + } return(true); } @@ -747,7 +761,22 @@ bool GameConnection::isValidControlCameraFov(F32 fov) obj = obj->getControlObject(); } - return cObj ? cObj->isValidCameraFov(fov) : NULL; + if (cObj) + { + if (Entity* ent = dynamic_cast(cObj)) + { + if (CameraInterface* camInterface = ent->getComponent()) + { + return camInterface->isValidCameraFov(fov); + } + } + else + { + return cObj->isValidCameraFov(fov); + } + } + + return NULL; } bool GameConnection::setControlCameraFov(F32 fov) @@ -762,9 +791,25 @@ bool GameConnection::setControlCameraFov(F32 fov) } if (cObj) { + F32 newFov = 90.f; + if (Entity* ent = dynamic_cast(cObj)) + { + if (CameraInterface* camInterface = ent->getComponent()) + { + camInterface->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov)); + newFov = camInterface->getCameraFov(); + } + else + { + Con::errorf("Attempted to setControlCameraFov, but we don't have a camera!"); + } + } + else + { // allow shapebase to clamp fov to its datablock values cObj->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov)); F32 newFov = cObj->getCameraFov(); + } // server fov of client has 1degree resolution if( S32(newFov) != S32(mCameraFov) || newFov != fov ) @@ -1147,10 +1192,17 @@ void GameConnection::readPacket(BitStream *bstream) if (bstream->readFlag()) { + bool callScript = false; + if (mCameraObject.isNull()) + callScript = true; + S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize); GameBase* obj = dynamic_cast(resolveGhost(gIndex)); setCameraObject(obj); obj->readPacketData(this, bstream); + + if (callScript) + initialControlSet_callback(); } else setCameraObject(0); @@ -1727,6 +1779,13 @@ DefineEngineMethod( GameConnection, transmitDataBlocks, void, (S32 sequence),, // Ensure that the client knows that the datablock send is done... object->sendConnectionMessage(GameConnection::DataBlocksDone, object->getDataBlockSequence()); } + + if (iCount == 0) + { + //if we have no datablocks to send, we still need to be able to complete the level load process + //so fire off our callback anyways + object->sendConnectionMessage(GameConnection::DataBlocksDone, object->getDataBlockSequence()); + } } else { From 827e70d6747226b7f38529d4c9b10833eb884fb9 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 14:12:53 -0500 Subject: [PATCH 33/71] Integration of Entities into the inspector/editor so they can call back into the tool scripts for custom handling. --- .../source/gui/controls/guiTreeViewCtrl.cpp | 58 +- Engine/source/gui/controls/guiTreeViewCtrl.h | 13 +- Engine/source/gui/editor/guiInspector.cpp | 24 +- .../gui/editor/inspector/entityGroup.cpp | 135 +++++ .../source/gui/editor/inspector/entityGroup.h | 72 +++ .../gui/editor/inspector/mountingGroup.cpp | 507 ++++++++++++++++++ .../gui/editor/inspector/mountingGroup.h | 152 ++++++ Engine/source/gui/worldEditor/editor.cpp | 4 +- 8 files changed, 960 insertions(+), 5 deletions(-) create mode 100644 Engine/source/gui/editor/inspector/entityGroup.cpp create mode 100644 Engine/source/gui/editor/inspector/entityGroup.h create mode 100644 Engine/source/gui/editor/inspector/mountingGroup.cpp create mode 100644 Engine/source/gui/editor/inspector/mountingGroup.h diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index 99fb8b440..c243ce6eb 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -36,7 +36,7 @@ #include "gui/editor/editorFunctions.h" #endif #include "console/engineAPI.h" - +#include "T3D/Entity.h" IMPLEMENT_CONOBJECT(GuiTreeViewCtrl); @@ -486,6 +486,14 @@ void GuiTreeViewCtrl::Item::getDisplayText(U32 bufLen, char *buf) { FrameAllocatorMarker txtAlloc; + //if we're doing the special case of forcing the item text, just skip the rest of this junk + if (mState.test(ForceItemName)) + { + StringTableEntry text = (mScriptInfo.mText) ? mScriptInfo.mText : StringTable->EmptyString(); + dStrncpy(buf, text, bufLen); + return; + } + if( mState.test( InspectorData ) ) { SimObject *pObject = getObject(); @@ -637,6 +645,18 @@ void GuiTreeViewCtrl::Item::getTooltipText(U32 bufLen, char *buf) bool GuiTreeViewCtrl::Item::isParent() const { + //We might have a special case with entities + //So if our entity either has children, or has some component with the EditorInspect interface, we return true + if (mInspectorInfo.mObject) + { + Entity* e = dynamic_cast(mInspectorInfo.mObject.getObject()); + if (e) + { + if (e->size() > 0 || e->getComponentCount() != 0) + return true; + } + } + if(mState.test(VirtualParent)) { if( !isInspectorData() ) @@ -1518,6 +1538,11 @@ bool GuiTreeViewCtrl::isValidDragTarget( Item* item ) { bool isValid = true; + // First, check if we're just going to override this from manually setting the ForceAllowDrag flag + // If that's set, we're assuming special circumstances and will just let it go on it's way + if (item->isDragTargetAllowed()) + return true; + // If this is inspector data, first make sure the item accepts all // selected objects as children. This prevents bad surprises when // certain SimSet subclasses reject children and start shoving them @@ -3462,6 +3487,11 @@ void GuiTreeViewCtrl::onMouseDragged(const GuiEvent &event) if (mSelectedItems.size() == 0) return; + //Check through to make sure all attempted dragged items even allow it + for (U32 i = 0; i < mSelectedItems.size(); i++) + if (!mSelectedItems[i]->isDragAllowed()) + return; + // Give us a little delta before we actually start a mouse drag so that // if the user moves the mouse a little while clicking, he/she does not // accidentally trigger a drag. @@ -3756,6 +3786,23 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) ) onVirtualParentExpand(item); + //Slightly hacky, but I'm not sure of a better setup until we get major update to the editors + //We check if our object is an entity, and if it is, we call a 'onInspect' function. + //This function is pretty much a special notifier to the entity so if it has any behaviors that do special + //stuff in the editor, it can fire that up + Entity* e = dynamic_cast(item->getObject()); + if (item->mScriptInfo.mText != StringTable->insert("Components")) + { + Entity* e = dynamic_cast(item->getObject()); + if (e) + { + if (item->isExpanded()) + e->onInspect(); + else + e->onEndInspect(); + } + } + mFlags.set( RebuildVisible ); scrollVisible(item); } @@ -4490,6 +4537,11 @@ bool GuiTreeViewCtrl::objectSearch( const SimObject *object, Item **item ) Item *pItem = mItems[i]; if ( !pItem ) + continue; + + //A bit hackish, but we make a special exception here for items that are named 'Components', as they're merely + //virtual parents to act as a container to an Entity's components + if (pItem->mScriptInfo.mText == StringTable->insert("Components")) continue; SimObject *pObj = pItem->getObject(); @@ -4555,6 +4607,10 @@ bool GuiTreeViewCtrl::onVirtualParentBuild(Item *item, bool bForceFullUpdate) // Go through our items and purge those that have disappeared from // the set. + + //Entities will be a special case here, if we're an entity, skip this step + if (dynamic_cast(srcObj)) + return true; for( Item* ptr = item->mChild; ptr != NULL; ) { diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.h b/Engine/source/gui/controls/guiTreeViewCtrl.h index e2360ed87..91f842b3d 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.h +++ b/Engine/source/gui/controls/guiTreeViewCtrl.h @@ -75,7 +75,10 @@ class GuiTreeViewCtrl : public GuiArrayCtrl ShowClassName = BIT( 11 ), ShowObjectName = BIT( 12 ), ShowInternalName = BIT( 13 ), - ShowClassNameForUnnamed = BIT( 14 ) + ShowClassNameForUnnamed = BIT( 14 ), + ForceItemName = BIT(15), + ForceDragTarget = BIT(16), + DenyDrag = BIT(17), }; GuiTreeViewCtrl* mParentControl; @@ -169,6 +172,14 @@ class GuiTreeViewCtrl : public GuiArrayCtrl /// or false if it's just an item. bool isInspectorData() const { return mState.test(InspectorData); }; + /// Returns true if we've been manually set to allow dragging overrides. + /// As it's a manually set flag, by default it is false. + bool isDragTargetAllowed() const { return mState.test(ForceDragTarget); }; + + /// Returns true if we've been manually set to allow dragging overrides. + /// As it's a manually set flag, by default it is false. + bool isDragAllowed() const { return !mState.test(DenyDrag); }; + /// Returns true if we should show the expand art /// and make the item interact with the mouse as if /// it were a parent. diff --git a/Engine/source/gui/editor/guiInspector.cpp b/Engine/source/gui/editor/guiInspector.cpp index af12b2810..79905ea97 100644 --- a/Engine/source/gui/editor/guiInspector.cpp +++ b/Engine/source/gui/editor/guiInspector.cpp @@ -28,7 +28,8 @@ #include "gui/editor/inspector/dynamicGroup.h" #include "gui/containers/guiScrollCtrl.h" #include "gui/editor/inspector/customField.h" - +#include "gui/editor/inspector/entityGroup.h" +#include "gui/editor/inspector/mountingGroup.h" IMPLEMENT_CONOBJECT(GuiInspector); @@ -584,6 +585,27 @@ void GuiInspector::refresh() mGroups.push_back(general); addObject(general); + //Behavior inspector group + if (mTargets.first()->getClassRep()->isSubclassOf("Entity")) + { + GuiInspectorEntityGroup *components = new GuiInspectorEntityGroup("Components", this); + if (components != NULL) + { + components->registerObject(); + mGroups.push_back(components); + addObject(components); + } + + //Mounting group override + GuiInspectorGroup *mounting = new GuiInspectorMountingGroup("Mounting", this); + if (mounting != NULL) + { + mounting->registerObject(); + mGroups.push_back(mounting); + addObject(mounting); + } + } + // Create the inspector groups for static fields. for( TargetVector::iterator iter = mTargets.begin(); iter != mTargets.end(); ++ iter ) diff --git a/Engine/source/gui/editor/inspector/entityGroup.cpp b/Engine/source/gui/editor/inspector/entityGroup.cpp new file mode 100644 index 000000000..7c7bd2762 --- /dev/null +++ b/Engine/source/gui/editor/inspector/entityGroup.cpp @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// 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 "gui/buttons/guiIconButtonCtrl.h" +#include "gui/editor/guiInspector.h" +#include "gui/editor/inspector/entityGroup.h" +#include "core/strings/stringUnit.h" +#include "T3D/Components/Component.h" + +#include "console/engineAPI.h" + +IMPLEMENT_CONOBJECT(GuiInspectorEntityGroup); + +ConsoleDocClass(GuiInspectorEntityGroup, + "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " + "of regular persistent fields.\n\n" + "Editor use only.\n\n" + "@internal" + ); + +bool GuiInspectorEntityGroup::onAdd() +{ + if (!Parent::onAdd()) + return false; +} + +//----------------------------------------------------------------------------- +// GuiInspectorEntityGroup - add custom controls +//----------------------------------------------------------------------------- +bool GuiInspectorEntityGroup::createContent() +{ + if(!Parent::createContent()) + return false; + + Con::evaluatef("%d.stack = %d;", this->getId(), mStack->getId()); + + Con::executef(this, "createContent"); + + return true; +} + +//----------------------------------------------------------------------------- +// GuiInspectorEntityGroup - inspectGroup override +//----------------------------------------------------------------------------- +bool GuiInspectorEntityGroup::inspectGroup() +{ + const U32 numTargets = mParent->getNumInspectObjects(); + if (numTargets == 1) + { + Entity* target = dynamic_cast(mParent->getInspectObject(0)); + + Con::executef(this, "inspectObject", target->getIdString()); + } + + return true; +} + +void GuiInspectorEntityGroup::updateAllFields() +{ + // We overload this to just reinspect the group. + inspectGroup(); +} + +void GuiInspectorEntityGroup::onMouseMove(const GuiEvent &event) +{ + //mParent->mOverDivider = false; +} +ConsoleMethod(GuiInspectorEntityGroup, inspectGroup, bool, 2, 2, "Refreshes the dynamic fields in the inspector.") +{ + return object->inspectGroup(); +} + +void GuiInspectorEntityGroup::clearFields() +{ +} + +SimFieldDictionary::Entry* GuiInspectorEntityGroup::findDynamicFieldInDictionary(StringTableEntry fieldName) +{ + SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); + + for (SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) + { + SimFieldDictionary::Entry * entry = (*ditr); + + if (entry->slotName == fieldName) + return entry; + } + + return NULL; +} + +void GuiInspectorEntityGroup::addDynamicField() +{ +} + +AbstractClassRep::Field* GuiInspectorEntityGroup::findObjectBehaviorField(Component* target, String fieldName) +{ + AbstractClassRep::FieldList& fieldList = target->getClassRep()->mFieldList; + for (AbstractClassRep::FieldList::iterator itr = fieldList.begin(); + itr != fieldList.end(); ++itr) + { + AbstractClassRep::Field* field = &(*itr); + String fldNm(field->pFieldname); + if (fldNm == fieldName) + return field; + } + return NULL; +} +ConsoleMethod(GuiInspectorEntityGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();") +{ + object->addDynamicField(); +} + +ConsoleMethod(GuiInspectorEntityGroup, removeDynamicField, void, 3, 3, "") +{ +} diff --git a/Engine/source/gui/editor/inspector/entityGroup.h b/Engine/source/gui/editor/inspector/entityGroup.h new file mode 100644 index 000000000..327539846 --- /dev/null +++ b/Engine/source/gui/editor/inspector/entityGroup.h @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// 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 GUI_INSPECTOR_ENTITY_GROUP_H +#define GUI_INSPECTOR_ENTITY_GROUP_H + +#include "gui/editor/inspector/group.h" +#include "console/simFieldDictionary.h" +#include "T3D/Components/Component.h" +#include "gui/controls/guiPopUpCtrlEx.h" + +class GuiInspectorEntityGroup : public GuiInspectorGroup +{ +private: + typedef GuiInspectorGroup Parent; + GuiControl* mAddCtrl; + + GuiPopUpMenuCtrlEx* mAddBhvrList; + +public: + DECLARE_CONOBJECT(GuiInspectorEntityGroup); + GuiInspectorEntityGroup() { /*mNeedScroll=false;*/ }; + GuiInspectorEntityGroup(StringTableEntry groupName, SimObjectPtr parent) + : GuiInspectorGroup(groupName, parent) { /*mNeedScroll=false;*/ + }; + + //----------------------------------------------------------------------------- + // inspectGroup is overridden in GuiInspectorEntityGroup to inspect an + // objects FieldDictionary (dynamic fields) instead of regular persistent + // fields. + virtual bool onAdd(); + bool inspectGroup(); + virtual void updateAllFields(); + + void onMouseMove(const GuiEvent &event); + + // For scriptable dynamic field additions + void addDynamicField(); + + // Clear our fields (delete them) + void clearFields(); + + // Find an already existent field by name in the dictionary + virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary(StringTableEntry fieldName); + + AbstractClassRep::Field* findObjectBehaviorField(Component* target, String fieldName); +protected: + // create our inner controls when we add + virtual bool createContent(); + +}; + +#endif diff --git a/Engine/source/gui/editor/inspector/mountingGroup.cpp b/Engine/source/gui/editor/inspector/mountingGroup.cpp new file mode 100644 index 000000000..bcfa19fa9 --- /dev/null +++ b/Engine/source/gui/editor/inspector/mountingGroup.cpp @@ -0,0 +1,507 @@ +//----------------------------------------------------------------------------- +// 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 "gui/buttons/guiIconButtonCtrl.h" +#include "gui/editor/guiInspector.h" +#include "gui/editor/inspector/mountingGroup.h" +#include "core/strings/stringUnit.h" +#include "T3D/Entity.h" +#include "T3D/Components/Component.h" + +//Need this to get node lists +#include "T3D/Components/render/renderComponentInterface.h" + +IMPLEMENT_CONOBJECT(GuiInspectorMountingGroup); + +ConsoleDocClass( GuiInspectorMountingGroup, + "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " + "of regular persistent fields.\n\n" + "Editor use only.\n\n" + "@internal" +); + +//----------------------------------------------------------------------------- +// GuiInspectorMountingGroup - add custom controls +//----------------------------------------------------------------------------- +GuiInspectorMountingGroup::GuiInspectorMountingGroup( StringTableEntry groupName, SimObjectPtr parent ) + : GuiInspectorGroup( groupName, parent) +{ + mParentInspector = parent; + + targetMountCtrl = NULL; + mountCtrl = NULL; +}; + +bool GuiInspectorMountingGroup::createContent() +{ + if(!Parent::createContent()) + return false; + + //give the necessary padding for the nested controls so it looks nice. + setMargin(RectI(4,0,4,4)); + + return true; +} + +GuiControl* GuiInspectorMountingGroup::buildMenuCtrl() +{ + GuiControl* retCtrl = new GuiPopUpMenuCtrl(); + + // If we couldn't construct the control, bail! + if( retCtrl == NULL ) + return retCtrl; + + GuiPopUpMenuCtrl *menu = dynamic_cast(retCtrl); + + // Let's make it look pretty. + retCtrl->setDataField( StringTable->insert("profile"), NULL, "GuiPopUpMenuProfile" ); + //GuiInspectorTypeMenuBase::_registerEditControl( retCtrl ); + + char szName[512]; + dSprintf( szName, 512, "IE_%s_%d_%s_Field", retCtrl->getClassName(), mParentInspector->getInspectObject()->getId(), mCaption); + + // Register the object + retCtrl->registerObject( szName ); + + // Configure it to update our value when the popup is closed + char szBuffer[512]; + dSprintf( szBuffer, 512, "%d.apply( %d.getText() );", getId(), menu->getId() ); + menu->setField("Command", szBuffer ); + + return menu; +} + +bool GuiInspectorMountingGroup::buildList(Entity* ent, GuiPopUpMenuCtrl* menu) +{ + RenderComponentInterface* renderInterface = ent->getComponent(); + + if (renderInterface) + { + TSShape* shape = renderInterface->getShape(); + S32 nodeCount = shape ? shape->nodes.size() : 0; + + for(U32 i=0; i < nodeCount; i++) + { + menu->addEntry(shape->names[i], i); + } + + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// GuiInspectorMountingGroup - inspectGroup override +//----------------------------------------------------------------------------- +bool GuiInspectorMountingGroup::inspectGroup() +{ + // We can't inspect a group without a target! + if( !mParent->getNumInspectObjects() ) + return false; + + // to prevent crazy resizing, we'll just freeze our stack for a sec.. + mStack->freeze(true); + + bool bNoGroup = false; + + // Un-grouped fields are all sorted into the 'general' group + if ( dStricmp( mCaption, "General" ) == 0 ) + bNoGroup = true; + + // Just delete all fields and recreate them (like the dynamicGroup) + // because that makes creating controls for array fields a lot easier + clearFields(); + + bool bNewItems = false; + bool bMakingArray = false; + GuiStackControl *pArrayStack = NULL; + GuiRolloutCtrl *pArrayRollout = NULL; + bool bGrabItems = false; + + AbstractClassRep* commonAncestorClass = findCommonAncestorClass(); + AbstractClassRep::FieldList& fieldList = commonAncestorClass->mFieldList; + for( AbstractClassRep::FieldList::iterator itr = fieldList.begin(); + itr != fieldList.end(); ++ itr ) + { + AbstractClassRep::Field* field = &( *itr ); + if( field->type == AbstractClassRep::StartGroupFieldType ) + { + // If we're dealing with general fields, always set grabItems to true (to skip them) + if( bNoGroup == true ) + bGrabItems = true; + else if( dStricmp( field->pGroupname, mCaption ) == 0 ) + bGrabItems = true; + continue; + } + else if ( field->type == AbstractClassRep::EndGroupFieldType ) + { + // If we're dealing with general fields, always set grabItems to false (to grab them) + if( bNoGroup == true ) + bGrabItems = false; + else if( dStricmp( field->pGroupname, mCaption ) == 0 ) + bGrabItems = false; + continue; + } + + // Skip field if it has the HideInInspectors flag set. + + if( field->flag.test( AbstractClassRep::FIELD_HideInInspectors ) ) + continue; + + if( ( bGrabItems == true || ( bNoGroup == true && bGrabItems == false ) ) && itr->type != AbstractClassRep::DeprecatedFieldType ) + { + if( bNoGroup == true && bGrabItems == true ) + continue; + + // If the field already exists, just update it + GuiInspectorField *fieldGui = findField( field->pFieldname ); + if ( fieldGui != NULL ) + { + fieldGui->updateValue(); + continue; + } + + bNewItems = true; + + if(field->pFieldname == StringTable->insert("mountNode")) + { + fieldGui = new GuiInspectorNodeListField(); + + Entity* e = dynamic_cast(mParent->getInspectObject(0)); + if(e) + (dynamic_cast(fieldGui))->setTargetEntity(e); + } + else + { + fieldGui = constructField( field->type ); + if ( fieldGui == NULL ) + fieldGui = new GuiInspectorField(); + } + + fieldGui->init( mParent, this ); + fieldGui->setInspectorField( field ); + + if( fieldGui->registerObject() ) + { + #ifdef DEBUG_SPEW + Platform::outputDebugString( "[GuiInspectorGroup] Adding field '%s'", + field->pFieldname ); + #endif + + mChildren.push_back( fieldGui ); + mStack->addObject( fieldGui ); + } + else + { + SAFE_DELETE( fieldGui ); + } + } + } + mStack->freeze(false); + mStack->updatePanes(); + + // If we've no new items, there's no need to resize anything! + if( bNewItems == false && !mChildren.empty() ) + return true; + + sizeToContents(); + + setUpdate(); + + return true; +} + +void GuiInspectorMountingGroup::updateAllFields() +{ + // We overload this to just reinspect the group. + inspectGroup(); +} + +void GuiInspectorMountingGroup::onMouseMove(const GuiEvent &event) +{ + //mParent->mOverDivider = false; + bool test = false; +} +ConsoleMethod(GuiInspectorMountingGroup, inspectGroup, bool, 2, 2, "Refreshes the dynamic fields in the inspector.") +{ + return object->inspectGroup(); +} + +void GuiInspectorMountingGroup::clearFields() +{ +} + +bool GuiInspectorMountingGroup::resize( const Point2I &newPosition, const Point2I &newExtent ) +{ + if ( !Parent::resize( newPosition, newExtent ) ) + return false; + + //check if we're set up yet + if(!targetMountCtrl || !mountCtrl) + //no? bail + return false; + + targetMountCtrl->setExtent(newExtent.x, 18); + mountCtrl->setExtent(newExtent.x, 18); + + S32 dividerPos, dividerMargin; + mParentInspector->getDivider( dividerPos, dividerMargin ); + + Point2I fieldExtent = Point2I(newExtent.x, 18); + Point2I fieldPos = Point2I(newExtent.x, 18); + + S32 editWidth = dividerPos - dividerMargin; + + targetMountText->setPosition(0,0); + targetMountText->setExtent(fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y); + + targetMountNode->setPosition(fieldExtent.x - dividerPos + dividerMargin, 1); + targetMountNode->setExtent(editWidth, fieldExtent.y - 1); + + mountText->setPosition(0,0); + mountText->setExtent(fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y); + + mountNode->setPosition(fieldExtent.x - dividerPos + dividerMargin, 1); + mountNode->setExtent(editWidth, fieldExtent.y - 1); + + return true; +} + +SimFieldDictionary::Entry* GuiInspectorMountingGroup::findDynamicFieldInDictionary( StringTableEntry fieldName ) +{ + SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); + + for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) + { + SimFieldDictionary::Entry * entry = (*ditr); + + if( entry->slotName == fieldName ) + return entry; + } + + return NULL; +} + +void GuiInspectorMountingGroup::addDynamicField() +{ +} + +AbstractClassRep::Field* GuiInspectorMountingGroup::findObjectComponentField(Component* target, String fieldName) +{ + AbstractClassRep::FieldList& fieldList = target->getClassRep()->mFieldList; + for( AbstractClassRep::FieldList::iterator itr = fieldList.begin(); + itr != fieldList.end(); ++ itr ) + { + AbstractClassRep::Field* field = &( *itr ); + String fldNm(field->pFieldname); + if(fldNm == fieldName) + return field; + } + return NULL; +} +ConsoleMethod( GuiInspectorMountingGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();" ) +{ + object->addDynamicField(); +} + +ConsoleMethod( GuiInspectorMountingGroup, removeDynamicField, void, 3, 3, "" ) +{ +} + +// +IMPLEMENT_CONOBJECT( GuiInspectorNodeListField ); + +ConsoleDocClass( GuiInspectorNodeListField, + "@brief A control that allows to edit the custom properties (text) of one or more SimObjects.\n\n" + "Editor use only.\n\n" + "@internal" +); + +GuiInspectorNodeListField::GuiInspectorNodeListField( GuiInspector *inspector, + GuiInspectorGroup* parent, + SimFieldDictionary::Entry* field, + SimObjectPtr target ) +{ + mInspector = inspector; + mParent = parent; + setBounds(0,0,100,20); + mTargetEntity = target; +} + +GuiInspectorNodeListField::GuiInspectorNodeListField() +{ + mInspector = NULL; + mParent = NULL; +} + +void GuiInspectorNodeListField::setData( const char* data, bool callbacks ) +{ + mCustomValue = data; + + //We aren't updating any mounting info if we're not mounted already + if(mTargetEntity.getObject()) + { + Entity* target = dynamic_cast(mTargetEntity->getObjectMount()); + if(target) + { + RenderComponentInterface* renderInterface = target->getComponent(); + if (renderInterface) + { + if (renderInterface->getShape()) + { + S32 nodeIdx = renderInterface->getShape()->findNode(data); + + target->mountObject(mTargetEntity, nodeIdx, MatrixF::Identity); + mTargetEntity->setMaskBits(Entity::MountedMask); + } + } + } + } + + // Force our edit to update + updateValue(); +} + +const char* GuiInspectorNodeListField::getData( U32 inspectObjectIndex ) +{ + return mCustomValue; +} + +void GuiInspectorNodeListField::updateValue() +{ + mMenu->clear(); + //mMenu->addEntry("Origin"); + + //if(mCustomValue.isEmpty()) + if(mTargetEntity.getObject()) + { + Entity* target = dynamic_cast(mTargetEntity->getObjectMount()); + if(target) + { + mMenu->addEntry("Origin"); + mMenu->setActive(true); + + RenderComponentInterface* renderInterface = target->getComponent(); + + if (renderInterface) + { + TSShape* shape = renderInterface->getShape(); + + S32 nodeCount = shape ? shape->nodes.size() : 0; + + for(U32 i=0; i < nodeCount; i++) + { + mMenu->addEntry(shape->names[i], i); + } + + S32 targetNode = mTargetEntity->getMountNode(); + if(targetNode != -1) + { + String name = shape->names[targetNode]; + mCustomValue = name; + } + else + { + mCustomValue = String("Origin"); + } + + setValue( mCustomValue ); + return; + } + } + } + + setValue("Not Mounted"); + mMenu->setActive(false); +} + +void GuiInspectorNodeListField::setDoc( const char* doc ) +{ + mDoc = StringTable->insert( doc, true ); +} + +void GuiInspectorNodeListField::setToolTip( StringTableEntry data ) +{ + static StringTableEntry sTooltipProfile = StringTable->insert( "tooltipProfile" ); + static StringTableEntry sHoverTime = StringTable->insert( "hovertime" ); + static StringTableEntry sTooltip = StringTable->insert( "tooltip" ); + + mEdit->setDataField( sTooltipProfile, NULL, "GuiToolTipProfile" ); + mEdit->setDataField( sHoverTime, NULL, "1000" ); + mEdit->setDataField( sTooltip, NULL, data ); +} + +bool GuiInspectorNodeListField::onAdd() +{ + if( !Parent::onAdd() ) + return false; + + return true; +} + +void GuiInspectorNodeListField::setInspectorField( AbstractClassRep::Field *field, + StringTableEntry caption, + const char*arrayIndex ) +{ + // Override the base just to be sure it doesn't get called. + // We don't use an AbstractClassRep::Field... + + mField = field; + mCaption = field->pFieldname; + mDoc = field->pFieldDocs; +} + +GuiControl* GuiInspectorNodeListField::constructEditControl() +{ + GuiControl* retCtrl = new GuiPopUpMenuCtrl(); + + mMenu = dynamic_cast(retCtrl); + + static StringTableEntry sProfile = StringTable->insert( "profile" ); + retCtrl->setDataField( sProfile, NULL, "ToolsGuiPopUpMenuEditProfile" ); + + // Register the object + retCtrl->registerObject(); + + char szBuffer[512]; + dSprintf( szBuffer, 512, "%d.apply( %d.getText() );", getId(), mMenu->getId() ); + mMenu->setField("Command", szBuffer ); + + return retCtrl; +} + +void GuiInspectorNodeListField::setValue( const char* newValue ) +{ + GuiPopUpMenuCtrl *ctrl = dynamic_cast( mEdit ); + if( ctrl != NULL ) + ctrl->setText( newValue ); +} + +void GuiInspectorNodeListField::_executeSelectedCallback() +{ +} + +void GuiInspectorNodeListField::setTargetEntity(SimObjectPtr target) +{ + mTargetEntity = target; +} \ No newline at end of file diff --git a/Engine/source/gui/editor/inspector/mountingGroup.h b/Engine/source/gui/editor/inspector/mountingGroup.h new file mode 100644 index 000000000..da8ed91a6 --- /dev/null +++ b/Engine/source/gui/editor/inspector/mountingGroup.h @@ -0,0 +1,152 @@ +//----------------------------------------------------------------------------- +// 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 GUI_INSPECTOR_MOUNTINGGROUP_H +#define GUI_INSPECTOR_MOUNTINGGROUP_H + +#include "gui/editor/inspector/group.h" +#include "console/simFieldDictionary.h" +#include "T3D/Components/Component.h" +#include "gui/controls/guiPopUpCtrlEx.h" + +#ifndef _GUI_INSPECTOR_TYPES_H_ +#include "gui/editor/guiInspectorTypes.h" +#endif + +#ifndef _ENTITY_H_ +#include "T3D/Entity.h" +#endif + +class GuiInspectorMountingGroup; + +class GuiInspectorNodeListField : public GuiInspectorField +{ + typedef GuiInspectorField Parent; + friend class GuiInspectorMountingGroup; + +public: + + GuiInspectorNodeListField( GuiInspector *inspector, GuiInspectorGroup* parent, SimFieldDictionary::Entry* field, + SimObjectPtr target ); + GuiInspectorNodeListField(); + ~GuiInspectorNodeListField() {}; + + DECLARE_CONOBJECT( GuiInspectorNodeListField ); + + virtual void setData( const char* data, bool callbacks = true ); + virtual const char* getData( U32 inspectObjectIndex = 0 ); + virtual void updateValue(); + virtual StringTableEntry getFieldName() { return StringTable->EmptyString(); } + + virtual void setDoc( const char* doc ); + virtual void setToolTip( StringTableEntry data ); + + virtual bool onAdd(); + + virtual void setInspectorField( AbstractClassRep::Field *field, + StringTableEntry caption = NULL, + const char *arrayIndex = NULL ); + + virtual GuiControl* constructEditControl(); + + virtual void setValue( const char* newValue ); + + void setTargetEntity(SimObjectPtr target); + +protected: + + virtual void _executeSelectedCallback(); + +protected: + + String mCustomValue; + StringTableEntry mDoc; + + GuiPopUpMenuCtrl *mMenu; + + SimObjectPtr mTargetEntity; +}; + +class GuiInspectorMountingGroup : public GuiInspectorGroup +{ +private: + typedef GuiInspectorGroup Parent; + GuiControl* mAddCtrl; + + GuiPopUpMenuCtrlEx* mAddBhvrList; + + GuiTextCtrl *persistText; + GuiButtonCtrl *reloadFile; + GuiButtonCtrl *saveFile; + GuiButtonCtrl *overwriteFile; + GuiButtonCtrl *mBrowseButton; + GuiControl *filePath; + + GuiControl *targetMountCtrl; + GuiTextCtrl *targetMountText; + GuiPopUpMenuCtrl *targetMountNode; + + GuiControl *mountCtrl; + GuiTextCtrl *mountText; + GuiPopUpMenuCtrl *mountNode; + + GuiInspectorNodeListField* mountNodeList; + GuiInspectorNodeListField* targetMountNodeList; + + SimObjectPtr mParentInspector; + +public: + DECLARE_CONOBJECT(GuiInspectorMountingGroup); + GuiInspectorMountingGroup() { /*mNeedScroll=false;*/ }; + GuiInspectorMountingGroup( StringTableEntry groupName, SimObjectPtr parent ); + + //----------------------------------------------------------------------------- + // inspectGroup is overridden in GuiInspectorMountingGroup to inspect an + // objects FieldDictionary (dynamic fields) instead of regular persistent + // fields. + bool inspectGroup(); + virtual void updateAllFields(); + + void onMouseMove(const GuiEvent &event); + + // For scriptable dynamic field additions + void addDynamicField(); + + // Clear our fields (delete them) + void clearFields(); + + virtual bool resize( const Point2I &newPosition, const Point2I &newExtent ); + + // Find an already existent field by name in the dictionary + virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary( StringTableEntry fieldName ); + + AbstractClassRep::Field* findObjectComponentField(Component* target, String fieldName); +protected: + // create our inner controls when we add + virtual bool createContent(); + + GuiControl* buildMenuCtrl(); + + bool buildList(Entity* ent, GuiPopUpMenuCtrl* menu); +}; + +#endif diff --git a/Engine/source/gui/worldEditor/editor.cpp b/Engine/source/gui/worldEditor/editor.cpp index cfcee744d..2f05c96ad 100644 --- a/Engine/source/gui/worldEditor/editor.cpp +++ b/Engine/source/gui/worldEditor/editor.cpp @@ -122,9 +122,9 @@ void EditManager::editorDisabled() static GameBase * getControlObj() { GameConnection * connection = GameConnection::getLocalClientConnection(); - ShapeBase* control = 0; + GameBase* control = 0; if(connection) - control = dynamic_cast(connection->getControlObject()); + control = connection->getControlObject(); return(control); } From b4bc405dce047396ce11519c96f2bd5b10d6f65e Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 14:16:43 -0500 Subject: [PATCH 34/71] Updates the include guard in ShapeAsset --- Engine/source/T3D/assets/ShapeAsset.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index dac95a45e..6766d1682 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -19,8 +19,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#ifndef _SHAPE_ASSET_H_ -#define _SHAPE_ASSET_H_ +#ifndef SHAPE_ASSET_H +#define SHAPE_ASSET_H #ifndef _ASSET_BASE_H_ #include "assets/assetBase.h" @@ -84,5 +84,5 @@ protected: DefineConsoleType(TypeShapeAssetPtr, ShapeAsset) -#endif // _ASSET_BASE_H_ +#endif From 6ccf97e35de99ce254504e574aad9a31c4c092ef Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 14:17:33 -0500 Subject: [PATCH 35/71] Adds ComponentAsset so the editor scripts can be aware of what components have been defined/are useable. --- Engine/source/T3D/assets/ComponentAsset.cpp | 138 ++++++++++++++++++++ Engine/source/T3D/assets/ComponentAsset.h | 77 +++++++++++ 2 files changed, 215 insertions(+) create mode 100644 Engine/source/T3D/assets/ComponentAsset.cpp create mode 100644 Engine/source/T3D/assets/ComponentAsset.h diff --git a/Engine/source/T3D/assets/ComponentAsset.cpp b/Engine/source/T3D/assets/ComponentAsset.cpp new file mode 100644 index 000000000..2f4d524ac --- /dev/null +++ b/Engine/source/T3D/assets/ComponentAsset.cpp @@ -0,0 +1,138 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2013 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef COMPONENT_ASSET_H +#include "ComponentAsset.h" +#endif + +#ifndef _ASSET_MANAGER_H_ +#include "assets/assetManager.h" +#endif + +#ifndef _CONSOLETYPES_H_ +#include "console/consoleTypes.h" +#endif + +#ifndef _TAML_ +#include "persistence/taml/taml.h" +#endif + +#ifndef _ASSET_PTR_H_ +#include "assets/assetPtr.h" +#endif + +// Debug Profiling. +#include "platform/profiler.h" + +//----------------------------------------------------------------------------- + +IMPLEMENT_CONOBJECT(ComponentAsset); + +ConsoleType(ComponentAssetPtr, TypeComponentAssetPtr, ComponentAsset, ASSET_ID_FIELD_PREFIX) + +//----------------------------------------------------------------------------- + +ConsoleGetType(TypeComponentAssetPtr) +{ + // Fetch asset Id. + return (*((AssetPtr*)dptr)).getAssetId(); +} + +//----------------------------------------------------------------------------- + +ConsoleSetType(TypeComponentAssetPtr) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + const char* pFieldValue = argv[0]; + + // Fetch asset pointer. + AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); + + // Is the asset pointer the correct type? + if (pAssetPtr == NULL) + { + // No, so fail. + //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); + + return; + } + + // Warn. + Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- + +ComponentAsset::ComponentAsset() : + mAcquireReferenceCount(0), + mpOwningAssetManager(NULL), + mAssetInitialized(false) +{ + // Generate an asset definition. + mpAssetDefinition = new AssetDefinition(); + + mComponentName = StringTable->lookup(""); + mComponentClass = StringTable->lookup(""); + mFriendlyName = StringTable->lookup(""); + mComponentType = StringTable->lookup(""); + mDescription = StringTable->lookup(""); +} + +//----------------------------------------------------------------------------- + +ComponentAsset::~ComponentAsset() +{ + // If the asset manager does not own the asset then we own the + // asset definition so delete it. + if (!getOwned()) + delete mpAssetDefinition; +} + +//----------------------------------------------------------------------------- + +void ComponentAsset::initPersistFields() +{ + // Call parent. + Parent::initPersistFields(); + + addField("componentName", TypeString, Offset(mComponentName, ComponentAsset), "Unique Name of the component. Defines the namespace of the scripts for the component."); + addField("componentClass", TypeString, Offset(mComponentClass, ComponentAsset), "Class of object this component uses."); + addField("friendlyName", TypeString, Offset(mFriendlyName, ComponentAsset), "The human-readble name for the component."); + addField("componentType", TypeString, Offset(mComponentType, ComponentAsset), "The category of the component for organizing in the editor."); + addField("description", TypeString, Offset(mDescription, ComponentAsset), "Simple description of the component."); +} + +//------------------------------------------------------------------------------ + +void ComponentAsset::copyTo(SimObject* object) +{ + // Call to parent. + Parent::copyTo(object); +} \ No newline at end of file diff --git a/Engine/source/T3D/assets/ComponentAsset.h b/Engine/source/T3D/assets/ComponentAsset.h new file mode 100644 index 000000000..0eaa5a86b --- /dev/null +++ b/Engine/source/T3D/assets/ComponentAsset.h @@ -0,0 +1,77 @@ +#pragma once +//----------------------------------------------------------------------------- +// Copyright (c) 2013 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#ifndef COMPONENT_ASSET_H +#define COMPONENT_ASSET_H + +#ifndef _ASSET_BASE_H_ +#include "assets/assetBase.h" +#endif + +#ifndef _ASSET_DEFINITION_H_ +#include "assets/assetDefinition.h" +#endif + +#ifndef _STRINGUNIT_H_ +#include "string/stringUnit.h" +#endif + +#ifndef _ASSET_FIELD_TYPES_H_ +#include "assets/assetFieldTypes.h" +#endif + +//----------------------------------------------------------------------------- +class ComponentAsset : public AssetBase +{ + typedef AssetBase Parent; + + AssetManager* mpOwningAssetManager; + bool mAssetInitialized; + AssetDefinition* mpAssetDefinition; + U32 mAcquireReferenceCount; + + StringTableEntry mComponentName; + StringTableEntry mComponentClass; + StringTableEntry mFriendlyName; + StringTableEntry mComponentType; + StringTableEntry mDescription; + +public: + ComponentAsset(); + virtual ~ComponentAsset(); + + /// Engine. + static void initPersistFields(); + virtual void copyTo(SimObject* object); + + /// Declare Console Object. + DECLARE_CONOBJECT(ComponentAsset); + +protected: + virtual void initializeAsset(void) {} + virtual void onAssetRefresh(void) {} +}; + +DefineConsoleType(TypeComponentAssetPtr, ComponentAsset) + +#endif // _ASSET_BASE_H_ + From 749ac4efc202a91b4b591cedcde8f4fb6a596d86 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 14 May 2016 15:36:58 -0500 Subject: [PATCH 36/71] Adds the onPostAdd callback for when objects are created via TAML. --- Engine/source/persistence/taml/taml.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Engine/source/persistence/taml/taml.cpp b/Engine/source/persistence/taml/taml.cpp index caea660cd..dfe9266cf 100644 --- a/Engine/source/persistence/taml/taml.cpp +++ b/Engine/source/persistence/taml/taml.cpp @@ -284,6 +284,10 @@ SimObject* Taml::read( const char* pFilename ) // No, so warn. Con::warnf( "Taml::read() - Failed to load an object from the file '%s'.", mFilePathBuffer ); } + else + { + pSimObject->onPostAdd(); + } return pSimObject; } From b04ad52b5d9a960cdc6bed55bd38cf4cf61ec0b3 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 15 May 2016 10:11:46 -0500 Subject: [PATCH 37/71] Ensure that inclusion of any entity/component stuff is properly bracketed with the preprocessor check. --- Engine/source/T3D/gameBase/gameConnection.cpp | 20 +++++++++++++- Engine/source/T3D/gameBase/processList.cpp | 5 +++- .../T3D/gameBase/std/stdGameProcess.cpp | 7 +++++ .../source/gui/controls/guiTreeViewCtrl.cpp | 11 +++++++- Engine/source/gui/editor/guiInspector.cpp | 7 ++++- Engine/source/scene/sceneRenderState.cpp | 5 ++++ Tools/CMake/torque3d.cmake | 26 +++++++++++++++++-- 7 files changed, 75 insertions(+), 6 deletions(-) diff --git a/Engine/source/T3D/gameBase/gameConnection.cpp b/Engine/source/T3D/gameBase/gameConnection.cpp index cb8a5c1af..05ce14151 100644 --- a/Engine/source/T3D/gameBase/gameConnection.cpp +++ b/Engine/source/T3D/gameBase/gameConnection.cpp @@ -38,8 +38,11 @@ #include "T3D/gameBase/gameConnectionEvents.h" #include "console/engineAPI.h" #include "math/mTransform.h" + +#ifdef TORQUE_EXPERIMENTAL_EC #include "T3D/Entity.h" #include "T3D/Components/coreInterfaces.h" +#endif #ifdef TORQUE_HIFI_NET #include "T3D/gameBase/hifi/hifiMoveList.h" @@ -733,6 +736,7 @@ bool GameConnection::getControlCameraFov(F32 * fov) } if (cObj) { +#ifdef TORQUE_EXPERIMENTAL_EC if (Entity* ent = dynamic_cast(cObj)) { if (CameraInterface* camInterface = ent->getComponent()) @@ -744,6 +748,9 @@ bool GameConnection::getControlCameraFov(F32 * fov) { *fov = cObj->getCameraFov(); } +#else + *fov = cObj->getCameraFov(); +#endif return(true); } @@ -763,6 +770,7 @@ bool GameConnection::isValidControlCameraFov(F32 fov) if (cObj) { +#ifdef TORQUE_EXPERIMENTAL_EC if (Entity* ent = dynamic_cast(cObj)) { if (CameraInterface* camInterface = ent->getComponent()) @@ -774,6 +782,9 @@ bool GameConnection::isValidControlCameraFov(F32 fov) { return cObj->isValidCameraFov(fov); } +#else + return cObj->isValidCameraFov(fov); +#endif } return NULL; @@ -791,6 +802,8 @@ bool GameConnection::setControlCameraFov(F32 fov) } if (cObj) { + +#ifdef TORQUE_EXPERIMENTAL_EC F32 newFov = 90.f; if (Entity* ent = dynamic_cast(cObj)) { @@ -806,10 +819,15 @@ bool GameConnection::setControlCameraFov(F32 fov) } else { + // allow shapebase to clamp fov to its datablock values + cObj->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov)); + newFov = cObj->getCameraFov(); + } +#else // allow shapebase to clamp fov to its datablock values cObj->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov)); F32 newFov = cObj->getCameraFov(); - } +#endif // server fov of client has 1degree resolution if( S32(newFov) != S32(mCameraFov) || newFov != fov ) diff --git a/Engine/source/T3D/gameBase/processList.cpp b/Engine/source/T3D/gameBase/processList.cpp index 1f891fe09..e012c4c02 100644 --- a/Engine/source/T3D/gameBase/processList.cpp +++ b/Engine/source/T3D/gameBase/processList.cpp @@ -27,9 +27,10 @@ #include "platform/profiler.h" #include "console/consoleTypes.h" +#ifdef TORQUE_EXPERIMENTAL_EC #include "T3D/Components/coreInterfaces.h" - #include "T3D/Components/Component.h" +#endif //---------------------------------------------------------------------------- ProcessObject::ProcessObject() @@ -271,10 +272,12 @@ void ProcessList::advanceObjects() onTickObject(pobj); } +#ifdef TORQUE_EXPERIMENTAL_EC for (U32 i = 0; i < UpdateInterface::all.size(); i++) { UpdateInterface::all[i]->processTick(); } +#endif mTotalTicks++; diff --git a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp index 51222568c..88d0891d5 100644 --- a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp +++ b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp @@ -36,8 +36,11 @@ #include "T3D/gameBase/gameConnection.h" #include "T3D/gameBase/std/stdMoveList.h" #include "T3D/fx/cameraFXMgr.h" + +#ifdef TORQUE_EXPERIMENTAL_EC #include "T3D/Components/coreInterfaces.h" #include "T3D/Components/Component.h" +#endif MODULE_BEGIN( ProcessList ) @@ -134,6 +137,7 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) obj = obj->mProcessLink.next; } +#ifdef TORQUE_EXPERIMENTAL_EC for (U32 i = 0; i < UpdateInterface::all.size(); i++) { Component *comp = dynamic_cast(UpdateInterface::all[i]); @@ -143,6 +147,7 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) UpdateInterface::all[i]->interpolateTick(mLastDelta); } +#endif // Inform objects of total elapsed delta so they can advance // client side animations. @@ -158,6 +163,7 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) obj = obj->mProcessLink.next; } +#ifdef TORQUE_EXPERIMENTAL_EC for (U32 i = 0; i < UpdateInterface::all.size(); i++) { Component *comp = dynamic_cast(UpdateInterface::all[i]); @@ -170,6 +176,7 @@ bool StdClientProcessList::advanceTime( SimTime timeDelta ) UpdateInterface::all[i]->advanceTime(dt); } +#endif return ret; } diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index c243ce6eb..1e3dfa712 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -36,7 +36,9 @@ #include "gui/editor/editorFunctions.h" #endif #include "console/engineAPI.h" +#ifdef TORQUE_EXPERIMENTAL_EC #include "T3D/Entity.h" +#endif IMPLEMENT_CONOBJECT(GuiTreeViewCtrl); @@ -645,6 +647,7 @@ void GuiTreeViewCtrl::Item::getTooltipText(U32 bufLen, char *buf) bool GuiTreeViewCtrl::Item::isParent() const { +#ifdef TORQUE_EXPERIMENTAL_EC //We might have a special case with entities //So if our entity either has children, or has some component with the EditorInspect interface, we return true if (mInspectorInfo.mObject) @@ -656,6 +659,7 @@ bool GuiTreeViewCtrl::Item::isParent() const return true; } } +#endif if(mState.test(VirtualParent)) { @@ -3786,6 +3790,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) ) onVirtualParentExpand(item); +#ifdef TORQUE_EXPERIMENTAL_EC //Slightly hacky, but I'm not sure of a better setup until we get major update to the editors //We check if our object is an entity, and if it is, we call a 'onInspect' function. //This function is pretty much a special notifier to the entity so if it has any behaviors that do special @@ -3802,6 +3807,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) e->onEndInspect(); } } +#endif mFlags.set( RebuildVisible ); scrollVisible(item); @@ -4539,10 +4545,12 @@ bool GuiTreeViewCtrl::objectSearch( const SimObject *object, Item **item ) if ( !pItem ) continue; +#ifdef TORQUE_EXPERIMENTAL_EC //A bit hackish, but we make a special exception here for items that are named 'Components', as they're merely //virtual parents to act as a container to an Entity's components if (pItem->mScriptInfo.mText == StringTable->insert("Components")) continue; +#endif SimObject *pObj = pItem->getObject(); @@ -4607,10 +4615,11 @@ bool GuiTreeViewCtrl::onVirtualParentBuild(Item *item, bool bForceFullUpdate) // Go through our items and purge those that have disappeared from // the set. - +#ifdef TORQUE_EXPERIMENTAL_EC //Entities will be a special case here, if we're an entity, skip this step if (dynamic_cast(srcObj)) return true; +#endif for( Item* ptr = item->mChild; ptr != NULL; ) { diff --git a/Engine/source/gui/editor/guiInspector.cpp b/Engine/source/gui/editor/guiInspector.cpp index 79905ea97..811441e2d 100644 --- a/Engine/source/gui/editor/guiInspector.cpp +++ b/Engine/source/gui/editor/guiInspector.cpp @@ -28,8 +28,11 @@ #include "gui/editor/inspector/dynamicGroup.h" #include "gui/containers/guiScrollCtrl.h" #include "gui/editor/inspector/customField.h" + +#ifdef TORQUE_EXPERIMENTAL_EC #include "gui/editor/inspector/entityGroup.h" #include "gui/editor/inspector/mountingGroup.h" +#endif IMPLEMENT_CONOBJECT(GuiInspector); @@ -585,7 +588,8 @@ void GuiInspector::refresh() mGroups.push_back(general); addObject(general); - //Behavior inspector group +#ifdef TORQUE_EXPERIMENTAL_EC + //Entity inspector group if (mTargets.first()->getClassRep()->isSubclassOf("Entity")) { GuiInspectorEntityGroup *components = new GuiInspectorEntityGroup("Components", this); @@ -605,6 +609,7 @@ void GuiInspector::refresh() addObject(mounting); } } +#endif // Create the inspector groups for static fields. diff --git a/Engine/source/scene/sceneRenderState.cpp b/Engine/source/scene/sceneRenderState.cpp index 3d8db7c26..5d05e809d 100644 --- a/Engine/source/scene/sceneRenderState.cpp +++ b/Engine/source/scene/sceneRenderState.cpp @@ -26,8 +26,10 @@ #include "renderInstance/renderPassManager.h" #include "math/util/matrixSet.h" +#ifdef TORQUE_EXPERIMENTAL_EC #include "T3D/Components/render/renderComponentInterface.h" #include "T3D/Components/Component.h" +#endif //----------------------------------------------------------------------------- @@ -106,6 +108,7 @@ void SceneRenderState::renderObjects( SceneObject** objects, U32 numObjects ) object->prepRenderImage( this ); } +#ifdef TORQUE_EXPERIMENTAL_EC U32 interfaceCount = RenderComponentInterface::all.size(); for (U32 i = 0; i < RenderComponentInterface::all.size(); i++) { @@ -116,6 +119,8 @@ void SceneRenderState::renderObjects( SceneObject** objects, U32 numObjects ) RenderComponentInterface::all[i]->prepRenderImage(this); } } +#endif + PROFILE_END(); // Render what the objects have batched. diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index b9972e467..c8c017583 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -86,6 +86,9 @@ if(WIN32) option(TORQUE_D3D11 "Allow Direct3D 11 render" OFF) endif() +option(TORQUE_EXPERIMENTAL_EC "Experimental Entity/Component systems" OFF) +mark_as_advanced(TORQUE_EXPERIMENTAL_EC) + ############################################################################### # options ############################################################################### @@ -173,8 +176,6 @@ addPathRec("${srcDir}/app") addPath("${srcDir}/sfx/media") addPath("${srcDir}/sfx/null") addPath("${srcDir}/sfx") -addPath("${srcDir}/component") -addPath("${srcDir}/component/interfaces") addPath("${srcDir}/console") addPath("${srcDir}/core") addPath("${srcDir}/core/stream") @@ -254,7 +255,13 @@ addPath("${srcDir}/ts/arch") addPath("${srcDir}/physics") addPath("${srcDir}/gui/3d") addPath("${srcDir}/postFx") + +if(NOT TORQUE_EXPERIMENTAL_EC) + set(BLACKLIST "Entity.cpp;Entity.h" ) +endif() addPath("${srcDir}/T3D") +set(BLACKLIST "" ) + addPath("${srcDir}/T3D/examples") addPath("${srcDir}/T3D/fps") addPath("${srcDir}/T3D/fx") @@ -264,6 +271,17 @@ addPath("${srcDir}/T3D/decal") addPath("${srcDir}/T3D/sfx") addPath("${srcDir}/T3D/gameBase") addPath("${srcDir}/T3D/turret") + +if( TORQUE_EXPERIMENTAL_EC ) + addPath("${srcDir}/T3D/components/") + addPath("${srcDir}/T3D/components/animation") + addPath("${srcDir}/T3D/components/camera") + addPath("${srcDir}/T3D/components/collision") + addPath("${srcDir}/T3D/components/game") + addPath("${srcDir}/T3D/components/physics") + addPath("${srcDir}/T3D/components/render") +endif() + addPath("${srcDir}/main/") addPath("${srcDir}/assets") addPath("${srcDir}/module") @@ -341,7 +359,11 @@ if(TORQUE_TOOLS) addPath("${srcDir}/environment/editors") addPath("${srcDir}/forest/editor") addPath("${srcDir}/gui/editor") + if(NOT TORQUE_EXPERIMENTAL_EC) + set(BLACKLIST "entityGroup.cpp;entityGroup.h;mountingGroup.cpp;mountingGroup.h" ) + endif() addPath("${srcDir}/gui/editor/inspector") + set(BLACKLIST "" ) endif() if(TORQUE_HIFI) From 7bf49f0670f598432bed3c7016ca998d1d76f3ec Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 15 May 2016 10:12:24 -0500 Subject: [PATCH 38/71] Adds a GameObject asset type, to make tracking and management of GameObjects significantly easier. --- Engine/source/T3D/assets/GameObjectAsset.cpp | 134 +++++++++++++++++++ Engine/source/T3D/assets/GameObjectAsset.h | 75 +++++++++++ 2 files changed, 209 insertions(+) create mode 100644 Engine/source/T3D/assets/GameObjectAsset.cpp create mode 100644 Engine/source/T3D/assets/GameObjectAsset.h diff --git a/Engine/source/T3D/assets/GameObjectAsset.cpp b/Engine/source/T3D/assets/GameObjectAsset.cpp new file mode 100644 index 000000000..07cbb2819 --- /dev/null +++ b/Engine/source/T3D/assets/GameObjectAsset.cpp @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2013 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef GAME_OBJECT_ASSET_H +#include "GameObjectAsset.h" +#endif + +#ifndef _ASSET_MANAGER_H_ +#include "assets/assetManager.h" +#endif + +#ifndef _CONSOLETYPES_H_ +#include "console/consoleTypes.h" +#endif + +#ifndef _TAML_ +#include "persistence/taml/taml.h" +#endif + +#ifndef _ASSET_PTR_H_ +#include "assets/assetPtr.h" +#endif + +// Debug Profiling. +#include "platform/profiler.h" + +//----------------------------------------------------------------------------- + +IMPLEMENT_CONOBJECT(GameObjectAsset); + +ConsoleType(GameObjectAssetPtr, TypeGameObjectAssetPtr, GameObjectAsset, ASSET_ID_FIELD_PREFIX) + +//----------------------------------------------------------------------------- + +ConsoleGetType(TypeGameObjectAssetPtr) +{ + // Fetch asset Id. + return (*((AssetPtr*)dptr)).getAssetId(); +} + +//----------------------------------------------------------------------------- + +ConsoleSetType(TypeGameObjectAssetPtr) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + const char* pFieldValue = argv[0]; + + // Fetch asset pointer. + AssetPtr* pAssetPtr = dynamic_cast*>((AssetPtrBase*)(dptr)); + + // Is the asset pointer the correct type? + if (pAssetPtr == NULL) + { + // No, so fail. + //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue); + return; + } + + // Set asset. + pAssetPtr->setAssetId(pFieldValue); + + return; + } + + // Warn. + Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- + +GameObjectAsset::GameObjectAsset() : + mAcquireReferenceCount(0), + mpOwningAssetManager(NULL), + mAssetInitialized(false) +{ + // Generate an asset definition. + mpAssetDefinition = new AssetDefinition(); + + mGameObjectName = StringTable->lookup(""); + mScriptFilePath = StringTable->lookup(""); + mTAMLFilePath = StringTable->lookup(""); +} + +//----------------------------------------------------------------------------- + +GameObjectAsset::~GameObjectAsset() +{ + // If the asset manager does not own the asset then we own the + // asset definition so delete it. + if (!getOwned()) + delete mpAssetDefinition; +} + +//----------------------------------------------------------------------------- + +void GameObjectAsset::initPersistFields() +{ + // Call parent. + Parent::initPersistFields(); + + addField("gameObjectName", TypeString, Offset(mGameObjectName, GameObjectAsset), "Name of the game object. Defines the created object's class."); + addField("scriptFilePath", TypeString, Offset(mScriptFilePath, GameObjectAsset), "Path to the script file for the GameObject's script code."); + addField("TAMLFilePath", TypeString, Offset(mTAMLFilePath, GameObjectAsset), "Path to the taml file for the GameObject's heirarchy."); +} + +//------------------------------------------------------------------------------ + +void GameObjectAsset::copyTo(SimObject* object) +{ + // Call to parent. + Parent::copyTo(object); +} \ No newline at end of file diff --git a/Engine/source/T3D/assets/GameObjectAsset.h b/Engine/source/T3D/assets/GameObjectAsset.h new file mode 100644 index 000000000..82230cd5c --- /dev/null +++ b/Engine/source/T3D/assets/GameObjectAsset.h @@ -0,0 +1,75 @@ +#pragma once +//----------------------------------------------------------------------------- +// Copyright (c) 2013 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#ifndef GAME_OBJECT_ASSET_H +#define GAME_OBJECT_ASSET_H + +#ifndef _ASSET_BASE_H_ +#include "assets/assetBase.h" +#endif + +#ifndef _ASSET_DEFINITION_H_ +#include "assets/assetDefinition.h" +#endif + +#ifndef _STRINGUNIT_H_ +#include "string/stringUnit.h" +#endif + +#ifndef _ASSET_FIELD_TYPES_H_ +#include "assets/assetFieldTypes.h" +#endif + +//----------------------------------------------------------------------------- +class GameObjectAsset : public AssetBase +{ + typedef AssetBase Parent; + + AssetManager* mpOwningAssetManager; + bool mAssetInitialized; + AssetDefinition* mpAssetDefinition; + U32 mAcquireReferenceCount; + + StringTableEntry mGameObjectName; + StringTableEntry mScriptFilePath; + StringTableEntry mTAMLFilePath; + +public: + GameObjectAsset(); + virtual ~GameObjectAsset(); + + /// Engine. + static void initPersistFields(); + virtual void copyTo(SimObject* object); + + /// Declare Console Object. + DECLARE_CONOBJECT(GameObjectAsset); + +protected: + virtual void initializeAsset(void) {} + virtual void onAssetRefresh(void) {} +}; + +DefineConsoleType(TypeGameObjectAssetPtr, GameObjectAsset) + +#endif // _ASSET_BASE_H_ + From 6fe0b1789d700eaaa368f2d4f0a81703c81472c6 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 15 May 2016 16:24:47 -0500 Subject: [PATCH 39/71] Adds some example components, game objects and the tools and scripts to utilize them. --- Templates/Full/game/art/art.module.taml | 13 + .../shapes/actors/Soldier/soldier.asset.taml | 3 + Templates/Full/game/main.cs | 1 + .../Full/game/scripts/scripts.module.taml | 13 + .../components/animationComponent.asset.taml | 7 + .../cameraOrbiterComponent.asset.taml | 7 + .../components/collisionComponent.asset.taml | 7 + .../server/components/game/camera.asset.taml | 7 + .../scripts/server/components/game/camera.cs | 198 ++++++++++++++ .../components/game/controlObject.asset.taml | 7 + .../server/components/game/controlObject.cs | 91 +++++++ .../components/game/itemRotate.asset.taml | 7 + .../server/components/game/itemRotate.cs | 49 ++++ .../components/game/playerSpawner.asset.taml | 7 + .../server/components/game/playerSpawner.cs | 70 +++++ .../components/input/fpsControls.asset.taml | 7 + .../server/components/input/fpsControls.cs | 249 +++++++++++++++++ .../server/components/input/inputManager.cs | 82 ++++++ .../components/meshComponent.asset.taml | 7 + .../playerControllerComponent.asset.taml | 7 + .../stateMachineComponent.asset.taml | 7 + .../Full/game/scripts/server/gameCore.cs | 25 ++ .../server/gameObjects/GameObjectList.xml | 28 ++ .../server/gameObjects/GameObjectManager.cs | 75 ++++++ .../ThirdPersonPlayerObject.asset.taml | 5 + .../gameObjects/ThirdPersonPlayerObject.cs | 253 ++++++++++++++++++ .../gameObjects/ThirdPersonPlayerObject.taml | 99 +++++++ .../Full/game/scripts/server/scriptExec.cs | 20 ++ .../gui/superToolTipDlg.ed.gui | 45 ++++ .../Full/game/tools/componentEditor/main.cs | 28 ++ .../scripts/SuperToolTipDlg.ed.cs | 155 +++++++++++ .../scripts/componentEditor.ed.cs | 233 ++++++++++++++++ 32 files changed, 1812 insertions(+) create mode 100644 Templates/Full/game/art/art.module.taml create mode 100644 Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml create mode 100644 Templates/Full/game/scripts/scripts.module.taml create mode 100644 Templates/Full/game/scripts/server/components/animationComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/collisionComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/game/camera.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/game/camera.cs create mode 100644 Templates/Full/game/scripts/server/components/game/controlObject.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/game/controlObject.cs create mode 100644 Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/game/itemRotate.cs create mode 100644 Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/game/playerSpawner.cs create mode 100644 Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/input/fpsControls.cs create mode 100644 Templates/Full/game/scripts/server/components/input/inputManager.cs create mode 100644 Templates/Full/game/scripts/server/components/meshComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml create mode 100644 Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml create mode 100644 Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs create mode 100644 Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml create mode 100644 Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs create mode 100644 Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml create mode 100644 Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui create mode 100644 Templates/Full/game/tools/componentEditor/main.cs create mode 100644 Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs create mode 100644 Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs diff --git a/Templates/Full/game/art/art.module.taml b/Templates/Full/game/art/art.module.taml new file mode 100644 index 000000000..73855c09e --- /dev/null +++ b/Templates/Full/game/art/art.module.taml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml b/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml new file mode 100644 index 000000000..4ba732205 --- /dev/null +++ b/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/Full/game/main.cs b/Templates/Full/game/main.cs index 955f5aa6c..2a261201d 100644 --- a/Templates/Full/game/main.cs +++ b/Templates/Full/game/main.cs @@ -254,6 +254,7 @@ else { //You can also explicitly decalre some modules here to be loaded by default if they are part of your game //Ex: ModuleDatabase.LoadExplicit( "AppCore" ); + ModuleDatabase.LoadGroup( "Game" ); if( !$isDedicated ) { diff --git a/Templates/Full/game/scripts/scripts.module.taml b/Templates/Full/game/scripts/scripts.module.taml new file mode 100644 index 000000000..e1a6b57be --- /dev/null +++ b/Templates/Full/game/scripts/scripts.module.taml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/animationComponent.asset.taml b/Templates/Full/game/scripts/server/components/animationComponent.asset.taml new file mode 100644 index 000000000..62f15cdf9 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/animationComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml b/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml new file mode 100644 index 000000000..e03081564 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml b/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml new file mode 100644 index 000000000..9796df18d --- /dev/null +++ b/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/game/camera.asset.taml b/Templates/Full/game/scripts/server/components/game/camera.asset.taml new file mode 100644 index 000000000..5d00d1170 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/camera.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/game/camera.cs b/Templates/Full/game/scripts/server/components/game/camera.cs new file mode 100644 index 000000000..e0b6bc41e --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/camera.cs @@ -0,0 +1,198 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +function CameraComponent::onAdd(%this) +{ + Parent::onBehaviorAdd(%this); + + %this.addComponentField(clientOwner, "The client that views this camera", "int", "1", ""); + + %test = %this.clientOwner; + + %barf = ClientGroup.getCount(); + + %clientID = %this.getClientID(); + if(%clientID && !isObject(%clientID.camera)) + { + %this.scopeToClient(%clientID); + %this.setDirty(); + + %clientID.setCameraObject(%this.owner); + %clientID.setControlCameraFov(%this.FOV); + + %clientID.camera = %this.owner; + } + + %res = $pref::Video::mode; + %derp = 0; +} + +function CameraComponent::onRemove(%this) +{ + %clientID = %this.getClientID(); + if(%clientID) + %clientID.clearCameraObject(); +} + +function CameraComponent::onInspectorUpdate(%this) +{ + //if(%this.clientOwner) + //%this.clientOwner.setCameraObject(%this.owner); +} + +function CameraComponent::getClientID(%this) +{ + return ClientGroup.getObject(%this.clientOwner-1); +} + +function CameraComponent::isClientCamera(%this, %client) +{ + %clientID = ClientGroup.getObject(%this.clientOwner-1); + + if(%client.getID() == %clientID) + return true; + else + return false; +} + +function CameraComponent::onClientConnect(%this, %client) +{ + //if(%this.isClientCamera(%client) && !isObject(%client.camera)) + //{ + %this.scopeToClient(%client); + %this.setDirty(); + + %client.setCameraObject(%this.owner); + %client.setControlCameraFov(%this.FOV); + + %client.camera = %this.owner; + //} + //else + //{ + // echo("CONNECTED CLIENT IS NOT CAMERA OWNER!"); + //} +} + +function CameraComponent::onClientDisconnect(%this, %client) +{ + Parent::onClientDisconnect(%this, %client); + + if(isClientCamera(%client)){ + %this.clearScopeToClient(%client); + %client.clearCameraObject(); + } +} + +//move to the editor later +GlobalActionMap.bind("keyboard", "alt c", "toggleEditorCam"); + +function switchCamera(%client, %newCamEntity) +{ + if(!isObject(%client) || !isObject(%newCamEntity)) + return error("SwitchCamera: No client or target camera!"); + + %cam = %newCamEntity.getComponent(CameraComponent); + + if(!isObject(%cam)) + return error("SwitchCamera: Target camera doesn't have a camera behavior!"); + + //TODO: Cleanup clientOwner for previous camera! + if(%cam.clientOwner == 0 || %cam.clientOwner $= "") + %cam.clientOwner = 0; + + %cam.scopeToClient(%client); + %cam.setDirty(); + + %client.setCameraObject(%newCamEntity); + %client.setControlCameraFov(%cam.FOV); + + %client.camera = %newCamEntity; +} + +function buildEditorCamera() +{ + if(isObject("EditorCamera")) + return EditorCamera; + + %camObj = SGOManager.spawn("SpectatorObject", false); + + %camObj.name = "EditorCamera"; + + %client = ClientGroup.getObject(0); + + %camObj.getComponent(SpectatorControls).setupControls(%client); + + MissionCleanup.add(%camObj); + + return %camObj; +} + +//TODO: Move this somewhere else! +function toggleEditorCam(%val) +{ + if(!%val) + return; + + %client = ClientGroup.getObject(0); + + if(!isObject(%client.camera)) + return error("ToggleEditorCam: no existing camera!"); + + %editorCam = buildEditorCamera(); + + //if this is our first switch, just go to the editor camera + if(%client.lastCam $= "" || %client.camera.getId() != %editorCam.getId()) + { + if(%client.lastCam $= "") + { + //set up the position + %editorCam.position = %client.camera.position; + %editorCam.rotation = %client.camera.rotation; + } + + %client.lastCam = %client.camera; + %client.lastController = %client.getControlObject(); + switchCamera(%client, %editorCam); + switchControlObject(%client, %editorCam); + } + else + { + switchCamera(%client, %client.lastCam); + switchControlObject(%client, %client.lastController); + %client.lastCam = %editorCam; + %client.lastController = %editorCam; + } +} + +function serverCmdSetClientAspectRatio(%client, %width, %height) +{ + echo("Client: " @ %client SPC "changing screen res to: " @ %width SPC %height); + %client.screenExtent = %width SPC %height; + %cam = %client.getCameraObject(); + + if(!isObject(%cam)) + return; + + %cameraComp = %cam.getComponent(CameraComponent); + + %cameraComp.ScreenAspect = %width SPC %height; +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml b/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml new file mode 100644 index 000000000..2c9d48e1c --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/game/controlObject.cs b/Templates/Full/game/scripts/server/components/game/controlObject.cs new file mode 100644 index 000000000..5b67f394b --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/controlObject.cs @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +//registerComponent("ControlObjectComponent", "Component", "Control Object", "Game", false, "Allows the behavior owner to operate as a camera."); + +function ControlObjectComponent::onAdd(%this) +{ + Parent::onBehaviorAdd(%this); + + %this.addComponentField(clientOwner, "The shape to use for rendering", "int", "1", ""); + + %clientID = %this.getClientID(); + + if(%clientID && !isObject(%clientID.getControlObject())) + %clientID.setControlObject(%this.owner); +} + +function ControlObjectComponent::onRemove(%this) +{ + %clientID = %this.getClientID(); + + if(%clientID) + %clientID.setControlObject(0); +} + +function ControlObjectComponent::onClientConnect(%this, %client) +{ + if(%this.isControlClient(%client) && !isObject(%client.getControlObject())) + %client.setControlObject(%this.owner); +} + +function ControlObjectComponent::onClientDisconnect(%this, %client) +{ + if(%this.isControlClient(%client)) + %client.setControlObject(0); +} + +function ControlObjectComponent::getClientID(%this) +{ + return ClientGroup.getObject(%this.clientOwner-1); +} + +function ControlObjectComponent::isControlClient(%this, %client) +{ + %clientID = ClientGroup.getObject(%this.clientOwner-1); + + if(%client.getID() == %clientID) + return true; + else + return false; +} + +function ControlObjectComponent::onInspectorUpdate(%this, %field) +{ + %clientID = %this.getClientID(); + + if(%clientID && !isObject(%clientID.getControlObject())) + %clientID.setControlObject(%this.owner); +} + +function switchControlObject(%client, %newControlEntity) +{ + if(!isObject(%client) || !isObject(%newControlEntity)) + return error("SwitchControlObject: No client or target controller!"); + + %control = %newControlEntity.getComponent(ControlObjectComponent); + + if(!isObject(%control)) + return error("SwitchControlObject: Target controller has no conrol object behavior!"); + + %client.setControlObject(%newControlEntity); +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml b/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml new file mode 100644 index 000000000..8068b49f3 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/game/itemRotate.cs b/Templates/Full/game/scripts/server/components/game/itemRotate.cs new file mode 100644 index 000000000..259b44111 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/itemRotate.cs @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +//registerComponent("ItemRotationComponent", "Component", "Item Rotation", "Game", false, "Rotates the entity around the z axis, like an item pickup."); + +function ItemRotationComponent::onAdd(%this) +{ + %this.addComponentField(rotationsPerMinute, "Number of rotations per minute", "float", "5", ""); + %this.addComponentField(forward, "Rotate forward or backwards", "bool", "1", ""); + %this.addComponentField(horizontal, "Rotate horizontal or verticle, true for horizontal", "bool", "1", ""); +} + +function ItemRotateBehavior::Update(%this) +{ + %tickRate = 0.032; + + //Rotations per second is calculated based on a standard update tick being 32ms. So we scale by the tick speed, then add that to our rotation to + //get a nice rotation speed. + if(%this.horizontal) + { + if(%this.forward) + %this.owner.rotation.z += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; + else + %this.owner.rotation.z -= ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; + } + else + { + %this.owner.rotation.x += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; + } +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml b/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml new file mode 100644 index 000000000..d181a86b4 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/game/playerSpawner.cs b/Templates/Full/game/scripts/server/components/game/playerSpawner.cs new file mode 100644 index 000000000..fb6507d08 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/game/playerSpawner.cs @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +//registerComponent("PlayerSpawner", "Component", +// "Player Spawner", "Game", false, "When a client connects, it spawns a player object for them and attaches them to it"); + +function PlayerSpawner::onAdd(%this) +{ + %this.clientCount = 1; + %this.friendlyName = "Player Spawner"; + %this.componentType = "Spawner"; + + %this.addComponentField("GameObjectName", "The name of the game object we spawn for the players", string, "PlayerObject"); +} + +function PlayerSpawner::onClientConnect(%this, %client) +{ + %playerObj = SGOManager.spawn(%this.GameObjectName); + + if(!isObject(%playerObj)) + return; + + %playerObj.position = %this.owner.position; + + MissionCleanup.add(%playerObj); + + for(%b = 0; %b < %playerObj.getComponentCount(); %b++) + { + %comp = %playerObj.getComponentByIndex(%b); + + if(%comp.isMethod("onClientConnect")) + %comp.onClientConnect(%client); + } + + switchControlObject(%client, %playerObj); + switchCamera(%client, %playerObj); + + //%playerObj.getComponent(FPSControls).setupControls(%client); + + %this.clientCount++; +} + +function PlayerSpawner::onClientDisConnect(%this, %client) +{ + +} + +function PlayerSpawner::getClientID(%this) +{ + return ClientGroup.getObject(%this.clientOwner-1); +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml b/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml new file mode 100644 index 000000000..34f31f181 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/input/fpsControls.cs b/Templates/Full/game/scripts/server/components/input/fpsControls.cs new file mode 100644 index 000000000..3e7f571bd --- /dev/null +++ b/Templates/Full/game/scripts/server/components/input/fpsControls.cs @@ -0,0 +1,249 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +//registerComponent("FPSControls", "Component", "FPS Controls", "Input", false, "First Person Shooter-type controls"); + +function FPSControls::onAdd(%this) +{ + Parent::onBehaviorAdd(%this); + + // + %this.beginGroup("Keys"); + %this.addComponentField(forwardKey, "Key to bind to vertical thrust", keybind, "keyboard w"); + %this.addComponentField(backKey, "Key to bind to vertical thrust", keybind, "keyboard s"); + %this.addComponentField(leftKey, "Key to bind to horizontal thrust", keybind, "keyboard a"); + %this.addComponentField(rightKey, "Key to bind to horizontal thrust", keybind, "keyboard d"); + + %this.addComponentField(jump, "Key to bind to horizontal thrust", keybind, "keyboard space"); + %this.endGroup(); + + %this.beginGroup("Mouse"); + %this.addComponentField(pitchAxis, "Key to bind to horizontal thrust", keybind, "mouse yaxis"); + %this.addComponentField(yawAxis, "Key to bind to horizontal thrust", keybind, "mouse xaxis"); + %this.endGroup(); + + %this.addComponentField(moveSpeed, "Horizontal thrust force", float, 300.0); + %this.addComponentField(jumpStrength, "Vertical thrust force", float, 3.0); + // + + %control = %this.owner.getComponent( ControlObjectComponent ); + if(!%control) + return echo("SPECTATOR CONTROLS: No Control Object behavior!"); + + //%this.Physics = %this.owner.getComponent( PlayerPhysicsComponent ); + + //%this.Animation = %this.owner.getComponent( AnimationComponent ); + + //%this.Camera = %this.owner.getComponent( MountedCameraComponent ); + + //%this.Animation.playThread(0, "look"); + + %this.setupControls(%control.getClientID()); +} + +function FPSControls::onRemove(%this) +{ + Parent::onBehaviorRemove(%this); + + commandToClient(%control.clientOwnerID, 'removeInput', %this.forwardKey); + commandToClient(%control.clientOwnerID, 'removeInput', %this.backKey); + commandToClient(%control.clientOwnerID, 'removeInput', %this.leftKey); + commandToClient(%control.clientOwnerID, 'removeInput', %this.rightKey); + + commandToClient(%control.clientOwnerID, 'removeInput', %this.pitchAxis); + commandToClient(%control.clientOwnerID, 'removeInput', %this.yawAxis); +} + +function FPSControls::onBehaviorFieldUpdate(%this, %field) +{ + %controller = %this.owner.getBehavior( ControlObjectBehavior ); + commandToClient(%controller.clientOwnerID, 'updateInput', %this.getFieldValue(%field), %field); +} + +function FPSControls::onClientConnect(%this, %client) +{ + %this.setupControls(%client); +} + + +function FPSControls::setupControls(%this, %client) +{ + %control = %this.owner.getComponent( ControlObjectComponent ); + if(!%control.isControlClient(%client)) + { + echo("FPS CONTROLS: Client Did Not Match"); + return; + } + + %inputCommand = "FPSControls"; + + %test = %this.forwardKey; + + /*SetInput(%client, %this.forwardKey.x, %this.forwardKey.y, %inputCommand@"_forwardKey"); + SetInput(%client, %this.backKey.x, %this.backKey.y, %inputCommand@"_backKey"); + SetInput(%client, %this.leftKey.x, %this.leftKey.y, %inputCommand@"_leftKey"); + SetInput(%client, %this.rightKey.x, %this.rightKey.y, %inputCommand@"_rightKey"); + + SetInput(%client, %this.jump.x, %this.jump.y, %inputCommand@"_jump"); + + SetInput(%client, %this.pitchAxis.x, %this.pitchAxis.y, %inputCommand@"_pitchAxis"); + SetInput(%client, %this.yawAxis.x, %this.yawAxis.y, %inputCommand@"_yawAxis");*/ + + SetInput(%client, "keyboard", "w", %inputCommand@"_forwardKey"); + SetInput(%client, "keyboard", "s", %inputCommand@"_backKey"); + SetInput(%client, "keyboard", "a", %inputCommand@"_leftKey"); + SetInput(%client, "keyboard", "d", %inputCommand@"_rightKey"); + + SetInput(%client, "keyboard", "space", %inputCommand@"_jump"); + + SetInput(%client, "mouse", "yaxis", %inputCommand@"_pitchAxis"); + SetInput(%client, "mouse", "xaxis", %inputCommand@"_yawAxis"); + + SetInput(%client, "keyboard", "f", %inputCommand@"_flashlight"); + +} + +function FPSControls::onMoveTrigger(%this, %triggerID) +{ + //check if our jump trigger was pressed! + if(%triggerID == 2) + { + %this.owner.applyImpulse("0 0 0", "0 0 " @ %this.jumpStrength); + } +} + +function FPSControls::Update(%this) +{ + return; + + %moveVector = %this.owner.getMoveVector(); + %moveRotation = %this.owner.getMoveRotation(); + + %this.Physics.moveVector = "0 0 0"; + + if(%moveVector.x != 0) + { + %fv = VectorNormalize(%this.owner.getRightVector()); + + %forMove = VectorScale(%fv, (%moveVector.x));// * (%this.moveSpeed * 0.032))); + + //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); + + %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove); + + //if(%forMove > 0) + // %this.Animation.playThread(1, "run"); + } + /*else + { + %fv = VectorNormalize(%this.owner.getRightVector()); + + %forMove = VectorScale(%fv, (%moveVector.x * (%this.moveSpeed * 0.032))); + + if(%forMove <= 0) + %this.Animation.stopThread(1); + + }*/ + + if(%moveVector.y != 0) + { + %fv = VectorNormalize(%this.owner.getForwardVector()); + + %forMove = VectorScale(%fv, (%moveVector.y));// * (%this.moveSpeed * 0.032))); + + //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); + + %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove); + + //if(VectorLen(%this.Physics.velocity) < 2) + // %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); + } + + /*if(%moveVector.z) + { + %fv = VectorNormalize(%this.owner.getUpVector()); + + %forMove = VectorScale(%fv, (%moveVector.z * (%this.moveSpeed * 0.032))); + + %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); + }*/ + + if(%moveRotation.x != 0) + { + %look = mRadToDeg(%moveRotation.x) / 180; + + //%this.Animation.setThreadPos(0, %look); + + %this.owner.getComponent( MountedCameraComponent ).rotationOffset.x += mRadToDeg(%moveRotation.x); + + //%this.Camera.rotationOffset.x += mRadToDeg(%moveRotation.x); + } + // %this.owner.rotation.x += mRadToDeg(%moveRotation.x); + + if(%moveRotation.z != 0) + { + %zrot = mRadToDeg(%moveRotation.z); + %this.owner.getComponent( MountedCameraComponent ).rotationOffset.z += %zrot; + //%this.owner.rotation.z += %zrot; + } +} + +// +function FPSControls_forwardKey(%val) +{ + $mvForwardAction = %val; +} + +function FPSControls_backKey(%val) +{ + $mvBackwardAction = %val; +} + +function FPSControls_leftKey(%val) +{ + $mvLeftAction = %val; +} + +function FPSControls_rightKey(%val) +{ + $mvRightAction = %val; +} + +function FPSControls_yawAxis(%val) +{ + $mvYaw += getMouseAdjustAmount(%val); +} + +function FPSControls_pitchAxis(%val) +{ + $mvPitch += getMouseAdjustAmount(%val); +} + +function FPSControls_jump(%val) +{ + $mvTriggerCount2++; +} + +function FPSControls_flashLight(%val) +{ + $mvTriggerCount3++; +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/input/inputManager.cs b/Templates/Full/game/scripts/server/components/input/inputManager.cs new file mode 100644 index 000000000..c8123d1e3 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/input/inputManager.cs @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +function SetInput(%client, %device, %key, %command, %bindMap, %behav) +{ + commandToClient(%client, 'SetInput', %device, %key, %command, %bindMap, %behav); +} + +function RemoveInput(%client, %device, %key, %command, %bindMap) +{ + commandToClient(%client, 'removeInput', %device, %key, %command, %bindMap); +} + +function clientCmdSetInput(%device, %key, %command, %bindMap, %behav) +{ + //if we're requesting a custom bind map, set that up + if(%bindMap $= "") + %bindMap = moveMap; + + if (!isObject(%bindMap)){ + new ActionMap(moveMap); + moveMap.push(); + } + + //get our local + //%localID = ServerConnection.resolveGhostID(%behav); + + //%tmpl = %localID.getTemplate(); + //%tmpl.insantiateNamespace(%tmpl.getName()); + + //first, check if we have an existing command + %oldBind = %bindMap.getBinding(%command); + if(%oldBind !$= "") + %bindMap.unbind(getField(%oldBind, 0), getField(%oldBind, 1)); + + //now, set the requested bind + %bindMap.bind(%device, %key, %command); +} + +function clientCmdRemoveSpecCtrlInput(%device, %key, %bindMap) +{ + //if we're requesting a custom bind map, set that up + if(%bindMap $= "") + %bindMap = moveMap; + + if (!isObject(%bindMap)) + return; + + %bindMap.unbind(%device, %key); +} + +function clientCmdSetupClientBehavior(%bhvrGstID) +{ + %localID = ServerConnection.resolveGhostID(%bhvrGstID); + %tmpl = %localID.getTemplate(); + %tmpl.insantiateNamespace(%tmpl.getName()); +} + +function getMouseAdjustAmount(%val) +{ + // based on a default camera FOV of 90' + return(%val * ($cameraFov / 90) * 0.01) * $pref::Input::LinkMouseSensitivity; +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/components/meshComponent.asset.taml b/Templates/Full/game/scripts/server/components/meshComponent.asset.taml new file mode 100644 index 000000000..d019cd893 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/meshComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml b/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml new file mode 100644 index 000000000..d5174644b --- /dev/null +++ b/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml b/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml new file mode 100644 index 000000000..a261bb194 --- /dev/null +++ b/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/Full/game/scripts/server/gameCore.cs b/Templates/Full/game/scripts/server/gameCore.cs index abff15c0a..bb7aed714 100644 --- a/Templates/Full/game/scripts/server/gameCore.cs +++ b/Templates/Full/game/scripts/server/gameCore.cs @@ -573,6 +573,31 @@ function GameCore::onClientEnterGame(%game, %client) %client.isAiControlled(), %client.isAdmin, %client.isSuperAdmin); + + %entityIds = parseMissionGroupForIds("Entity", ""); + %entityCount = getWordCount(%entityIds); + + for(%i=0; %i < %entityCount; %i++) + { + %entity = getWord(%entityIds, %i); + + for(%e=0; %e < %entity.getCount(); %e++) + { + %child = %entity.getObject(%e); + if(%child.getCLassName() $= "Entity") + %entityIds = %entityIds SPC %child.getID(); + } + + for(%c=0; %c < %entity.getComponentCount(); %c++) + { + %comp = %entity.getComponentByIndex(%c); + + if(%comp.isMethod("onClientConnect")) + { + %comp.onClientConnect(%client); + } + } + } } function GameCore::onClientLeaveGame(%game, %client) diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml b/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml new file mode 100644 index 000000000..e9cc73c89 --- /dev/null +++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml @@ -0,0 +1,28 @@ + + + + ScriptedTriggerObject + data/EC/scripts/gameObjects/ScriptedTriggerObject.taml + data/EC/scripts/gameObjects/ScriptedTriggerObject.cs + + + PlayerObject + data/EC/scripts/gameObjects/playerObject.taml + data/EC/scripts/gameObjects/playerObject.cs + + + spectatorObject + data/EC/scripts/gameObjects/spectatorObject.taml + data/EC/scripts/gameObjects/spectatorObject.cs + + + ThirdPersonPlayerObject + data/EC/scripts/gameObjects/ThirdPersonPlayerObject.taml + data/EC/scripts/gameObjects/ThirdPersonPlayerObject.cs + + + FirstPersonArms + data/EC/scripts/gameObjects/FirstPersonArms.taml + data/EC/scripts/gameObjects/FirstPersonArms.cs + + diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs new file mode 100644 index 000000000..138bcb8be --- /dev/null +++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs @@ -0,0 +1,75 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +function execGameObjects() +{ + //find all GameObjectAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) + return; //if we didn't find ANY, just exit + + %count = %assetQuery.getCount(); + + for(%i=0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); + + if(isFile(%gameObjectAsset.scriptFilePath)) + exec(%gameObjectAsset.scriptFilePath); + } +} + +function spawnGameObject(%name, %addToMissionGroup) +{ + if(%addToMissionGroup $= "") + %addToMissionGroup = true; + + //find all GameObjectAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) + return; //if we didn't find ANY, just exit + + %count = %assetQuery.getCount(); + + for(%i=0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); + + if(%gameObjectAsset.gameObjectName $= %name) + { + if(isFile(%gameObjectAsset.TAMLFilePath)) + { + %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); + + if(%addToMissionGroup == true) + MissionGroup.add(%newSGOObject); + + return %newSGOObject; + } + } + } + + return 0; +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml new file mode 100644 index 000000000..2d593a50b --- /dev/null +++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml @@ -0,0 +1,5 @@ + diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs new file mode 100644 index 000000000..bc92db12d --- /dev/null +++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs @@ -0,0 +1,253 @@ +function ThirdPersonPlayerObject::onAdd(%this) +{ + %this.turnRate = 0.3; + + %this.phys = %this.getComponent("PlayerControllerComponent"); + %this.collision = %this.getComponent("CollisionComponent"); + %this.cam = %this.getComponent("CameraComponent"); + %this.camArm = %this.getComponent("CameraOrbiterComponent"); + %this.animation = %this.getComponent("AnimationComponent"); + %this.stateMachine = %this.getComponent("StateMachineComponent"); + %this.mesh = %this.getComponent("MeshComponent"); + + %this.stateMachine.forwardVector = 0; + + %this.crouch = false; + + %this.firstPerson = false; + + %this.crouchSpeedMod = 0.5; + + %this.aimOrbitDist = 1.5; + %this.regularOrbitDist = 5; + + %this.regularOrbitMaxPitch = 70; + %this.regularOrbitMinPitch = -10; + + %this.aimedMaxPitch = 90; + %this.aimedMinPitch = -90; + + %this.arms = SGOManager.spawn("FirstPersonArms", true); + + %this.add(arms); + + //%this.mesh.mountObject(%this.arms, "Eye"); +} + +function ThirdPersonPlayerObject::onRemove(%this) +{ + +} + +function ThirdPersonPlayerObject::moveVectorEvent(%this) +{ + %moveVector = %this.getMoveVector(); + + // forward of the camera on the x-z plane + %cameraForward = %this.cam.getForwardVector(); + + %cameraRight = %this.cam.getRightVector(); + + %moveVec = VectorAdd(VectorScale(%cameraRight, %moveVector.x), VectorScale(%cameraForward, %moveVector.y)); + + if(%this.aiming || %this.firstPerson) + { + %forMove = "0 0 0"; + + if(%moveVector.x != 0) + { + %this.phys.inputVelocity.x = %moveVector.x * 10; + } + else + { + %this.phys.inputVelocity.x = 0; + } + + if(%moveVector.y != 0) + { + + %this.phys.inputVelocity.y = %moveVector.y * 10; + } + else + { + %this.phys.inputVelocity.y = 0; + } + } + else + { + if(%moveVec.x == 0 && %moveVec.y == 0) + { + %this.phys.inputVelocity = "0 0 0"; + %this.stateMachine.forwardVector = 0; + } + else + { + %moveVec.z = 0; + + %curForVec = %this.getForwardVector(); + + %newForVec = VectorLerp(%curForVec, %moveVec, %this.turnRate); + + %this.setForwardVector(%newForVec); + + %this.phys.inputVelocity.y = 10; + + %this.stateMachine.forwardVector = 1; + } + } + + if(%this.crouch) + %this.phys.inputVelocity = VectorScale(%this.phys.inputVelocity, %this.crouchSpeedMod); +} + +function ThirdPersonPlayerObject::moveYawEvent(%this) +{ + %moveRotation = %this.getMoveRotation(); + + %camOrb = %this.getComponent("CameraOrbiterComponent"); + + if(%this.aiming || %this.firstPerson) + { + %this.rotation.z += %moveRotation.z * 10; + } + + %camOrb.rotation.z += %moveRotation.z * 10; +} + +function ThirdPersonPlayerObject::movePitchEvent(%this) +{ + %moveRotation = %this.getMoveRotation(); + + %camOrb = %this.getComponent("CameraOrbiterComponent"); + + %camOrb.rotation.x += %moveRotation.x * 10; +} + +function ThirdPersonPlayerObject::moveRollEvent(%this){} + +function ThirdPersonPlayerObject::moveTriggerEvent(%this, %triggerNum, %triggerValue) +{ + if(%triggerNum == 3 && %triggerValue) + { + if(%triggerValue) + { + %this.firstPerson = !%this.firstPerson; + + if(%this.firstPerson) + { + %this.rotation.z = %this.cam.rotationOffset.z; + %this.camArm.orbitDistance = 0; + %this.camArm.maxPitchAngle = %this.aimedMaxPitch; + %this.camArm.minPitchAngle = %this.aimedMinPitch; + + %this.cam.positionOffset = "0 0 0"; + %this.cam.rotationOffset = "0 0 0"; + } + else if(%this.aiming) + { + %this.camArm.orbitDistance = %this.aimOrbitDist; + + %this.camArm.maxPitchAngle = %this.aimedMaxPitch; + %this.camArm.minPitchAngle = %this.aimedMinPitch; + } + else + { + %this.camArm.orbitDistance = %this.regularOrbitDist; + + %this.camArm.maxPitchAngle = %this.regularOrbitMaxPitch; + %this.camArm.minPitchAngle = %this.regularOrbitMinPitch; + } + + commandToClient(localclientConnection, 'SetClientRenderShapeVisibility', + localclientConnection.getGhostID(%this.getComponent("MeshComponent")), !%this.firstPerson); + } + } + else if(%triggerNum == 2 && %triggerValue == true) + { + //get our best collision assuming up is 0 0 1 + %collisionAngle = %this.collision.getBestCollisionAngle("0 0 1"); + + if(%collisionAngle >= 80) + { + %surfaceNormal = %this.collision.getCollisionNormal(0); + %jumpVector = VectorScale(%surfaceNormal, 200); + echo("Jump surface Angle is at: " @ %surfaceNormal); + + %this.phys.applyImpulse(%this.position, %jumpVector); + %this.setForwardVector(%jumpVector); + } + else + %this.phys.applyImpulse(%this.position, "0 0 300"); + } + else if(%triggerNum == 4) + { + %this.crouch = %triggerValue; + } + else if(%triggerNum == 1) + { + %this.aiming = %triggerValue; + + if(%this.aiming) + { + %this.rotation.z = %this.cam.rotationOffset.z; + %this.camArm.orbitDistance = %this.aimOrbitDist; + %this.camArm.maxPitchAngle = %this.aimedMaxPitch; + %this.camArm.minPitchAngle = %this.aimedMinPitch; + } + else + { + %this.camArm.orbitDistance = %this.regularOrbitDist; + %this.camArm.maxPitchAngle = %this.regularOrbitMaxPitch; + %this.camArm.minPitchAngle = %this.regularOrbitMinPitch; + } + } +} + +function ThirdPersonPlayerObject::onCollisionEvent(%this, %colObject, %colNormal, %colPoint, %colMatID, %velocity) +{ + if(!%this.phys.isContacted()) + echo(%this @ " collided with " @ %colObject); +} + +function ThirdPersonPlayerObject::processTick(%this) +{ + %moveVec = %this.getMoveVector(); + %bestFit = ""; + + if(%this.crouch) + { + if(%moveVec.x != 0 || %moveVec.y != 0) + %bestFit = "Crouch_Forward"; + else + %bestFit = "Crouch_Root"; + } + else + { + if(%moveVec.x != 0 || %moveVec.y != 0) + %bestFit = "Run"; + else + %bestFit = "Root"; + } + + if(%this.animation.getThreadAnimation(0) !$= %bestFit) + %this.animation.playThread(0, %bestFit); +} + +//Used for first person mode +function clientCmdSetClientRenderShapeVisibility(%id, %visiblilty) +{ + %localID = ServerConnection.resolveGhostID(%id); + %localID.enabled = %visiblilty; +} + +function serverToClientObject( %serverObject ) +{ + assert( isObject( LocalClientConnection ), "serverToClientObject() - No local client connection found!" ); + assert( isObject( ServerConnection ), "serverToClientObject() - No server connection found!" ); + + %ghostId = LocalClientConnection.getGhostId( %serverObject ); + if ( %ghostId == -1 ) + return 0; + + return ServerConnection.resolveGhostID( %ghostId ); +} \ No newline at end of file diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml new file mode 100644 index 000000000..fcfead0d4 --- /dev/null +++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml @@ -0,0 +1,99 @@ + + + + + + + + + + + diff --git a/Templates/Full/game/scripts/server/scriptExec.cs b/Templates/Full/game/scripts/server/scriptExec.cs index a61204040..d48e268e7 100644 --- a/Templates/Full/game/scripts/server/scriptExec.cs +++ b/Templates/Full/game/scripts/server/scriptExec.cs @@ -58,3 +58,23 @@ exec("./turret.cs"); // Load our gametypes exec("./gameCore.cs"); // This is the 'core' of the gametype functionality. exec("./gameDM.cs"); // Overrides GameCore with DeathMatch functionality. + +//Entity/Component stuff +if(isFile("./components/game/camera.cs")) + exec("./components/game/camera.cs"); +if(isFile("./components/game/controlObject.cs")) + exec("./components/game/controlObject.cs"); +if(isFile("./components/game/itemRotate.cs")) + exec("./components/game/itemRotate.cs"); +if(isFile("./components/game/playerSpawner.cs")) + exec("./components/game/playerSpawner.cs"); +if(isFile("./components/input/fpsControls.cs")) + exec("./components/input/fpsControls.cs"); +if(isFile("./components/input/inputManager.cs")) + exec("./components/input/inputManager.cs"); + +if(isFile("./gameObjects/GameObjectManager.cs")) +{ + exec("./gameObjects/GameObjectManager.cs"); + execGameObjects(); +} \ No newline at end of file diff --git a/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui b/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui new file mode 100644 index 000000000..ef506941a --- /dev/null +++ b/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui @@ -0,0 +1,45 @@ +%guiContent = new GuiControl(SuperTooltipDlg) { + canSaveDynamicFields = "0"; + Profile = "GuiTransparentProfileModeless"; + class = "SuperTooltip"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "0 0"; + Extent = "640 480"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + hovertime = "1000"; + + new GuiControl(SuperTooltipWindow) { + canSaveDynamicFields = "0"; + Profile = "EditorTextEditBoldModeless"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "216 160"; + Extent = "221 134"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + hovertime = "1000"; + internalName = "tooltipWindow"; + + new GuiMLTextCtrl(SuperTooltipMLText) { + canSaveDynamicFields = "0"; + Profile = "EditorMLTextProfileModeless"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "5 5"; + Extent = "210 14"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + hovertime = "1000"; + lineSpacing = "2"; + allowColorChars = "0"; + maxChars = "-1"; + internalName = "tooltipMLText"; + }; + }; +}; + diff --git a/Templates/Full/game/tools/componentEditor/main.cs b/Templates/Full/game/tools/componentEditor/main.cs new file mode 100644 index 000000000..56d74830a --- /dev/null +++ b/Templates/Full/game/tools/componentEditor/main.cs @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +//Scripts +exec("./scripts/componentEditor.ed.cs"); +exec("./scripts/superToolTipDlg.ed.cs"); + +//gui +exec("./gui/superToolTipDlg.ed.gui"); diff --git a/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs b/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs new file mode 100644 index 000000000..7f25bd5e6 --- /dev/null +++ b/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs @@ -0,0 +1,155 @@ +function createSuperTooltipTheme(%name) +{ + %theme = new ScriptObject() + { + class = SuperTooltipTheme; + }; + + %theme.setName(%name); + + return %theme; +} + +function SuperTooltipTheme::addStyle(%this, %name, %style) +{ + %this.styles[%name] = %style; +} + +function SuperTooltipTheme::setDefaultStyle(%this, %type, %default) +{ + %this.defaultStyles[%type] = %default; +} + +function SuperTooltipTheme::setSpacing(%this, %verticalSpace, %horizontalSpace) +{ + %this.verticalSpace = %verticalSpace; + %this.horizontalSpace = %horizontalSpace; +} + +function SuperTooltipTheme::getStyle(%this, %name) +{ + return %this.styles[%name]; +} + +function SuperTooltip::init(%this, %theme) +{ + %this.clearTooltip(); + + if(isObject(%theme)) + %this.setTheme(%theme); +} + +function SuperTooltip::clearTooltip(%this) +{ + if(%this.paramCount > 0) + { + for(%i=0;%i<%this.paramCount;%i++) + %this.param[%i] = ""; + } + + %this.title = ""; + %this.paramCount = 0; +} + +function SuperTooltip::processTooltip(%this, %globalPos, %verticalAlign, %horizontalAlign) +{ + if (%verticalAlign $= "") + %verticalAlign = 1; + if (%horizontalAlign $= "") + %horizontalAlign = 0; + + %tooltipWindow = %this.findObjectByInternalName("tooltipWindow"); + + if(isObject(%tooltipWindow)) + %tooltipMLText = %tooltipWindow.findObjectByInternalName("tooltipMLText"); + else + return false; + + if(!isObject(%tooltipMLText)) + return false; + + %verticalSpace = %this.theme.verticalSpace; + %horizontalSpace = %this.theme.horizontalSpace; + + if (%verticalAlign == 1) + %verticalSpace = -%verticalSpace; + if (%horizontalAlign == 1) + %horizontalSpace = -%horizontalSpace; + + %text = %this.getFormatedText(); + %tooltipMLText.setText(%text); + + canvas.pushDialog(%this); + + %tooltipMLText.forceReflow(); + %MLExtent = %tooltipMLText.extent; + %MLHeight = getWord(%MLExtent, 1); + + %tooltipExtent = %tooltipWindow.extent; + %tooltipWidth = getWord(%tooltipExtent, 0); + %tooltipHeight = %MLHeight; + %tooltipWindow.extent = %tooltipWidth SPC %tooltipHeight; + + %globalPosX = getWord(%globalPos, 0); + %globalPosY = getWord(%globalPos, 1); + + %tooltipPosX = %globalPosX - (%horizontalAlign * %tooltipWidth) + %horizontalSpace; + %tooltipPosY = %globalPosY - (%verticalAlign * %tooltipHeight) + %verticalSpace; + + %tooltipWindow.setPosition(%tooltipPosX, %tooltipPosY); + + return true; +} + +function SuperTooltip::hide(%this) +{ + canvas.popDialog(%this); + + %this.clearTooltip(); +} + +function SuperTooltip::setTheme(%this, %theme) +{ + %this.theme = %theme; +} + +function SuperTooltip::setTitle(%this, %title, %style) +{ + if(%style !$= "") + %themeStyle = %this.theme.styles[%style]; + else + %themeStyle = %this.theme.getStyle(%this.theme.defaultStyles[Title]); + + %this.title = %themeStyle @ %title; +} + +function SuperTooltip::addParam(%this, %title, %text, %paramTitleStyle, %paramStyle) +{ + if(%paramTitleStyle !$= "") + %themeTitleStyle = %this.theme.styles[%paramTitleStyle]; + else + %themeTitleStyle = %this.theme.getStyle(%this.theme.defaultStyles[ParamTitle]); + + if(%paramStyle !$= "") + %themeStyle = %this.theme.styles[%paramStyle]; + else + %themeStyle = %this.theme.getStyle(%this.theme.defaultStyles[Param]); + + if (%title $= "") + %this.param[%this.paramCount] = %themeStyle @ %text @ "\n"; + else + %this.param[%this.paramCount] = %themeTitleStyle @ %title @ ": " @ %themeStyle @ %text @ "\n"; + %this.paramCount++; +} + +function SuperTooltip::getFormatedText(%this) +{ + %text = %this.title @ "\n\n"; + + for(%i=0;%i<%this.paramCount;%i++) + { + %text = %text @ %this.param[%i]; + } + + return %text; +} \ No newline at end of file diff --git a/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs b/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs new file mode 100644 index 000000000..9a9ce33d6 --- /dev/null +++ b/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs @@ -0,0 +1,233 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +function GuiInspectorEntityGroup::CreateContent(%this) +{ +} + +function GuiInspectorEntityGroup::InspectObject( %this, %targetObject ) +{ + %this.stack.clear(); + %this.stack.addGuiControl(%this.createAddComponentList()); +} + +function GuiInspectorEntityGroup::createAddComponentList(%this) +{ + %extent = %this.getExtent(); + + %container = new GuiControl() + { + Profile = "EditorContainerProfile"; + HorizSizing = "width"; + VertSizing = "bottom"; + Position = "0 0"; + Extent = %extent.x SPC "25"; + }; + + %componentList = new GuiPopUpMenuCtrlEx(QuickEditComponentList) + { + Profile = "GuiPopupMenuProfile"; + HorizSizing = "width"; + VertSizing = "bottom"; + position = "28 4"; + Extent = (%extent.x - 28) SPC "18"; + hovertime = "100"; + tooltip = "The component to add to the object"; + tooltipProfile = "EditorToolTipProfile"; + }; + + %addButton = new GuiIconButtonCtrl() { + class = AddComponentQuickEditButton; + Profile = "EditorButton"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "2 0"; + Extent = "24 24"; + buttonMargin = "4 4"; + iconLocation = "Left"; + sizeIconToButton = "0"; + iconBitmap = "tools/gui/images/iconAdd.png"; + hovertime = "100"; + tooltip = "Add the selected component to the object"; + tooltipProfile = "EditorToolTipProfile"; + componentList = %componentList; + }; + + %componentList.refresh(); + + %container.add(%componentList); + %container.add(%addButton); + + if(!isObject("componentTooltipTheme")) + { + %theme = createsupertooltiptheme("componentTooltipTheme"); + %theme.addstyle("headerstyle", ""); + %theme.addstyle("headertwostyle", ""); + %theme.addstyle("basictextstyle", ""); + %theme.setdefaultstyle("title", "headerstyle"); + %theme.setdefaultstyle("paramtitle", "headertwostyle"); + %theme.setdefaultstyle("param", "basictextstyle"); + %theme.setspacing(3, 0); + } + + return %container; +} + +function QuickEditComponentList::refresh(%this) +{ + %this.clear(); + + //find all ComponentAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "ComponentAsset")) + return; //if we didn't find ANY, just exit + + // Find all the types. + %count = %assetQuery.getCount(); + + %categories = ""; + for (%i = 0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + %componentAsset = AssetDatabase.acquireAsset(%assetId); + %componentType = %componentAsset.componentType; + if (!isInList(%componentType, %categories)) + %categories = %categories TAB %componentType; + } + + %categories = trim(%categories); + + %index = 0; + %categoryCount = getFieldCount(%categories); + for (%i = 0; %i < %categoryCount; %i++) + { + %category = getField(%categories, %i); + %this.addCategory(%category); + + for (%j = 0; %j < %count; %j++) + { + %assetId = %assetQuery.getAsset(%j); + + %componentAsset = AssetDatabase.acquireAsset(%assetId); + %componentType = %componentAsset.componentType; + %friendlyName = %componentAsset.friendlyName; + + if (%componentType $= %category) + { + //TODO: Haven't worked out getting categories to look distinct + //from entries in the drop-down so for now just indent them for the visual distinction + %spacedName = " " @ %friendlyName; + %this.add(%spacedName, %index); + %this.component[%index] = %componentAsset; + %index++; + } + } + } +} + +function QuickEditComponentList::onHotTrackItem( %this, %itemID ) +{ + %componentObj = %this.component[%itemID]; + if( isObject( %componentObj ) && %this.componentDesc != %componentObj ) + { + SuperTooltipDlg.init("componentTooltipTheme"); + SuperTooltipDlg.setTitle(%componentObj.friendlyName); + SuperTooltipDlg.addParam("", %componentObj.description @ "\n"); + + %fieldCount = %componentObj.getComponentFieldCount(); + for (%i = 0; %i < %fieldCount; %i++) + { + %name = getField(%componentObj.getComponentField(%i), 0); + + SuperTooltipDlg.addParam(%name, %description @ "\n"); + } + %position = %this.getGlobalPosition(); + SuperTooltipDlg.processTooltip( %position,0,1 ); + %this.opened = true; + %this.componentDesc = %componentObj; + } + else if( !isObject( %componentObj ) ) + { + if( %this.opened == true ) + SuperTooltipDlg.hide(); + %this.componentDesc = ""; + } +} + +function QuickEditComponentList::setProperty(%this, %object) +{ + %this.objectToAdd = %object; +} + +function QuickEditComponentList::onSelect(%this) +{ + if( %this.opened == true ) + SuperTooltipDlg.hide(); + + %this.componentToAdd = %this.component[%this.getSelected()]; +} + +function QuickEditComponentList::onCancel( %this ) +{ + if( %this.opened == true ) + SuperTooltipDlg.hide(); +} + +function AddComponentQuickEditButton::onClick(%this) +{ + %component = %this.componentList.componentToAdd; + + %componentName = %this.componentList.componentToAdd.componentName; + %componentClass = %this.componentList.componentToAdd.componentClass; + + %command = "$ComponentEditor::newComponent = new" SPC %componentClass SPC "(){ class = \"" + @ %componentName @ "\"; };"; + + eval(%command); + + %instance = $ComponentEditor::newComponent; + %undo = new UndoScriptAction() + { + actionName = "Added Component"; + class = UndoAddComponent; + object = %this.componentList.objectToAdd; + component = %instance; + }; + + %undo.addToManager(LevelBuilderUndoManager); + + %instance.owner = Inspector.getInspectObject(0); + %instance.owner.add(%instance); + + Inspector.schedule( 50, "refresh" ); + EWorldEditor.isDirty = true; +} + +function addComponent(%obj, %instance) +{ + echo("Adding the component!"); + %obj.addComponent(%instance); + Inspector.schedule( 50, "refresh" ); + EWorldEditor.isDirty = true; +} + From f703a842183748dc246aff79d13feef0ab1b4c6d Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 16 May 2016 13:21:44 -0500 Subject: [PATCH 40/71] Duplicates the missing samplerstate configurations in the empty template, for parity. --- .../scripts/client/lighting/advanced/shaders.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs index 7e6816db3..08a82b8dc 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs @@ -39,9 +39,11 @@ new GFXStateBlockData( AL_VectorLightState ) mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) mSamplerNames[1] = "shadowMap"; - samplerStates[2] = SamplerClampLinear; // SSAO Mask - mSamplerNames[2] = "ssaoMask"; - samplerStates[3] = SamplerWrapPoint; // Random Direction Map + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // SSAO Mask + mSamplerNames[3] = "ssaoMask"; + samplerStates[4] = SamplerWrapPoint; // Random Direction Map cullDefined = true; cullMode = GFXCullNone; @@ -114,8 +116,10 @@ new GFXStateBlockData( AL_ConvexLightState ) mSamplerNames[0] = "prePassBuffer"; samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) mSamplerNames[1] = "shadowMap"; - samplerStates[2] = SamplerClampLinear; // Cookie Map - samplerStates[3] = SamplerWrapPoint; // Random Direction Map + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // Cookie Map + samplerStates[4] = SamplerWrapPoint; // Random Direction Map cullDefined = true; cullMode = GFXCullCW; From c1f02c05e1267b52876fb3e5110a7eaa1386f188 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 16 May 2016 16:03:24 -0500 Subject: [PATCH 41/71] Adds some console methods to the non-class namespace Rotation for some convenient utility functions for dealing with rotations. --- Engine/source/math/mRotation.cpp | 51 +++++++++++++++++++++++++++++++- Engine/source/math/mathTypes.cpp | 2 +- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Engine/source/math/mRotation.cpp b/Engine/source/math/mRotation.cpp index d915348d6..69dfca35d 100644 --- a/Engine/source/math/mRotation.cpp +++ b/Engine/source/math/mRotation.cpp @@ -20,6 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "math/mRotation.h" +#include "console/console.h" +#include "console/engineAPI.h" #ifdef TORQUE_TESTS_ENABLED #include "testing/unitTesting.h" @@ -296,4 +298,51 @@ TEST(Maths, RotationF_Calculations) { //TODO: implement unit test }; -#endif \ No newline at end of file +#endif + +DefineConsoleStaticMethod(Rotation, Add, RotationF, (RotationF a, RotationF b), , + "Adds two rotations together.\n" + "@param a Rotation one." + "@param b Rotation two." + "@returns v sum of both rotations." + "@ingroup Math") +{ + return a + b; +} + +DefineConsoleStaticMethod(Rotation, Subtract, RotationF, (RotationF a, RotationF b), , + "Subtracts two rotations.\n" + "@param a Rotation one." + "@param b Rotation two." + "@returns v difference of both rotations." + "@ingroup Math") +{ + return a - b; +} + +DefineConsoleStaticMethod(Rotation, Interpolate, RotationF, (RotationF a, RotationF b, F32 factor), , + "Interpolates between two rotations.\n" + "@param a Rotation one." + "@param b Rotation two." + "@param factor The amount to interpolate between the two." + "@returns v, interpolated result." + "@ingroup Math") +{ + RotationF result; + result.interpolate(a, b, factor); + return result; +} + +DefineConsoleStaticMethod(Rotation, LookAt, RotationF, (Point3F origin, Point3F target, Point3F up), + (Point3F(0, 0, 0), Point3F(0, 0, 0), Point3F(0, 0, 1)), + "Provides a rotation orientation to look at a target from a given position.\n" + "@param origin Position of the object doing the looking." + "@param target Position to be looked at." + "@param up The up angle to orient the rotation." + "@returns v orientation result." + "@ingroup Math") +{ + RotationF result; + result.lookAt(origin, target, up); + return result; +} \ No newline at end of file diff --git a/Engine/source/math/mathTypes.cpp b/Engine/source/math/mathTypes.cpp index dd018b2a4..9e5605207 100644 --- a/Engine/source/math/mathTypes.cpp +++ b/Engine/source/math/mathTypes.cpp @@ -583,7 +583,7 @@ ConsoleSetType( TypeEaseF ) // TypeRotationF //----------------------------------------------------------------------------- ConsoleType(RotationF, TypeRotationF, RotationF, "") -//ImplementConsoleTypeCasters( TypeRotationF, RotationF ) +ImplementConsoleTypeCasters( TypeRotationF, RotationF ) ConsoleGetType(TypeRotationF) { From c0a96c908f861ef824aa971df0db7a431217558f Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 17 May 2016 12:46:39 -0500 Subject: [PATCH 42/71] Adds handling for if the user cancels out of the file dialog, and adds support for proper multi-filters. --- .../platform/nativeDialogs/fileDialog.cpp | 60 +++++++++++++------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/Engine/source/platform/nativeDialogs/fileDialog.cpp b/Engine/source/platform/nativeDialogs/fileDialog.cpp index f7eb26a53..08d689585 100644 --- a/Engine/source/platform/nativeDialogs/fileDialog.cpp +++ b/Engine/source/platform/nativeDialogs/fileDialog.cpp @@ -184,33 +184,56 @@ static const U32 convertUTF16toUTF8DoubleNULL(const UTF16 *unistring, UTF8 *out // bool FileDialog::Execute() { - String suffix; + String strippedFilters; U32 filtersCount = StringUnit::getUnitCount(mData.mFilters, "|"); for (U32 i = 1; i < filtersCount; ++i) { //The first of each pair is the name, which we'll skip because NFD doesn't support named filters atm - const char *filter = StringUnit::getUnit(mData.mFilters, i, "|"); + String filter = StringUnit::getUnit(mData.mFilters, i, "|"); - if (!dStrcmp(filter, "*.*")) + if (!dStrcmp(filter.c_str(), "*.*")) continue; - U32 c = 2; - const char* tmpchr = &filter[c]; - String tString = String(tmpchr); - tString.ToLower(tString); - suffix += tString; - suffix += String(","); - suffix += tString.ToUpper(tString); + U32 subFilterCount = StringUnit::getUnitCount(filter, ";"); + + //if we have a 'super filter', break it down to sub-options as well + if (subFilterCount > 1) + { + String suffixFilter; + String subFilters; + + for (U32 f = 0; f < subFilterCount; ++f) + { + String subFilter = StringUnit::getUnit(filter, f, ";"); + + suffixFilter += String::ToLower(subFilter) + "," + String::ToUpper(subFilter) + ","; + subFilters += String::ToLower(subFilter) + "," + String::ToUpper(subFilter) + ";"; + } + + suffixFilter = suffixFilter.substr(0, suffixFilter.length() - 1); + suffixFilter += ";"; + + strippedFilters += suffixFilter + subFilters; + } + else //otherwise, just add the filter + { + strippedFilters += String::ToLower(filter) + "," + String::ToUpper(filter) + ";"; + } ++i; - if (i < filtersCount-2) - suffix += String(";"); + if (i < filtersCount - 2) + strippedFilters += String(";"); } - String strippedFilters = suffix; - strippedFilters.replace(";",","); - strippedFilters += String(";") + suffix; + + //strip the last character, if it's unneeded + if (strippedFilters.endsWith(";")) + { + strippedFilters = strippedFilters.substr(0, strippedFilters.length() - 1); + } + + strippedFilters.replace("*.", ""); // Get the current working directory, so we can back up to it once Windows has // done its craziness and messed with it. @@ -236,10 +259,14 @@ bool FileDialog::Execute() else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES) result = NFD_OpenDialogMultiple(strippedFilters.c_str(), defaultPath.c_str(), &pathSet); + if (result == NFD_CANCEL) + { + return false; + } + String resultPath = String(outPath).replace(rootDir, String("")); resultPath = resultPath.replace(0, 1, String("")).c_str(); //kill '\\' prefix resultPath = resultPath.replace(String("\\"), String("/")); - // Did we select a file? if (result != NFD_OKAY) @@ -278,7 +305,6 @@ bool FileDialog::Execute() // Return success. return true; - } DefineEngineMethod(FileDialog, Execute, bool, (), , From 36bb0b3c540600d8dbd81b9e0230bbeeb5e6bbf8 Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 17 May 2016 23:57:30 -0500 Subject: [PATCH 43/71] Minor corrections to some component scripts to clear old references. --- .../scripts/server/components/game/camera.cs | 2 -- .../server/components/game/controlObject.cs | 2 -- .../server/components/input/fpsControls.cs | 2 -- .../server/gameObjects/GameObjectList.xml | 28 ------------------- .../gameObjects/ThirdPersonPlayerObject.cs | 6 ---- 5 files changed, 40 deletions(-) delete mode 100644 Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml diff --git a/Templates/Full/game/scripts/server/components/game/camera.cs b/Templates/Full/game/scripts/server/components/game/camera.cs index e0b6bc41e..24363bd82 100644 --- a/Templates/Full/game/scripts/server/components/game/camera.cs +++ b/Templates/Full/game/scripts/server/components/game/camera.cs @@ -22,8 +22,6 @@ function CameraComponent::onAdd(%this) { - Parent::onBehaviorAdd(%this); - %this.addComponentField(clientOwner, "The client that views this camera", "int", "1", ""); %test = %this.clientOwner; diff --git a/Templates/Full/game/scripts/server/components/game/controlObject.cs b/Templates/Full/game/scripts/server/components/game/controlObject.cs index 5b67f394b..7f477ecca 100644 --- a/Templates/Full/game/scripts/server/components/game/controlObject.cs +++ b/Templates/Full/game/scripts/server/components/game/controlObject.cs @@ -24,8 +24,6 @@ function ControlObjectComponent::onAdd(%this) { - Parent::onBehaviorAdd(%this); - %this.addComponentField(clientOwner, "The shape to use for rendering", "int", "1", ""); %clientID = %this.getClientID(); diff --git a/Templates/Full/game/scripts/server/components/input/fpsControls.cs b/Templates/Full/game/scripts/server/components/input/fpsControls.cs index 3e7f571bd..8331e409d 100644 --- a/Templates/Full/game/scripts/server/components/input/fpsControls.cs +++ b/Templates/Full/game/scripts/server/components/input/fpsControls.cs @@ -24,8 +24,6 @@ function FPSControls::onAdd(%this) { - Parent::onBehaviorAdd(%this); - // %this.beginGroup("Keys"); %this.addComponentField(forwardKey, "Key to bind to vertical thrust", keybind, "keyboard w"); diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml b/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml deleted file mode 100644 index e9cc73c89..000000000 --- a/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - ScriptedTriggerObject - data/EC/scripts/gameObjects/ScriptedTriggerObject.taml - data/EC/scripts/gameObjects/ScriptedTriggerObject.cs - - - PlayerObject - data/EC/scripts/gameObjects/playerObject.taml - data/EC/scripts/gameObjects/playerObject.cs - - - spectatorObject - data/EC/scripts/gameObjects/spectatorObject.taml - data/EC/scripts/gameObjects/spectatorObject.cs - - - ThirdPersonPlayerObject - data/EC/scripts/gameObjects/ThirdPersonPlayerObject.taml - data/EC/scripts/gameObjects/ThirdPersonPlayerObject.cs - - - FirstPersonArms - data/EC/scripts/gameObjects/FirstPersonArms.taml - data/EC/scripts/gameObjects/FirstPersonArms.cs - - diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs index bc92db12d..3ab05a79d 100644 --- a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs +++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs @@ -26,12 +26,6 @@ function ThirdPersonPlayerObject::onAdd(%this) %this.aimedMaxPitch = 90; %this.aimedMinPitch = -90; - - %this.arms = SGOManager.spawn("FirstPersonArms", true); - - %this.add(arms); - - //%this.mesh.mountObject(%this.arms, "Eye"); } function ThirdPersonPlayerObject::onRemove(%this) From 03e6228e562691693d34c3ff3a3700682b660c3a Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 17 May 2016 23:58:34 -0500 Subject: [PATCH 44/71] Adjusts the CMAKE install script to not install the E/C-related template files if that's not set as a flag. --- Tools/CMake/torque3d.cmake | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index c8c017583..263ae5d78 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -726,7 +726,34 @@ endif() if(TORQUE_TEMPLATE) message("Prepare Template(${TORQUE_TEMPLATE}) install...") - INSTALL(DIRECTORY "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game" DESTINATION "${TORQUE_APP_DIR}") + file(GLOB_RECURSE INSTALL_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/*") + + IF( NOT TORQUE_EXPERIMENTAL_EC) + list(REMOVE_ITEM INSTALL_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/art/art.module.taml") + list(REMOVE_ITEM INSTALL_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/art/shapes/actors/Soldier/soldier.asset.taml") + list(REMOVE_ITEM INSTALL_FILES_AND_DIRS "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/scripts/scripts.module.taml") + + foreach(ITEM ${INSTALL_FILES_AND_DIRS}) + get_filename_component( dir ${ITEM} DIRECTORY ) + get_filename_component( fileName ${ITEM} NAME ) + if( ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/scripts/server/components + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/scripts/server/components/game + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/scripts/server/components/input + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/scripts/server/gameObjects + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/tools/componentEditor + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/tools/componentEditor/gui + OR ${dir} STREQUAL ${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/game/tools/componentEditor/scripts ) + list(REMOVE_ITEM INSTALL_FILES_AND_DIRS ${dir}/${fileName}) + ENDIF() + endforeach() + ENDIF() + + foreach(ITEM ${INSTALL_FILES_AND_DIRS}) + get_filename_component( dir ${ITEM} DIRECTORY ) + STRING(REGEX REPLACE "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/" "${TORQUE_APP_DIR}/" INSTALL_DIR ${dir}) + install( FILES ${ITEM} DESTINATION ${INSTALL_DIR} ) + endforeach() + if(WIN32) INSTALL(FILES "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/cleanShaders.bat" DESTINATION "${TORQUE_APP_DIR}") INSTALL(FILES "${CMAKE_SOURCE_DIR}/Templates/${TORQUE_TEMPLATE}/DeleteCachedDTSs.bat" DESTINATION "${TORQUE_APP_DIR}") From d79b9a2988f558c2134901cc841cb8ef7410d668 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Wed, 18 May 2016 06:38:13 -0500 Subject: [PATCH 45/71] removes w=z trick (was causing fisheye, effectively) --- Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp | 2 +- Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp | 2 +- .../core/scripts/client/lighting/advanced/deferredShading.cs | 2 +- Templates/Empty/game/shaders/common/basicCloudsV.hlsl | 1 - Templates/Empty/game/shaders/common/cloudLayerV.hlsl | 1 - Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl | 1 - Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl | 1 - .../core/scripts/client/lighting/advanced/deferredShading.cs | 2 +- Templates/Full/game/shaders/common/basicCloudsV.hlsl | 1 - Templates/Full/game/shaders/common/cloudLayerV.hlsl | 1 - Templates/Full/game/shaders/common/gl/basicCloudsV.glsl | 1 - Templates/Full/game/shaders/common/gl/cloudLayerV.glsl | 1 - 12 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index 78c45a09c..11081125c 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -2805,7 +2805,7 @@ void DeferredSkyGLSL::processVert( Vector &componentList, { Var *outPosition = (Var*)LangElement::find( "gl_Position" ); MultiLine *meta = new MultiLine; - meta->addStatement( new GenOp( " @.w = @.z;\r\n", outPosition, outPosition ) ); + //meta->addStatement( new GenOp( " @.w = @.z;\r\n", outPosition, outPosition ) ); output = meta; } diff --git a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp index 8878f2600..78e1c3b89 100644 --- a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp @@ -3000,7 +3000,7 @@ void DeferredSkyHLSL::processVert( Vector &componentList, { Var *outPosition = (Var*)LangElement::find( "hpos" ); MultiLine *meta = new MultiLine; - meta->addStatement( new GenOp( " @.w = @.z;\r\n", outPosition, outPosition ) ); + //meta->addStatement( new GenOp( " @.w = @.z;\r\n", outPosition, outPosition ) ); output = meta; } diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs index d53e6965f..ad9732e0f 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs @@ -55,7 +55,7 @@ new ShaderData( AL_DeferredShader ) singleton PostEffect( AL_DeferredShading ) { - renderTime = "PFXBeforeBin"; + renderTime = "PFXAfterBin"; renderBin = "SkyBin"; shader = AL_DeferredShader; stateBlock = AL_DeferredShadingState; diff --git a/Templates/Empty/game/shaders/common/basicCloudsV.hlsl b/Templates/Empty/game/shaders/common/basicCloudsV.hlsl index 477f17d50..a176fdbcd 100644 --- a/Templates/Empty/game/shaders/common/basicCloudsV.hlsl +++ b/Templates/Empty/game/shaders/common/basicCloudsV.hlsl @@ -46,7 +46,6 @@ ConnectData main( CloudVert IN ) ConnectData OUT; OUT.hpos = mul(modelview, float4(IN.pos,1.0)); - OUT.hpos.w = OUT.hpos.z; float2 uv = IN.uv0; uv += texOffset; diff --git a/Templates/Empty/game/shaders/common/cloudLayerV.hlsl b/Templates/Empty/game/shaders/common/cloudLayerV.hlsl index 94f8b62cb..d60dd251d 100644 --- a/Templates/Empty/game/shaders/common/cloudLayerV.hlsl +++ b/Templates/Empty/game/shaders/common/cloudLayerV.hlsl @@ -63,7 +63,6 @@ ConnectData main( CloudVert IN ) ConnectData OUT; OUT.hpos = mul(modelview, float4(IN.pos,1.0)); - OUT.hpos.w = OUT.hpos.z; // Offset the uv so we don't have a seam directly over our head. float2 uv = IN.uv0 + float2( 0.5, 0.5 ); diff --git a/Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl b/Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl index 40c597120..cccbafa8c 100644 --- a/Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl +++ b/Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl @@ -41,7 +41,6 @@ out vec2 texCoord; void main() { gl_Position = tMul(modelview, IN_pos); - gl_Position.w = gl_Position.z; vec2 uv = IN_uv0; uv += texOffset; diff --git a/Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl b/Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl index cba5c009a..395c6f286 100644 --- a/Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl +++ b/Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl @@ -62,7 +62,6 @@ void main() vec2 IN_uv0 = vTexCoord0.st; gl_Position = modelview * IN_pos; - gl_Position.w = gl_Position.z; // Offset the uv so we don't have a seam directly over our head. vec2 uv = IN_uv0 + vec2( 0.5, 0.5 ); diff --git a/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs b/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs index d53e6965f..ad9732e0f 100644 --- a/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs +++ b/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs @@ -55,7 +55,7 @@ new ShaderData( AL_DeferredShader ) singleton PostEffect( AL_DeferredShading ) { - renderTime = "PFXBeforeBin"; + renderTime = "PFXAfterBin"; renderBin = "SkyBin"; shader = AL_DeferredShader; stateBlock = AL_DeferredShadingState; diff --git a/Templates/Full/game/shaders/common/basicCloudsV.hlsl b/Templates/Full/game/shaders/common/basicCloudsV.hlsl index 477f17d50..a176fdbcd 100644 --- a/Templates/Full/game/shaders/common/basicCloudsV.hlsl +++ b/Templates/Full/game/shaders/common/basicCloudsV.hlsl @@ -46,7 +46,6 @@ ConnectData main( CloudVert IN ) ConnectData OUT; OUT.hpos = mul(modelview, float4(IN.pos,1.0)); - OUT.hpos.w = OUT.hpos.z; float2 uv = IN.uv0; uv += texOffset; diff --git a/Templates/Full/game/shaders/common/cloudLayerV.hlsl b/Templates/Full/game/shaders/common/cloudLayerV.hlsl index 94f8b62cb..d60dd251d 100644 --- a/Templates/Full/game/shaders/common/cloudLayerV.hlsl +++ b/Templates/Full/game/shaders/common/cloudLayerV.hlsl @@ -63,7 +63,6 @@ ConnectData main( CloudVert IN ) ConnectData OUT; OUT.hpos = mul(modelview, float4(IN.pos,1.0)); - OUT.hpos.w = OUT.hpos.z; // Offset the uv so we don't have a seam directly over our head. float2 uv = IN.uv0 + float2( 0.5, 0.5 ); diff --git a/Templates/Full/game/shaders/common/gl/basicCloudsV.glsl b/Templates/Full/game/shaders/common/gl/basicCloudsV.glsl index 40c597120..cccbafa8c 100644 --- a/Templates/Full/game/shaders/common/gl/basicCloudsV.glsl +++ b/Templates/Full/game/shaders/common/gl/basicCloudsV.glsl @@ -41,7 +41,6 @@ out vec2 texCoord; void main() { gl_Position = tMul(modelview, IN_pos); - gl_Position.w = gl_Position.z; vec2 uv = IN_uv0; uv += texOffset; diff --git a/Templates/Full/game/shaders/common/gl/cloudLayerV.glsl b/Templates/Full/game/shaders/common/gl/cloudLayerV.glsl index cba5c009a..395c6f286 100644 --- a/Templates/Full/game/shaders/common/gl/cloudLayerV.glsl +++ b/Templates/Full/game/shaders/common/gl/cloudLayerV.glsl @@ -62,7 +62,6 @@ void main() vec2 IN_uv0 = vTexCoord0.st; gl_Position = modelview * IN_pos; - gl_Position.w = gl_Position.z; // Offset the uv so we don't have a seam directly over our head. vec2 uv = IN_uv0 + vec2( 0.5, 0.5 ); From f54fde9c6b62443b74c24cb83fafaa8dd48d500c Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 19 May 2016 23:42:38 -0500 Subject: [PATCH 46/71] Missing the preprocessor define in the project generation. --- Tools/CMake/torque3d.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 263ae5d78..bb0b274cb 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -428,6 +428,10 @@ if(TORQUE_DEDICATED) addDef(TORQUE_DEDICATED) endif() +if(TORQUE_EXPERIMENTAL_EC) + addDef(TORQUE_EXPERIMENTAL_EC) +endif() + #modules dir file(GLOB modules "modules/*.cmake") foreach(module ${modules}) From 7ae1d3d99627f73b41b0a702625c0ac8ccd4c256 Mon Sep 17 00:00:00 2001 From: John3 Date: Fri, 20 May 2016 17:04:56 -0500 Subject: [PATCH 47/71] Bug space folder in scene tree. Fix by David Robert Pemberton https://www.garagegames.com/community/blogs/view/22295 You can see the folder "soldier actor" --- .../Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs | 4 +++- .../game/tools/worldEditor/scripts/editors/creator.ed.cs | 4 +++- .../Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs | 4 +++- .../Full/game/tools/worldEditor/scripts/editors/creator.ed.cs | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs b/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs index 180a9a8ab..d61fe79ea 100644 --- a/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs +++ b/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs @@ -380,7 +380,8 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Ignore assets in the tools folder %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %splitPath, "/", " " ); if ( getWord( %splitPath, 0 ) $= "tools" ) { %fullPath = findNextFileMultiExpr( %filePatterns ); @@ -393,6 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Add this file's path ( parent folders ) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "|", " " ); %r = ShapeEdSelectMenu.findText( %temp ); if ( %r == -1 ) ShapeEdSelectMenu.add( %temp ); diff --git a/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs index dc5d7f991..afc9c7c85 100644 --- a/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -318,7 +318,8 @@ function EWCreatorWindow::navigate( %this, %address ) } %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { %fullPath = findNextFileMultiExpr( getFormatExtensions() ); @@ -332,6 +333,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "|", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { diff --git a/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs b/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs index 180a9a8ab..d61fe79ea 100644 --- a/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs +++ b/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs @@ -380,7 +380,8 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Ignore assets in the tools folder %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %splitPath, "/", " " ); if ( getWord( %splitPath, 0 ) $= "tools" ) { %fullPath = findNextFileMultiExpr( %filePatterns ); @@ -393,6 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Add this file's path ( parent folders ) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "|", " " ); %r = ShapeEdSelectMenu.findText( %temp ); if ( %r == -1 ) ShapeEdSelectMenu.add( %temp ); diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs index 6832410dd..daad87201 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -318,7 +318,8 @@ function EWCreatorWindow::navigate( %this, %address ) } %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { %fullPath = findNextFileMultiExpr( getFormatExtensions() ); @@ -332,6 +333,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "|", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { From 6517b864919b7651a8de1b08d307af6e422638fb Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 21 May 2016 11:47:10 -0500 Subject: [PATCH 48/71] Editor integration for creation of entities and GameObjects. --- .../server/components/game/itemRotate.cs | 2 +- .../server/gameObjects/GameObjectManager.cs | 68 ++++++-- .../worldEditor/gui/GeneralSettingsTab.ed.gui | 71 ++++++++ .../tools/worldEditor/scripts/EditorGui.ed.cs | 163 ++++++++++++++++++ .../worldEditor/scripts/editorPrefs.ed.cs | 1 + .../worldEditor/scripts/editors/creator.ed.cs | 1 + 6 files changed, 294 insertions(+), 12 deletions(-) diff --git a/Templates/Full/game/scripts/server/components/game/itemRotate.cs b/Templates/Full/game/scripts/server/components/game/itemRotate.cs index 259b44111..947d19214 100644 --- a/Templates/Full/game/scripts/server/components/game/itemRotate.cs +++ b/Templates/Full/game/scripts/server/components/game/itemRotate.cs @@ -29,7 +29,7 @@ function ItemRotationComponent::onAdd(%this) %this.addComponentField(horizontal, "Rotate horizontal or verticle, true for horizontal", "bool", "1", ""); } -function ItemRotateBehavior::Update(%this) +function ItemRotationComponent::Update(%this) { %tickRate = 0.032; diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs index 138bcb8be..57c47c5cf 100644 --- a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs +++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs @@ -39,15 +39,12 @@ function execGameObjects() } } -function spawnGameObject(%name, %addToMissionGroup) +function findGameObject(%name) { - if(%addToMissionGroup $= "") - %addToMissionGroup = true; - //find all GameObjectAssets %assetQuery = new AssetQuery(); if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) - return; //if we didn't find ANY, just exit + return 0; //if we didn't find ANY, just exit %count = %assetQuery.getCount(); @@ -61,15 +58,64 @@ function spawnGameObject(%name, %addToMissionGroup) { if(isFile(%gameObjectAsset.TAMLFilePath)) { - %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); - - if(%addToMissionGroup == true) - MissionGroup.add(%newSGOObject); - - return %newSGOObject; + return %gameObjectAsset; } } } return 0; +} + +function spawnGameObject(%name, %addToMissionGroup) +{ + if(%addToMissionGroup $= "") + %addToMissionGroup = true; + + %gameObjectAsset = findGameObject(%name); + + if(isObject(%gameObjectAsset)) + { + %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); + + if(%addToMissionGroup == true) + MissionGroup.add(%newSGOObject); + + return %newSGOObject; + } + + return 0; +} + +function saveGameObject(%name, %tamlPath, %scriptPath) +{ + %gameObjectAsset = findGameObject(%name); + + //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset + if(isObject(%gameObjectAsset)) + { + %assetID = %gameObjectAsset.getAssetId(); + + %gameObjectAsset.TAMLFilePath = %tamlPath; + %gameObjectAsset.scriptFilePath = %scriptPath; + + TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID)); + AssetDatabase.refreshAsset(%assetID); + } + else + { + //Doesn't exist, so make a new one + %gameObjectAsset = new GameObjectAsset() + { + assetName = %name @ "Asset"; + gameObjectName = %name; + TAMLFilePath = %tamlPath; + scriptFilePath = %scriptPath; + }; + + //Save it alongside the taml file + %path = filePath(%tamlPath); + + TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml"); + AssetDatabase.refreshAllAssets(true); + } } \ No newline at end of file diff --git a/Templates/Full/game/tools/worldEditor/gui/GeneralSettingsTab.ed.gui b/Templates/Full/game/tools/worldEditor/gui/GeneralSettingsTab.ed.gui index d89ff1a4d..b85e78ae0 100644 --- a/Templates/Full/game/tools/worldEditor/gui/GeneralSettingsTab.ed.gui +++ b/Templates/Full/game/tools/worldEditor/gui/GeneralSettingsTab.ed.gui @@ -204,6 +204,77 @@ editorSettingsWrite = "EditorGui.writeWorldEditorSettings();"; }; }; + new GuiControl() { + position = "0 0"; + extent = "430 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "ToolsGuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "ToolsGuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTextCtrl() { + text = "New Game Objects"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "5 1"; + extent = "70 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "ToolsGuiTextRightProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "ToolsGuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextEditCtrl() { + historySize = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + password = "0"; + passwordMask = "*"; + text = "scripts/server/gameObjects"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "81 0"; + extent = "345 17"; + minExtent = "8 2"; + horizSizing = "width"; + vertSizing = "bottom"; + profile = "ToolsGuiTextEditProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "ToolsGuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "1"; + class = "ESettingsWindowTextEdit"; + editorSettingsRead = "EditorGui.readWorldEditorSettings();"; + editorSettingsValue = "WorldEditor/newGameObjectDir"; + editorSettingsWrite = "EditorGui.writeWorldEditorSettings();"; + }; + }; }; }; }; diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index 6f80d9206..f9ab055af 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -1643,6 +1643,20 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj ) object = -1; }; + + if(%obj.isMemberOfClass("Entity")) + { + %popup = ETEntityContextPopup; + if( !isObject( %popup ) ) + %popup = new PopupMenu( ETEntityContextPopup : ETSimGroupContextPopup ) + { + superClass = "MenuBuilder"; + isPopup = "1"; + + item[ 12 ] = "-"; + item[ 13 ] = "Convert to Game Object" TAB "" TAB "EWorldEditor.createGameObject( %this.object );"; + }; + } %popup.object = %obj; @@ -2204,6 +2218,155 @@ function EWorldEditor::deleteMissionObject( %this, %object ) EditorTree.buildVisibleTree( true ); } +function EWorldEditor::createGameObject( %this, %entity ) +{ + if(!isObject(GameObjectBuilder)) + { + new GuiControl(GameObjectBuilder, EditorGuiGroup) { + profile = "ToolsGuiDefaultProfile"; + horizSizing = "right"; + vertSizing = "bottom"; + position = "0 0"; + extent = "800 600"; + minExtent = "8 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + helpTag = "0"; + + new GuiWindowCtrl(GameObjectBuilderTargetWindow) { + profile = "ToolsGuiWindowProfile"; + horizSizing = "center"; + vertSizing = "center"; + position = "384 205"; + extent = "256 102"; + minExtent = "256 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + helpTag = "0"; + resizeWidth = "1"; + resizeHeight = "1"; + canMove = "1"; + canClose = "0"; + canMinimize = "0"; + canMaximize = "0"; + minSize = "50 50"; + text = "Create Object"; + + new GuiTextCtrl() { + profile = "GuiCenterTextProfile"; + horizSizing = "right"; + vertSizing = "bottom"; + position = "9 26"; + extent = "84 16"; + minExtent = "8 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + helpTag = "0"; + text = "Object Name:"; + }; + new GuiTextEditCtrl(GameObjectBuilderObjectName) { + class = ObjectBuilderGuiTextEditCtrl; + profile = "ToolsGuiTextEditProfile"; + horizSizing = "width"; + vertSizing = "bottom"; + position = "78 26"; + extent = "172 18"; + minExtent = "8 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + helpTag = "0"; + historySize = "0"; + }; + new GuiButtonCtrl(GameObjectBuilderOKButton) { + profile = "ToolsGuiButtonProfile"; + horizSizing = "width"; + vertSizing = "bottom"; + position = "7 250"; + extent = "156 24"; + minExtent = "8 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + command = "EWorldEditor.buildGameObject();"; + helpTag = "0"; + text = "Create New"; + Accelerator = "return"; + }; + new GuiButtonCtrl(GameObjectBuilderCancelButton) { + profile = "ToolsGuiButtonProfile"; + horizSizing = "left"; + vertSizing = "bottom"; + position = "170 250"; + extent = "80 24"; + minExtent = "8 8"; + visible = "1"; + setFirstResponder = "0"; + modal = "1"; + command = "Canvas.popDialog(GameObjectBuilder);"; + helpTag = "0"; + text = "Cancel"; + Accelerator = "escape"; + }; + }; + }; + + GameObjectBuilderTargetWindow.extent = getWord(GameObjectBuilderTargetWindow.extent, 0) SPC 88; + GameObjectBuilderOKButton.position = getWord(GameObjectBuilderOKButton.position, 0) SPC 57; + GameObjectBuilderCancelButton.position = getWord(GameObjectBuilderCancelButton.position, 0) SPC 57; + } + + GameObjectBuilderObjectName.text = ""; + GameObjectBuilder.selectedEntity = %entity; + + Canvas.pushDialog(GameObjectBuilder); +} + +function EWorldEditor::buildGameObject(%this) +{ + if(GameObjectBuilderObjectName.getText() $= "") + { + error("Attempted to make a new Game Object with no name!"); + Canvas.popDialog(GameObjectBuilder); + return; + } + + %path = EditorSettings.value( "WorldEditor/newGameObjectDir" ); + %className = GameObjectBuilderObjectName.getText(); + GameObjectBuilder.selectedEntity.class = %className; + Inspector.inspect(GameObjectBuilder.selectedEntity); + + %file = new FileObject(); + + if(%file.openForWrite(%path @ "\\" @ %className @ ".cs")) + { + %file.writeline("function " @ %className @ "::onAdd(%this)\n{\n\n}\n"); + %file.writeline("function " @ %className @ "::onRemove(%this)\n{\n\n}\n"); + + //todo, pre-write any event functions of interest + + %file.close(); + } + + //set up the paths + %tamlPath = %path @ "/" @ %className @ ".taml"; + %scriptPath = %path @ "/" @ %className @ ".cs"; + saveGameObject(%className, %tamlPath, %scriptPath); + + //reload it + execGameObjects(); + + //now, add the script file and a ref to the taml into our SGO manifest so we can readily spawn it later. + TamlWrite(GameObjectBuilder.selectedEntity, %tamlpath); + + GameObjectBuilder.selectedEntity = ""; + + Canvas.popDialog(GameObjectBuilder); +} + function EWorldEditor::selectAllObjectsInSet( %this, %set, %deselect ) { if( !isObject( %set ) ) diff --git a/Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs index 0cc14bff0..1704e06ad 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs @@ -34,6 +34,7 @@ EditorSettings.setDefaultValue( "orthoFOV", "50" ); EditorSettings.setDefaultValue( "orthoShowGrid", "1" ); EditorSettings.setDefaultValue( "currentEditor", "WorldEditorInspectorPlugin" ); EditorSettings.setDefaultValue( "newLevelFile", "tools/levels/BlankRoom.mis" ); +EditorSettings.setDefaultValue( "newGameObjectDir", "scripts/server/gameObjects" ); if( isFile( "C:/Program Files/Torsion/Torsion.exe" ) ) EditorSettings.setDefaultValue( "torsionPath", "C:/Program Files/Torsion/Torsion.exe" ); diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs index 6832410dd..a6507cbaf 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -85,6 +85,7 @@ function EWCreatorWindow::init( %this ) %this.registerMissionObject( "SFXSpace", "Sound Space" ); %this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" ); %this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" ); + %this.registerMissionObject( "Entity", "Entity" ); %this.endGroup(); From 04adb9f2409df1f3520eceae7940e24882fb98e9 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 21 May 2016 14:44:24 -0500 Subject: [PATCH 49/71] Added a small sanity check so we don't pointlessly throw an error when expanding an Entity's component stack in the scene tree. --- Engine/source/gui/controls/guiTreeViewCtrl.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index 1e3dfa712..b96418845 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -3795,16 +3795,19 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) //We check if our object is an entity, and if it is, we call a 'onInspect' function. //This function is pretty much a special notifier to the entity so if it has any behaviors that do special //stuff in the editor, it can fire that up - Entity* e = dynamic_cast(item->getObject()); - if (item->mScriptInfo.mText != StringTable->insert("Components")) + if (item->isInspectorData()) { Entity* e = dynamic_cast(item->getObject()); - if (e) + if (item->mScriptInfo.mText != StringTable->insert("Components")) { - if (item->isExpanded()) - e->onInspect(); - else - e->onEndInspect(); + Entity* e = dynamic_cast(item->getObject()); + if (e) + { + if (item->isExpanded()) + e->onInspect(); + else + e->onEndInspect(); + } } } #endif From 4bb63f277e3655139235b4b70d730ce2e5f61f79 Mon Sep 17 00:00:00 2001 From: John3 Date: Sat, 21 May 2016 15:10:35 -0500 Subject: [PATCH 50/71] change pipe to underscore and fix prefabs assets --- .../game/tools/shapeEditor/scripts/shapeEditor.ed.cs | 4 ++-- .../game/tools/worldEditor/scripts/editors/creator.ed.cs | 8 +++++--- .../Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs | 4 ++-- .../game/tools/worldEditor/scripts/editors/creator.ed.cs | 8 +++++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs b/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs index d61fe79ea..391e0b217 100644 --- a/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs +++ b/Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs @@ -380,7 +380,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Ignore assets in the tools folder %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %fullPath, " ", "_" ); %splitPath = strreplace( %splitPath, "/", " " ); if ( getWord( %splitPath, 0 ) $= "tools" ) { @@ -394,7 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Add this file's path ( parent folders ) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); - %temp = strreplace( %temp, "|", " " ); + %temp = strreplace( %temp, "_", " " ); %r = ShapeEdSelectMenu.findText( %temp ); if ( %r == -1 ) ShapeEdSelectMenu.add( %temp ); diff --git a/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs index afc9c7c85..43d4fb65c 100644 --- a/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -318,7 +318,7 @@ function EWCreatorWindow::navigate( %this, %address ) } %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %fullPath, " ", "_" ); %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { @@ -333,7 +333,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); - %temp = strreplace( %temp, "|", " " ); + %temp = strreplace( %temp, "_", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { @@ -432,7 +432,8 @@ function EWCreatorWindow::navigate( %this, %address ) while ( %fullPath !$= "" ) { %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "_" ); + %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { %fullPath = findNextFile( %expr ); @@ -446,6 +447,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "_", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { diff --git a/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs b/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs index d61fe79ea..391e0b217 100644 --- a/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs +++ b/Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs @@ -380,7 +380,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Ignore assets in the tools folder %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %fullPath, " ", "_" ); %splitPath = strreplace( %splitPath, "/", " " ); if ( getWord( %splitPath, 0 ) $= "tools" ) { @@ -394,7 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address ) // Add this file's path ( parent folders ) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); - %temp = strreplace( %temp, "|", " " ); + %temp = strreplace( %temp, "_", " " ); %r = ShapeEdSelectMenu.findText( %temp ); if ( %r == -1 ) ShapeEdSelectMenu.add( %temp ); diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs index daad87201..9f015f359 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -318,7 +318,7 @@ function EWCreatorWindow::navigate( %this, %address ) } %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, " ", "|" ); + %splitPath = strreplace( %fullPath, " ", "_" ); %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { @@ -333,7 +333,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); - %temp = strreplace( %temp, "|", " " ); + %temp = strreplace( %temp, "_", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { @@ -432,7 +432,8 @@ function EWCreatorWindow::navigate( %this, %address ) while ( %fullPath !$= "" ) { %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() ); - %splitPath = strreplace( %fullPath, "/", " " ); + %splitPath = strreplace( %fullPath, " ", "_" ); + %splitPath = strreplace( %splitPath, "/", " " ); if( getWord(%splitPath, 0) $= "tools" ) { %fullPath = findNextFile( %expr ); @@ -446,6 +447,7 @@ function EWCreatorWindow::navigate( %this, %address ) // Add this file's path (parent folders) to the // popup menu if it isn't there yet. %temp = strreplace( %pathFolders, " ", "/" ); + %temp = strreplace( %temp, "_", " " ); %r = CreatorPopupMenu.findText( %temp ); if ( %r == -1 ) { From 8a7159c00e0cff62c00b36924e86a9aba1bbe182 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 22 May 2016 23:51:58 -0500 Subject: [PATCH 51/71] Fixes the drawUtil rendering of polyhedrons by correcting the index ordering to work with triangleStrip as opposed to Fan. --- Engine/source/gfx/gfxDrawUtil.cpp | 2 +- Engine/source/math/mPolyhedron.impl.h | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 959822000..42b146a10 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -1015,7 +1015,7 @@ void GFXDrawUtil::_drawSolidPolyhedron( const GFXStateBlockDesc &desc, const Any // Allocate a temp buffer for the face indices. - const U32 numIndices = poly.getNumEdges() * 2; + const U32 numIndices = poly.getNumEdges() * 3; const U32 numPlanes = poly.getNumPlanes(); GFXPrimitiveBufferHandle prims( mDevice, numIndices, 0, GFXBufferTypeVolatile ); diff --git a/Engine/source/math/mPolyhedron.impl.h b/Engine/source/math/mPolyhedron.impl.h index ef74995ab..796f11350 100644 --- a/Engine/source/math/mPolyhedron.impl.h +++ b/Engine/source/math/mPolyhedron.impl.h @@ -385,6 +385,8 @@ U32 PolyhedronImpl< Base >::extractFace( U32 plane, IndexType* outIndices, U32 m // so it should be sufficiently fast to just loop over the original // set. + U32 indexItr = 0; + do { // Add the vertex for the current edge. @@ -392,7 +394,15 @@ U32 PolyhedronImpl< Base >::extractFace( U32 plane, IndexType* outIndices, U32 m if( idx >= maxOutIndices ) return 0; - outIndices[ idx ++ ] = currentVertex; + ++indexItr; + + if (indexItr >= 3) + { + outIndices[idx++] = firstEdge->vertex[0]; + indexItr = 0; + } + + outIndices[idx++] = currentVertex; // Look for next edge. From cfd15d47e448f2ae581380784fd1cab6cef38361 Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 24 May 2016 20:09:24 -0500 Subject: [PATCH 52/71] Correction to interpolation/warp issue caused by using the wrong variable. --- Engine/source/T3D/Entity.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Engine/source/T3D/Entity.cpp b/Engine/source/T3D/Entity.cpp index e80f4e8b8..680f098d9 100644 --- a/Engine/source/T3D/Entity.cpp +++ b/Engine/source/T3D/Entity.cpp @@ -404,8 +404,7 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream) //mathWrite(*stream, getPosition()); mathWrite(*stream, mPos); - //mathWrite(*stream, getRotation()); - mathWrite(*stream, getRotation().asEulerF()); + mathWrite(*stream, getRotation()); mDelta.move.pack(stream); @@ -502,10 +501,7 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream) RotationF rot; - EulerF eRot; - mathRead(*stream, &eRot); - - rot = RotationF(eRot); + mathRead(*stream, &rot); mDelta.move.unpack(stream); @@ -602,7 +598,8 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream) mDelta.posVec = (cp - mDelta.pos) / mDelta.dt; QuatF cr; cr.interpolate(mDelta.rot[1], mDelta.rot[0], mDelta.dt); - mDelta.rot[1].interpolate(cr, pos, mDelta.dt / dt); + + mDelta.rot[1].interpolate(cr, rot.asQuatF(), mDelta.dt / dt); mDelta.rot[0].extrapolate(mDelta.rot[1], cr, mDelta.dt); } From 942235d11462c2d0ecc336b7ab31fda2646ad693 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Wed, 25 May 2016 03:08:28 -0500 Subject: [PATCH 53/71] Fixes vertcolor code insertion order, and applies it adaptively based on defered or forward lit context --- Engine/source/materials/materialFeatureTypes.cpp | 2 +- Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp | 5 ++++- Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Engine/source/materials/materialFeatureTypes.cpp b/Engine/source/materials/materialFeatureTypes.cpp index 85fbd2895..513474c77 100644 --- a/Engine/source/materials/materialFeatureTypes.cpp +++ b/Engine/source/materials/materialFeatureTypes.cpp @@ -30,7 +30,6 @@ ImplementFeatureType( MFT_VertTransform, MFG_Transform, 0, true ); ImplementFeatureType( MFT_TexAnim, MFG_PreTexture, 1.0f, true ); ImplementFeatureType( MFT_Parallax, MFG_PreTexture, 2.0f, true ); -ImplementFeatureType( MFT_DiffuseVertColor, MFG_PreTexture, 3.0f, true ); ImplementFeatureType( MFT_AccuScale, MFG_PreTexture, 4.0f, true ); ImplementFeatureType( MFT_AccuDirection, MFG_PreTexture, 4.0f, true ); @@ -42,6 +41,7 @@ ImplementFeatureType( MFT_DiffuseMap, MFG_Texture, 2.0f, true ); ImplementFeatureType( MFT_OverlayMap, MFG_Texture, 3.0f, true ); ImplementFeatureType( MFT_DetailMap, MFG_Texture, 4.0f, true ); ImplementFeatureType( MFT_DiffuseColor, MFG_Texture, 5.0f, true ); +ImplementFeatureType( MFT_DiffuseVertColor, MFG_Texture, 6.0f, true ); ImplementFeatureType( MFT_AlphaTest, MFG_Texture, 7.0f, true ); ImplementFeatureType( MFT_SpecularMap, MFG_Texture, 8.0f, true ); ImplementFeatureType( MFT_NormalMap, MFG_Texture, 9.0f, true ); diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index 11081125c..e1433c11f 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -1194,7 +1194,10 @@ void DiffuseVertColorFeatureGLSL::processPix( Vector &compon } MultiLine* meta = new MultiLine; - meta->addStatement( new GenOp( " @;\r\n", assignColor( vertColor, Material::Mul ) ) ); + if (fd.features[MFT_isDeferred]) + meta->addStatement(new GenOp(" @;\r\n", assignColor(vertColor, Material::Mul, NULL, ShaderFeature::RenderTarget1))); + else + meta->addStatement(new GenOp(" @;\r\n", assignColor(vertColor, Material::Mul))); output = meta; } diff --git a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp index 78e1c3b89..879176a44 100644 --- a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp @@ -1258,7 +1258,10 @@ void DiffuseVertColorFeatureHLSL::processPix( Vector &compon } MultiLine* meta = new MultiLine; - meta->addStatement( new GenOp( " @;\r\n", assignColor( vertColor, Material::Mul ) ) ); + if (fd.features[MFT_isDeferred]) + meta->addStatement(new GenOp(" @;\r\n", assignColor(vertColor, Material::Mul, NULL, ShaderFeature::RenderTarget1))); + else + meta->addStatement(new GenOp(" @;\r\n", assignColor(vertColor, Material::Mul))); output = meta; } From 358bbdb7401c1a5d2c8387e9b72e12d4aa295430 Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 25 May 2016 13:32:20 -0500 Subject: [PATCH 54/71] Removed script calls to some fields that no longer exist, which was causing console errors. --- .../game/tools/materialEditor/scripts/materialEditor.ed.cs | 3 --- .../game/tools/materialEditor/scripts/materialEditor.ed.cs | 3 --- 2 files changed, 6 deletions(-) diff --git a/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs index be7d55c39..c1f01f1a7 100644 --- a/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -918,9 +918,6 @@ function MaterialEditorGui::guiSync( %this, %material ) MaterialEditorPropertiesWindow-->vertLitCheckbox.setValue((%material).vertLit[%layer]); MaterialEditorPropertiesWindow-->vertColorSwatch.color = (%material).vertColor[%layer]; MaterialEditorPropertiesWindow-->subSurfaceCheckbox.setValue((%material).subSurface[%layer]); - MaterialEditorPropertiesWindow-->subSurfaceColorSwatch.color = (%material).subSurfaceColor[%layer]; - MaterialEditorPropertiesWindow-->subSurfaceRolloffTextEdit.setText((%material).subSurfaceRolloff[%layer]); - MaterialEditorPropertiesWindow-->minnaertTextEdit.setText((%material).minnaertConstant[%layer]); // Animation properties MaterialEditorPropertiesWindow-->RotationAnimation.setValue(0); diff --git a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs index be7d55c39..c1f01f1a7 100644 --- a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -918,9 +918,6 @@ function MaterialEditorGui::guiSync( %this, %material ) MaterialEditorPropertiesWindow-->vertLitCheckbox.setValue((%material).vertLit[%layer]); MaterialEditorPropertiesWindow-->vertColorSwatch.color = (%material).vertColor[%layer]; MaterialEditorPropertiesWindow-->subSurfaceCheckbox.setValue((%material).subSurface[%layer]); - MaterialEditorPropertiesWindow-->subSurfaceColorSwatch.color = (%material).subSurfaceColor[%layer]; - MaterialEditorPropertiesWindow-->subSurfaceRolloffTextEdit.setText((%material).subSurfaceRolloff[%layer]); - MaterialEditorPropertiesWindow-->minnaertTextEdit.setText((%material).minnaertConstant[%layer]); // Animation properties MaterialEditorPropertiesWindow-->RotationAnimation.setValue(0); From fb7e4f92ef4e6e38819ff871cbe2f260b5bcd162 Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 25 May 2016 22:16:24 -0500 Subject: [PATCH 55/71] Adds in a GameObjects folder that lists all available game objects to the Scripted objects tab in the creator panel in the editor. --- .../worldEditor/scripts/editors/creator.ed.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs index a6507cbaf..1712097ea 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -304,6 +304,36 @@ function EWCreatorWindow::navigate( %this, %address ) %this.addShapeIcon( %obj ); } } + + //Add a separate folder for Game Objects + if(isClass("Entity")) + { + if(%address $= "") + { + %this.addFolderIcon("GameObjects"); + } + else + { + //find all GameObjectAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) + return 0; //if we didn't find ANY, just exit + + %count = %assetQuery.getCount(); + + for(%i=0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); + + if(isFile(%gameObjectAsset.TAMLFilePath)) + { + %this.addGameObjectIcon( %gameObjectAsset.gameObjectName ); + } + } + } + } } if ( %this.tab $= "Meshes" ) @@ -734,6 +764,22 @@ function EWCreatorWindow::addPrefabIcon( %this, %fullPath ) %this.contentCtrl.addGuiControl( %ctrl ); } +function EWCreatorWindow::addGameObjectIcon( %this, %gameObjectName ) +{ + %ctrl = %this.createIcon(); + + %ctrl.altCommand = "spawnGameObject( \"" @ %gameObjectName @ "\", true );"; + %ctrl.iconBitmap = EditorIconRegistry::findIconByClassName( "Prefab" ); + %ctrl.text = %gameObjectName; + %ctrl.class = "CreatorGameObjectIconBtn"; + %ctrl.tooltip = "Spawn the " @ %gameObjectName @ " GameObject"; + + %ctrl.buttonType = "radioButton"; + %ctrl.groupNum = "-1"; + + %this.contentCtrl.addGuiControl( %ctrl ); +} + function CreatorPopupMenu::onSelect( %this, %id, %text ) { %split = strreplace( %text, "/", " " ); From ec8882c3c88c28af1d56f8166679e3b20ee8059c Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 26 May 2016 01:37:14 -0500 Subject: [PATCH 56/71] Ensuring all names are the correct casing for Linux --- .../T3D/components/Animation/animationComponent.cpp | 6 +++--- .../T3D/components/Animation/animationComponent.h | 6 +++--- .../Animation/animationComponent_ScriptBinding.h | 2 +- .../source/T3D/components/Camera/CameraComponent.cpp | 6 +++--- .../source/T3D/components/Camera/CameraComponent.h | 6 +++--- .../Camera/CameraComponent_ScriptBinding.h | 2 +- .../T3D/components/Camera/CameraOrbiterComponent.cpp | 2 +- .../T3D/components/Camera/CameraOrbiterComponent.h | 4 ++-- .../Collision/CollisionComponent_ScriptBinding.h | 2 +- .../T3D/components/Collision/collisionComponent.cpp | 6 +++--- .../T3D/components/Collision/collisionComponent.h | 10 +++++----- .../T3D/components/Collision/collisionInterfaces.cpp | 4 ++-- .../T3D/components/Collision/collisionTrigger.cpp | 2 +- Engine/source/T3D/components/Component.cpp | 2 +- Engine/source/T3D/components/Component.h | 4 ++-- .../T3D/components/Game/StateMachineComponent.cpp | 2 +- .../T3D/components/Game/StateMachineComponent.h | 4 ++-- Engine/source/T3D/components/Game/stateMachine.cpp | 2 +- .../source/T3D/components/Game/triggerComponent.cpp | 4 ++-- Engine/source/T3D/components/Game/triggerComponent.h | 6 +++--- .../T3D/components/Physics/physicsBehavior.cpp | 2 +- .../source/T3D/components/Physics/physicsBehavior.h | 6 +++--- .../components/Physics/physicsComponentInterface.h | 2 +- .../components/Physics/playerControllerComponent.cpp | 4 ++-- .../components/Physics/playerControllerComponent.h | 8 ++++---- .../T3D/components/Physics/rigidBodyComponent.cpp | 4 ++-- .../T3D/components/Physics/rigidBodyComponent.h | 6 +++--- .../source/T3D/components/Render/MeshComponent.cpp | 4 ++-- Engine/source/T3D/components/Render/MeshComponent.h | 8 ++++---- .../components/Render/MeshComponent_ScriptBinding.h | 2 +- .../T3D/components/Render/renderComponentInterface.h | 2 +- Engine/source/T3D/{Entity.cpp => entity.cpp} | 8 ++++---- Engine/source/T3D/{Entity.h => entity.h} | 8 ++++---- Engine/source/T3D/gameBase/gameConnection.cpp | 4 ++-- Engine/source/T3D/gameBase/processList.cpp | 4 ++-- Engine/source/T3D/gameBase/std/stdGameProcess.cpp | 4 ++-- Engine/source/gui/controls/guiTreeViewCtrl.cpp | 2 +- Engine/source/gui/editor/inspector/entityGroup.cpp | 2 +- Engine/source/gui/editor/inspector/entityGroup.h | 2 +- Engine/source/gui/editor/inspector/mountingGroup.cpp | 6 +++--- Engine/source/gui/editor/inspector/mountingGroup.h | 4 ++-- Engine/source/scene/sceneRenderState.cpp | 4 ++-- .../{SuperToolTipDlg.ed.cs => superToolTipDlg.ed.cs} | 0 Tools/CMake/torque3d.cmake | 12 ++++++------ 44 files changed, 95 insertions(+), 95 deletions(-) rename Engine/source/T3D/{Entity.cpp => entity.cpp} (99%) rename Engine/source/T3D/{Entity.h => entity.h} (97%) rename Templates/Full/game/tools/componentEditor/scripts/{SuperToolTipDlg.ed.cs => superToolTipDlg.ed.cs} (100%) diff --git a/Engine/source/T3D/components/Animation/animationComponent.cpp b/Engine/source/T3D/components/Animation/animationComponent.cpp index a43eedd7a..5c17a2369 100644 --- a/Engine/source/T3D/components/Animation/animationComponent.cpp +++ b/Engine/source/T3D/components/Animation/animationComponent.cpp @@ -20,9 +20,9 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Animation/AnimationComponent.h" -#include "T3D/Components/Animation/AnimationComponent_ScriptBinding.h" -#include "T3D/components/Render/MeshComponent.h" +#include "T3D/components/animation/animationcomponent.h" +#include "T3D/components/animation/animationComponent_ScriptBinding.h" +#include "T3D/components/render/meshcomponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/Animation/animationComponent.h b/Engine/source/T3D/components/Animation/animationComponent.h index 7e9378899..f1c01f40c 100644 --- a/Engine/source/T3D/components/Animation/animationComponent.h +++ b/Engine/source/T3D/components/Animation/animationComponent.h @@ -24,16 +24,16 @@ #define ANIMATION_COMPONENT_H #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef _TSSHAPE_H_ #include "ts/tsShapeInstance.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef RENDER_COMPONENT_INTERFACE_H -#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" #endif class SceneRenderState; diff --git a/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h b/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h index ffba3f790..366cbb6ba 100644 --- a/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/Components/Animation/animationComponent.h" +#include "T3D/components/animation/animationcomponent.h" DefineEngineMethod(AnimationComponent, playThread, bool, (S32 slot, const char* name, bool transition, F32 transitionTime), (-1, "", true, 0.5), "@brief Start a new animation thread, or restart one that has been paused or " diff --git a/Engine/source/T3D/components/Camera/CameraComponent.cpp b/Engine/source/T3D/components/Camera/CameraComponent.cpp index 5d914084c..c42fb96ad 100644 --- a/Engine/source/T3D/components/Camera/CameraComponent.cpp +++ b/Engine/source/T3D/components/Camera/CameraComponent.cpp @@ -20,8 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/camera/CameraComponent.h" -#include "T3D/Components/Camera/CameraComponent_ScriptBinding.h" +#include "T3D/components/camera/cameracomponent.h" +#include "T3D/components/camera/cameraComponent_ScriptBinding.h" #include "platform/platform.h" #include "console/consoleTypes.h" #include "core/util/safeDelete.h" @@ -37,7 +37,7 @@ #include "T3D/gameBase/gameConnection.h" #include "T3D/gameFunctions.h" #include "math/mathUtils.h" -#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" IMPLEMENT_CALLBACK( CameraComponent, validateCameraFov, F32, (F32 fov), (fov), "@brief Called on the server when the client has requested a FOV change.\n\n" diff --git a/Engine/source/T3D/components/Camera/CameraComponent.h b/Engine/source/T3D/components/Camera/CameraComponent.h index 1e5403833..9ae7aea99 100644 --- a/Engine/source/T3D/components/Camera/CameraComponent.h +++ b/Engine/source/T3D/components/Camera/CameraComponent.h @@ -24,7 +24,7 @@ #define CAMERA_COMPONENT_H #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef _SCENERENDERSTATE_H_ #include "scene/sceneRenderState.h" @@ -33,10 +33,10 @@ #include "math/mBox.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif class SceneRenderState; diff --git a/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h b/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h index c7ed90cb1..caa6a38e7 100644 --- a/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/Components/Camera/CameraComponent.h" +#include "T3D/components/camera/cameracomponent.h" //Basically, this only exists for backwards compatibility for parts of the editors ConsoleMethod(CameraComponent, getMode, const char*, 2, 2, "() - We get the first behavior of the requested type on our owner object.\n" diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp index 6b7866873..af91347ab 100644 --- a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp +++ b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Camera/CameraOrbiterComponent.h" +#include "T3D/components/camera/cameraOrbitercomponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h index c13029f37..b4b495a1d 100644 --- a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h +++ b/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h @@ -24,10 +24,10 @@ #define CAMERA_ORBITER_COMPONENT_H #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef CAMERA_COMPONENT_H -#include "T3D/Components/camera/cameraComponent.h" +#include "T3D/components/camera/cameracomponent.h" #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h b/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h index f822bfb76..3d7bf6bb3 100644 --- a/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/Components/Collision/CollisionComponent.h" +#include "T3D/components/collision/collisioncomponent.h" #include "materials/baseMatInstance.h" DefineConsoleMethod(CollisionComponent, getNumberOfContacts, S32, (), , diff --git a/Engine/source/T3D/components/Collision/collisionComponent.cpp b/Engine/source/T3D/components/Collision/collisionComponent.cpp index 1ce851b0f..0698b4b39 100644 --- a/Engine/source/T3D/components/Collision/collisionComponent.cpp +++ b/Engine/source/T3D/components/Collision/collisionComponent.cpp @@ -20,9 +20,9 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Collision/collisionComponent.h" -#include "T3D/Components/Collision/collisionComponent_ScriptBinding.h" -#include "T3D/Components/Physics/physicsBehavior.h" +#include "T3D/components/collision/collisioncomponent.h" +#include "T3D/components/collision/collisionComponent_ScriptBinding.h" +#include "T3D/components/physics/physicsBehavior.h" #include "console/consoleTypes.h" #include "core/util/safeDelete.h" #include "core/resourceManager.h" diff --git a/Engine/source/T3D/components/Collision/collisionComponent.h b/Engine/source/T3D/components/Collision/collisionComponent.h index aa05dc109..2d1be3098 100644 --- a/Engine/source/T3D/components/Collision/collisionComponent.h +++ b/Engine/source/T3D/components/Collision/collisionComponent.h @@ -36,19 +36,19 @@ #include "math/mBox.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif #ifndef COLLISION_INTERFACES_H -#include "T3D/Components/collision/collisionInterfaces.h" +#include "T3D/components/collision/collisionInterfaces.h" #endif #ifndef RENDER_COMPONENT_INTERFACE_H -#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" #endif #ifndef PHYSICS_COMPONENT_INTERFACE_H -#include "T3D/Components/physics/physicsComponentInterface.h" +#include "T3D/components/physics/physicsComponentInterface.h" #endif #ifndef _T3D_PHYSICSCOMMON_H_ #include "T3D/physics/physicsCommon.h" diff --git a/Engine/source/T3D/components/Collision/collisionInterfaces.cpp b/Engine/source/T3D/components/Collision/collisionInterfaces.cpp index 4fba3e3c0..9ddf01a40 100644 --- a/Engine/source/T3D/components/Collision/collisionInterfaces.cpp +++ b/Engine/source/T3D/components/Collision/collisionInterfaces.cpp @@ -20,9 +20,9 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/collision/collisionInterfaces.h" +#include "T3D/components/collision/collisionInterfaces.h" #include "scene/sceneObject.h" -#include "T3D/Entity.h" +#include "T3D/entity.h" #include "console/engineAPI.h" #include "T3D/trigger.h" #include "materials/baseMatInstance.h" diff --git a/Engine/source/T3D/components/Collision/collisionTrigger.cpp b/Engine/source/T3D/components/Collision/collisionTrigger.cpp index ed1e86675..7d1f50706 100644 --- a/Engine/source/T3D/components/Collision/collisionTrigger.cpp +++ b/Engine/source/T3D/components/Collision/collisionTrigger.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "platform/platform.h" -#include "T3D/Components/Collision/CollisionTrigger.h" +#include "T3D/components/collision/collisionTrigger.h" #include "scene/sceneRenderState.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/Component.cpp b/Engine/source/T3D/components/Component.cpp index 0c4475b79..607df5e30 100644 --- a/Engine/source/T3D/components/Component.cpp +++ b/Engine/source/T3D/components/Component.cpp @@ -23,7 +23,7 @@ #include "platform/platform.h" #include "console/simBase.h" #include "console/consoleTypes.h" -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #include "core/util/safeDelete.h" #include "core/resourceManager.h" #include "core/stream/fileStream.h" diff --git a/Engine/source/T3D/components/Component.h b/Engine/source/T3D/components/Component.h index 98eea53bc..0259bacd0 100644 --- a/Engine/source/T3D/components/Component.h +++ b/Engine/source/T3D/components/Component.h @@ -27,10 +27,10 @@ #include "sim/netObject.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif class Entity; diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.cpp b/Engine/source/T3D/components/Game/StateMachineComponent.cpp index 68058af59..572f845e9 100644 --- a/Engine/source/T3D/components/Game/StateMachineComponent.cpp +++ b/Engine/source/T3D/components/Game/StateMachineComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/game/StateMachineComponent.h" +#include "T3D/components/game/StateMachinecomponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.h b/Engine/source/T3D/components/Game/StateMachineComponent.h index 00fc4c27e..5d4051075 100644 --- a/Engine/source/T3D/components/Game/StateMachineComponent.h +++ b/Engine/source/T3D/components/Game/StateMachineComponent.h @@ -24,10 +24,10 @@ #define STATE_MACHINE_COMPONENT_H #ifndef COMPONENT_H - #include "T3D/Components/Component.h" + #include "T3D/components/component.h" #endif #ifndef STATE_MACHINE_H -#include "T3D/components/Game/stateMachine.h" +#include "T3D/components/game/stateMachine.h" #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Engine/source/T3D/components/Game/stateMachine.cpp b/Engine/source/T3D/components/Game/stateMachine.cpp index 867e9cb19..335b69db3 100644 --- a/Engine/source/T3D/components/Game/stateMachine.cpp +++ b/Engine/source/T3D/components/Game/stateMachine.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Game/stateMachine.h" +#include "T3D/components/game/stateMachine.h" StateMachine::StateMachine() { diff --git a/Engine/source/T3D/components/Game/triggerComponent.cpp b/Engine/source/T3D/components/Game/triggerComponent.cpp index df61859ce..a9697af50 100644 --- a/Engine/source/T3D/components/Game/triggerComponent.cpp +++ b/Engine/source/T3D/components/Game/triggerComponent.cpp @@ -3,7 +3,7 @@ // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "console/consoleTypes.h" -#include "T3D/Components/game/TriggerComponent.h" +#include "T3D/components/game/Triggercomponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" @@ -11,7 +11,7 @@ #include "console/engineAPI.h" #include "sim/netConnection.h" #include "T3D/gameBase/gameConnection.h" -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #include "math/mathUtils.h" #include "collision/concretePolyList.h" #include "collision/clippedPolyList.h" diff --git a/Engine/source/T3D/components/Game/triggerComponent.h b/Engine/source/T3D/components/Game/triggerComponent.h index 3b790f27e..bac45b62a 100644 --- a/Engine/source/T3D/components/Game/triggerComponent.h +++ b/Engine/source/T3D/components/Game/triggerComponent.h @@ -6,15 +6,15 @@ #define _TRIGGER_COMPONENT_H_ #ifndef _COMPONENT_H_ -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef _ENTITY_H_ -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef _COLLISION_INTERFACES_H_ -#include "T3D/Components/collision/collisionInterfaces.h" +#include "T3D/components/collision/collisionInterfaces.h" #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.cpp b/Engine/source/T3D/components/Physics/physicsBehavior.cpp index 3737abc56..f281192c0 100644 --- a/Engine/source/T3D/components/Physics/physicsBehavior.cpp +++ b/Engine/source/T3D/components/Physics/physicsBehavior.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Physics/physicsBehavior.h" +#include "T3D/components/physics/physicsBehavior.h" #include "platform/platform.h" #include "console/consoleTypes.h" #include "core/util/safeDelete.h" diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.h b/Engine/source/T3D/components/Physics/physicsBehavior.h index 707fc15e5..bc09f3108 100644 --- a/Engine/source/T3D/components/Physics/physicsBehavior.h +++ b/Engine/source/T3D/components/Physics/physicsBehavior.h @@ -5,7 +5,7 @@ #ifndef _PHYSICSBEHAVIOR_H_ #define _PHYSICSBEHAVIOR_H_ -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #ifndef __RESOURCE_H__ #include "core/resource.h" @@ -20,7 +20,7 @@ #include "math/mBox.h" #endif #ifndef _ENTITY_H_ -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef _CONVEX_H_ #include "collision/convex.h" @@ -36,7 +36,7 @@ #endif #ifndef _RENDER_COMPONENT_INTERFACE_H_ -#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" #endif class TSShapeInstance; diff --git a/Engine/source/T3D/components/Physics/physicsComponentInterface.h b/Engine/source/T3D/components/Physics/physicsComponentInterface.h index 0f5234816..3d233a222 100644 --- a/Engine/source/T3D/components/Physics/physicsComponentInterface.h +++ b/Engine/source/T3D/components/Physics/physicsComponentInterface.h @@ -24,7 +24,7 @@ #define PHYSICS_COMPONENT_INTERFACE_H #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif class PhysicsComponentInterface : public Interface diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.cpp b/Engine/source/T3D/components/Physics/playerControllerComponent.cpp index bb5217659..53283ac34 100644 --- a/Engine/source/T3D/components/Physics/playerControllerComponent.cpp +++ b/Engine/source/T3D/components/Physics/playerControllerComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/Physics/playerControllerComponent.h" +#include "T3D/components/physics/playerControllercomponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" #include "core/util/safeDelete.h" @@ -37,7 +37,7 @@ #include "collision/collision.h" #include "T3D/physics/physicsPlayer.h" #include "T3D/physics/physicsPlugin.h" -#include "T3D/Components/Collision/collisionInterfaces.h" +#include "T3D/components/collision/collisionInterfaces.h" #include "T3D/trigger.h" #include "T3D/components/collision/collisionTrigger.h" diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.h b/Engine/source/T3D/components/Physics/playerControllerComponent.h index 903d0f118..d38410888 100644 --- a/Engine/source/T3D/components/Physics/playerControllerComponent.h +++ b/Engine/source/T3D/components/Physics/playerControllerComponent.h @@ -24,7 +24,7 @@ #define PLAYER_CONTORLLER_COMPONENT_H #ifndef PHYSICSBEHAVIOR_H -#include "T3D/Components/Physics/physicsBehavior.h" +#include "T3D/components/physics/physicsBehavior.h" #endif #ifndef __RESOURCE_H__ #include "core/resource.h" @@ -39,7 +39,7 @@ #include "math/mBox.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef _CONVEX_H_ #include "collision/convex.h" @@ -54,10 +54,10 @@ #include "T3D/physics/physicsWorld.h" #endif #ifndef PHYSICS_COMPONENT_INTERFACE_H -#include "T3D/Components/physics/physicsComponentInterface.h" +#include "T3D/components/physics/physicsComponentInterface.h" #endif #ifndef COLLISION_INTERFACES_H -#include "T3D/Components/collision/collisionInterfaces.h" +#include "T3D/components/collision/collisionInterfaces.h" #endif class SceneRenderState; diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp b/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp index e2d22fa25..bdabafe3c 100644 --- a/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp +++ b/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/Components/physics/RigidBodyComponent.h" +#include "T3D/components/physics/rigidBodycomponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" @@ -31,7 +31,7 @@ #include "T3D/physics/physicsPlugin.h" #include "T3D/physics/physicsWorld.h" #include "T3D/physics/physicsCollision.h" -#include "T3D/Components/Collision/collisionComponent.h" +#include "T3D/components/collision/collisioncomponent.h" bool RigidBodyComponent::smNoCorrections = false; bool RigidBodyComponent::smNoSmoothing = false; diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.h b/Engine/source/T3D/components/Physics/rigidBodyComponent.h index 85b98379d..3c9aea61d 100644 --- a/Engine/source/T3D/components/Physics/rigidBodyComponent.h +++ b/Engine/source/T3D/components/Physics/rigidBodyComponent.h @@ -24,16 +24,16 @@ #define RIGID_BODY_COMPONENT_H #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef _T3D_PHYSICSCOMMON_H_ #include "T3D/physics/physicsCommon.h" #endif #ifndef COLLISION_COMPONENT_H -#include "T3D/Components/collision/collisionComponent.h" +#include "T3D/components/collision/collisioncomponent.h" #endif #ifndef PHYSICS_COMPONENT_INTERFACE_H -#include "T3D/Components/physics/physicsComponentInterface.h" +#include "T3D/components/physics/physicsComponentInterface.h" #endif class PhysicsBody; diff --git a/Engine/source/T3D/components/Render/MeshComponent.cpp b/Engine/source/T3D/components/Render/MeshComponent.cpp index 9444fa917..e84c43ace 100644 --- a/Engine/source/T3D/components/Render/MeshComponent.cpp +++ b/Engine/source/T3D/components/Render/MeshComponent.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "platform/platform.h" #include "console/consoleTypes.h" -#include "T3D/Components/Render/MeshComponent.h" +#include "T3D/components/render/meshcomponent.h" #include "core/util/safeDelete.h" #include "core/resourceManager.h" #include "core/stream/fileStream.h" @@ -44,7 +44,7 @@ #include "materials/materialManager.h" #include "materials/matInstance.h" #include "core/strings/findMatch.h" -#include "T3D/components/Render/MeshComponent_ScriptBinding.h" +#include "T3D/components/render/meshComponent_ScriptBinding.h" ////////////////////////////////////////////////////////////////////////// // Constructor/Destructor diff --git a/Engine/source/T3D/components/Render/MeshComponent.h b/Engine/source/T3D/components/Render/MeshComponent.h index e06a0ccee..8aa02a64d 100644 --- a/Engine/source/T3D/components/Render/MeshComponent.h +++ b/Engine/source/T3D/components/Render/MeshComponent.h @@ -24,7 +24,7 @@ #define STATIC_MESH_COMPONENT_H #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef __RESOURCE_H__ #include "core/resource.h" @@ -39,16 +39,16 @@ #include "math/mBox.h" #endif #ifndef ENTITY_H -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif #ifndef _NETSTRINGTABLE_H_ #include "sim/netStringTable.h" #endif #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif #ifndef RENDER_COMPONENT_INTERFACE_H -#include "T3D/Components/Render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" #endif #ifndef _ASSET_PTR_H_ #include "assets/assetPtr.h" diff --git a/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h b/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h index 08dd6dbfd..8181b3e7d 100644 --- a/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/components/Render/MeshComponent.h" +#include "T3D/components/render/meshcomponent.h" #include "scene/sceneObject.h" #include "math/mTransform.h" diff --git a/Engine/source/T3D/components/Render/renderComponentInterface.h b/Engine/source/T3D/components/Render/renderComponentInterface.h index 67d9a2f8f..6948f3866 100644 --- a/Engine/source/T3D/components/Render/renderComponentInterface.h +++ b/Engine/source/T3D/components/Render/renderComponentInterface.h @@ -30,7 +30,7 @@ #include "ts/TSShapeInstance.h" #endif #ifndef CORE_INTERFACES_H -#include "T3D/Components/coreInterfaces.h" +#include "T3D/components/coreInterfaces.h" #endif class RenderComponentInterface : public Interface < RenderComponentInterface > diff --git a/Engine/source/T3D/Entity.cpp b/Engine/source/T3D/entity.cpp similarity index 99% rename from Engine/source/T3D/Entity.cpp rename to Engine/source/T3D/entity.cpp index 680f098d9..bff589570 100644 --- a/Engine/source/T3D/Entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "platform/platform.h" -#include "T3D/Entity.h" +#include "T3D/entity.h" #include "core/stream/bitStream.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" @@ -34,9 +34,9 @@ #include "math/mathIO.h" #include "math/mTransform.h" -#include "T3D/Components/coreInterfaces.h" -#include "T3D/Components/render/renderComponentInterface.h" -#include "T3D/Components/Collision/collisionInterfaces.h" +#include "T3D/components/coreInterfaces.h" +#include "T3D/components/render/renderComponentInterface.h" +#include "T3D/components/collision/collisionInterfaces.h" #include "gui/controls/guiTreeViewCtrl.h" diff --git a/Engine/source/T3D/Entity.h b/Engine/source/T3D/entity.h similarity index 97% rename from Engine/source/T3D/Entity.h rename to Engine/source/T3D/entity.h index e2a35bf9f..faaaea4cf 100644 --- a/Engine/source/T3D/Entity.h +++ b/Engine/source/T3D/entity.h @@ -30,7 +30,7 @@ #include "T3D/gameBase/moveManager.h" #endif #ifndef COMPONENT_H -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #endif #ifndef MROTATION_H #include "math/mRotation.h" @@ -61,10 +61,10 @@ private: bool mInitialized; - Signal< void(Component*) > Entity::onComponentAdded; - Signal< void(Component*) > Entity::onComponentRemoved; + Signal< void(Component*) > onComponentAdded; + Signal< void(Component*) > onComponentRemoved; - Signal< void(MatrixF*) > Entity::onTransformSet; + Signal< void(MatrixF*) > onTransformSet; protected: diff --git a/Engine/source/T3D/gameBase/gameConnection.cpp b/Engine/source/T3D/gameBase/gameConnection.cpp index 05ce14151..0f36d6326 100644 --- a/Engine/source/T3D/gameBase/gameConnection.cpp +++ b/Engine/source/T3D/gameBase/gameConnection.cpp @@ -40,8 +40,8 @@ #include "math/mTransform.h" #ifdef TORQUE_EXPERIMENTAL_EC -#include "T3D/Entity.h" -#include "T3D/Components/coreInterfaces.h" +#include "T3D/entity.h" +#include "T3D/components/coreInterfaces.h" #endif #ifdef TORQUE_HIFI_NET diff --git a/Engine/source/T3D/gameBase/processList.cpp b/Engine/source/T3D/gameBase/processList.cpp index e012c4c02..8e524a205 100644 --- a/Engine/source/T3D/gameBase/processList.cpp +++ b/Engine/source/T3D/gameBase/processList.cpp @@ -28,8 +28,8 @@ #include "console/consoleTypes.h" #ifdef TORQUE_EXPERIMENTAL_EC -#include "T3D/Components/coreInterfaces.h" -#include "T3D/Components/Component.h" +#include "T3D/components/coreInterfaces.h" +#include "T3D/components/component.h" #endif //---------------------------------------------------------------------------- diff --git a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp index 88d0891d5..b9c3a27f1 100644 --- a/Engine/source/T3D/gameBase/std/stdGameProcess.cpp +++ b/Engine/source/T3D/gameBase/std/stdGameProcess.cpp @@ -38,8 +38,8 @@ #include "T3D/fx/cameraFXMgr.h" #ifdef TORQUE_EXPERIMENTAL_EC -#include "T3D/Components/coreInterfaces.h" -#include "T3D/Components/Component.h" +#include "T3D/components/coreInterfaces.h" +#include "T3D/components/component.h" #endif MODULE_BEGIN( ProcessList ) diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index b96418845..f8bc41c2e 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -37,7 +37,7 @@ #endif #include "console/engineAPI.h" #ifdef TORQUE_EXPERIMENTAL_EC -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif IMPLEMENT_CONOBJECT(GuiTreeViewCtrl); diff --git a/Engine/source/gui/editor/inspector/entityGroup.cpp b/Engine/source/gui/editor/inspector/entityGroup.cpp index 7c7bd2762..2fd6e6172 100644 --- a/Engine/source/gui/editor/inspector/entityGroup.cpp +++ b/Engine/source/gui/editor/inspector/entityGroup.cpp @@ -24,7 +24,7 @@ #include "gui/editor/guiInspector.h" #include "gui/editor/inspector/entityGroup.h" #include "core/strings/stringUnit.h" -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #include "console/engineAPI.h" diff --git a/Engine/source/gui/editor/inspector/entityGroup.h b/Engine/source/gui/editor/inspector/entityGroup.h index 327539846..00944cda1 100644 --- a/Engine/source/gui/editor/inspector/entityGroup.h +++ b/Engine/source/gui/editor/inspector/entityGroup.h @@ -25,7 +25,7 @@ #include "gui/editor/inspector/group.h" #include "console/simFieldDictionary.h" -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #include "gui/controls/guiPopUpCtrlEx.h" class GuiInspectorEntityGroup : public GuiInspectorGroup diff --git a/Engine/source/gui/editor/inspector/mountingGroup.cpp b/Engine/source/gui/editor/inspector/mountingGroup.cpp index bcfa19fa9..bce47f66a 100644 --- a/Engine/source/gui/editor/inspector/mountingGroup.cpp +++ b/Engine/source/gui/editor/inspector/mountingGroup.cpp @@ -24,11 +24,11 @@ #include "gui/editor/guiInspector.h" #include "gui/editor/inspector/mountingGroup.h" #include "core/strings/stringUnit.h" -#include "T3D/Entity.h" -#include "T3D/Components/Component.h" +#include "T3D/entity.h" +#include "T3D/components/component.h" //Need this to get node lists -#include "T3D/Components/render/renderComponentInterface.h" +#include "T3D/components/render/renderComponentInterface.h" IMPLEMENT_CONOBJECT(GuiInspectorMountingGroup); diff --git a/Engine/source/gui/editor/inspector/mountingGroup.h b/Engine/source/gui/editor/inspector/mountingGroup.h index da8ed91a6..5c4bdac75 100644 --- a/Engine/source/gui/editor/inspector/mountingGroup.h +++ b/Engine/source/gui/editor/inspector/mountingGroup.h @@ -25,7 +25,7 @@ #include "gui/editor/inspector/group.h" #include "console/simFieldDictionary.h" -#include "T3D/Components/Component.h" +#include "T3D/components/component.h" #include "gui/controls/guiPopUpCtrlEx.h" #ifndef _GUI_INSPECTOR_TYPES_H_ @@ -33,7 +33,7 @@ #endif #ifndef _ENTITY_H_ -#include "T3D/Entity.h" +#include "T3D/entity.h" #endif class GuiInspectorMountingGroup; diff --git a/Engine/source/scene/sceneRenderState.cpp b/Engine/source/scene/sceneRenderState.cpp index 5d05e809d..47bb8b440 100644 --- a/Engine/source/scene/sceneRenderState.cpp +++ b/Engine/source/scene/sceneRenderState.cpp @@ -27,8 +27,8 @@ #include "math/util/matrixSet.h" #ifdef TORQUE_EXPERIMENTAL_EC -#include "T3D/Components/render/renderComponentInterface.h" -#include "T3D/Components/Component.h" +#include "T3D/components/render/renderComponentInterface.h" +#include "T3D/components/component.h" #endif //----------------------------------------------------------------------------- diff --git a/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs b/Templates/Full/game/tools/componentEditor/scripts/superToolTipDlg.ed.cs similarity index 100% rename from Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs rename to Templates/Full/game/tools/componentEditor/scripts/superToolTipDlg.ed.cs diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index bb0b274cb..fc7e2a920 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -274,12 +274,12 @@ addPath("${srcDir}/T3D/turret") if( TORQUE_EXPERIMENTAL_EC ) addPath("${srcDir}/T3D/components/") - addPath("${srcDir}/T3D/components/animation") - addPath("${srcDir}/T3D/components/camera") - addPath("${srcDir}/T3D/components/collision") - addPath("${srcDir}/T3D/components/game") - addPath("${srcDir}/T3D/components/physics") - addPath("${srcDir}/T3D/components/render") + addPath("${srcDir}/T3D/components/Animation") + addPath("${srcDir}/T3D/components/Camera") + addPath("${srcDir}/T3D/components/Collision") + addPath("${srcDir}/T3D/components/Game") + addPath("${srcDir}/T3D/components/Physics") + addPath("${srcDir}/T3D/components/Render") endif() addPath("${srcDir}/main/") From 93e767f0c5fa3db7960448c29ba9595f8d3a473d Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 26 May 2016 01:39:06 -0500 Subject: [PATCH 57/71] Additional casing fixes. --- Engine/source/T3D/components/{Component.cpp => component.cpp} | 0 Engine/source/T3D/components/{Component.h => component.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Engine/source/T3D/components/{Component.cpp => component.cpp} (100%) rename Engine/source/T3D/components/{Component.h => component.h} (100%) diff --git a/Engine/source/T3D/components/Component.cpp b/Engine/source/T3D/components/component.cpp similarity index 100% rename from Engine/source/T3D/components/Component.cpp rename to Engine/source/T3D/components/component.cpp diff --git a/Engine/source/T3D/components/Component.h b/Engine/source/T3D/components/component.h similarity index 100% rename from Engine/source/T3D/components/Component.h rename to Engine/source/T3D/components/component.h From f5e86a83b51a8259100085688aae609cb0f3591a Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 26 May 2016 13:56:19 -0500 Subject: [PATCH 58/71] Other renames to ensure linux case-sensitivity compliance and casing format consistency. --- .../components/{Animation => animation}/animationComponent.cpp | 0 .../T3D/components/{Animation => animation}/animationComponent.h | 0 .../{Animation => animation}/animationComponent_ScriptBinding.h | 0 .../{Camera/CameraComponent.cpp => camera/cameraComponent.cpp} | 0 .../{Camera/CameraComponent.h => camera/cameraComponent.h} | 0 .../cameraComponent_ScriptBinding.h} | 0 .../cameraOrbiterComponent.cpp} | 0 .../CameraOrbiterComponent.h => camera/cameraOrbiterComponent.h} | 0 .../components/{Collision => collision}/collisionComponent.cpp | 0 .../T3D/components/{Collision => collision}/collisionComponent.h | 0 .../collisionComponent_ScriptBinding.h} | 0 .../components/{Collision => collision}/collisionInterfaces.cpp | 0 .../T3D/components/{Collision => collision}/collisionInterfaces.h | 0 .../T3D/components/{Collision => collision}/collisionTrigger.cpp | 0 .../T3D/components/{Collision => collision}/collisionTrigger.h | 0 Engine/source/T3D/components/{Game => game}/stateMachine.cpp | 0 Engine/source/T3D/components/{Game => game}/stateMachine.h | 0 .../StateMachineComponent.cpp => game/stateMachineComponent.cpp} | 0 .../StateMachineComponent.h => game/stateMachineComponent.h} | 0 Engine/source/T3D/components/{Game => game}/triggerComponent.cpp | 0 Engine/source/T3D/components/{Game => game}/triggerComponent.h | 0 .../T3D/components/{Physics => physics}/physicsBehavior.cpp | 0 .../source/T3D/components/{Physics => physics}/physicsBehavior.h | 0 .../components/{Physics => physics}/physicsComponentInterface.cpp | 0 .../components/{Physics => physics}/physicsComponentInterface.h | 0 .../components/{Physics => physics}/playerControllerComponent.cpp | 0 .../components/{Physics => physics}/playerControllerComponent.h | 0 .../T3D/components/{Physics => physics}/rigidBodyComponent.cpp | 0 .../T3D/components/{Physics => physics}/rigidBodyComponent.h | 0 .../{Render/MeshComponent.cpp => render/meshComponent.cpp} | 0 .../components/{Render/MeshComponent.h => render/meshComponent.h} | 0 .../meshComponent_ScriptBinding.h} | 0 .../T3D/components/{Render => render}/renderComponentInterface.h | 0 33 files changed, 0 insertions(+), 0 deletions(-) rename Engine/source/T3D/components/{Animation => animation}/animationComponent.cpp (100%) rename Engine/source/T3D/components/{Animation => animation}/animationComponent.h (100%) rename Engine/source/T3D/components/{Animation => animation}/animationComponent_ScriptBinding.h (100%) rename Engine/source/T3D/components/{Camera/CameraComponent.cpp => camera/cameraComponent.cpp} (100%) rename Engine/source/T3D/components/{Camera/CameraComponent.h => camera/cameraComponent.h} (100%) rename Engine/source/T3D/components/{Camera/CameraComponent_ScriptBinding.h => camera/cameraComponent_ScriptBinding.h} (100%) rename Engine/source/T3D/components/{Camera/CameraOrbiterComponent.cpp => camera/cameraOrbiterComponent.cpp} (100%) rename Engine/source/T3D/components/{Camera/CameraOrbiterComponent.h => camera/cameraOrbiterComponent.h} (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionComponent.cpp (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionComponent.h (100%) rename Engine/source/T3D/components/{Collision/CollisionComponent_ScriptBinding.h => collision/collisionComponent_ScriptBinding.h} (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionInterfaces.cpp (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionInterfaces.h (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionTrigger.cpp (100%) rename Engine/source/T3D/components/{Collision => collision}/collisionTrigger.h (100%) rename Engine/source/T3D/components/{Game => game}/stateMachine.cpp (100%) rename Engine/source/T3D/components/{Game => game}/stateMachine.h (100%) rename Engine/source/T3D/components/{Game/StateMachineComponent.cpp => game/stateMachineComponent.cpp} (100%) rename Engine/source/T3D/components/{Game/StateMachineComponent.h => game/stateMachineComponent.h} (100%) rename Engine/source/T3D/components/{Game => game}/triggerComponent.cpp (100%) rename Engine/source/T3D/components/{Game => game}/triggerComponent.h (100%) rename Engine/source/T3D/components/{Physics => physics}/physicsBehavior.cpp (100%) rename Engine/source/T3D/components/{Physics => physics}/physicsBehavior.h (100%) rename Engine/source/T3D/components/{Physics => physics}/physicsComponentInterface.cpp (100%) rename Engine/source/T3D/components/{Physics => physics}/physicsComponentInterface.h (100%) rename Engine/source/T3D/components/{Physics => physics}/playerControllerComponent.cpp (100%) rename Engine/source/T3D/components/{Physics => physics}/playerControllerComponent.h (100%) rename Engine/source/T3D/components/{Physics => physics}/rigidBodyComponent.cpp (100%) rename Engine/source/T3D/components/{Physics => physics}/rigidBodyComponent.h (100%) rename Engine/source/T3D/components/{Render/MeshComponent.cpp => render/meshComponent.cpp} (100%) rename Engine/source/T3D/components/{Render/MeshComponent.h => render/meshComponent.h} (100%) rename Engine/source/T3D/components/{Render/MeshComponent_ScriptBinding.h => render/meshComponent_ScriptBinding.h} (100%) rename Engine/source/T3D/components/{Render => render}/renderComponentInterface.h (100%) diff --git a/Engine/source/T3D/components/Animation/animationComponent.cpp b/Engine/source/T3D/components/animation/animationComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Animation/animationComponent.cpp rename to Engine/source/T3D/components/animation/animationComponent.cpp diff --git a/Engine/source/T3D/components/Animation/animationComponent.h b/Engine/source/T3D/components/animation/animationComponent.h similarity index 100% rename from Engine/source/T3D/components/Animation/animationComponent.h rename to Engine/source/T3D/components/animation/animationComponent.h diff --git a/Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h b/Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h similarity index 100% rename from Engine/source/T3D/components/Animation/animationComponent_ScriptBinding.h rename to Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h diff --git a/Engine/source/T3D/components/Camera/CameraComponent.cpp b/Engine/source/T3D/components/camera/cameraComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Camera/CameraComponent.cpp rename to Engine/source/T3D/components/camera/cameraComponent.cpp diff --git a/Engine/source/T3D/components/Camera/CameraComponent.h b/Engine/source/T3D/components/camera/cameraComponent.h similarity index 100% rename from Engine/source/T3D/components/Camera/CameraComponent.h rename to Engine/source/T3D/components/camera/cameraComponent.h diff --git a/Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h b/Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h similarity index 100% rename from Engine/source/T3D/components/Camera/CameraComponent_ScriptBinding.h rename to Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp b/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Camera/CameraOrbiterComponent.cpp rename to Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp diff --git a/Engine/source/T3D/components/Camera/CameraOrbiterComponent.h b/Engine/source/T3D/components/camera/cameraOrbiterComponent.h similarity index 100% rename from Engine/source/T3D/components/Camera/CameraOrbiterComponent.h rename to Engine/source/T3D/components/camera/cameraOrbiterComponent.h diff --git a/Engine/source/T3D/components/Collision/collisionComponent.cpp b/Engine/source/T3D/components/collision/collisionComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Collision/collisionComponent.cpp rename to Engine/source/T3D/components/collision/collisionComponent.cpp diff --git a/Engine/source/T3D/components/Collision/collisionComponent.h b/Engine/source/T3D/components/collision/collisionComponent.h similarity index 100% rename from Engine/source/T3D/components/Collision/collisionComponent.h rename to Engine/source/T3D/components/collision/collisionComponent.h diff --git a/Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h b/Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h similarity index 100% rename from Engine/source/T3D/components/Collision/CollisionComponent_ScriptBinding.h rename to Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h diff --git a/Engine/source/T3D/components/Collision/collisionInterfaces.cpp b/Engine/source/T3D/components/collision/collisionInterfaces.cpp similarity index 100% rename from Engine/source/T3D/components/Collision/collisionInterfaces.cpp rename to Engine/source/T3D/components/collision/collisionInterfaces.cpp diff --git a/Engine/source/T3D/components/Collision/collisionInterfaces.h b/Engine/source/T3D/components/collision/collisionInterfaces.h similarity index 100% rename from Engine/source/T3D/components/Collision/collisionInterfaces.h rename to Engine/source/T3D/components/collision/collisionInterfaces.h diff --git a/Engine/source/T3D/components/Collision/collisionTrigger.cpp b/Engine/source/T3D/components/collision/collisionTrigger.cpp similarity index 100% rename from Engine/source/T3D/components/Collision/collisionTrigger.cpp rename to Engine/source/T3D/components/collision/collisionTrigger.cpp diff --git a/Engine/source/T3D/components/Collision/collisionTrigger.h b/Engine/source/T3D/components/collision/collisionTrigger.h similarity index 100% rename from Engine/source/T3D/components/Collision/collisionTrigger.h rename to Engine/source/T3D/components/collision/collisionTrigger.h diff --git a/Engine/source/T3D/components/Game/stateMachine.cpp b/Engine/source/T3D/components/game/stateMachine.cpp similarity index 100% rename from Engine/source/T3D/components/Game/stateMachine.cpp rename to Engine/source/T3D/components/game/stateMachine.cpp diff --git a/Engine/source/T3D/components/Game/stateMachine.h b/Engine/source/T3D/components/game/stateMachine.h similarity index 100% rename from Engine/source/T3D/components/Game/stateMachine.h rename to Engine/source/T3D/components/game/stateMachine.h diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.cpp b/Engine/source/T3D/components/game/stateMachineComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Game/StateMachineComponent.cpp rename to Engine/source/T3D/components/game/stateMachineComponent.cpp diff --git a/Engine/source/T3D/components/Game/StateMachineComponent.h b/Engine/source/T3D/components/game/stateMachineComponent.h similarity index 100% rename from Engine/source/T3D/components/Game/StateMachineComponent.h rename to Engine/source/T3D/components/game/stateMachineComponent.h diff --git a/Engine/source/T3D/components/Game/triggerComponent.cpp b/Engine/source/T3D/components/game/triggerComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Game/triggerComponent.cpp rename to Engine/source/T3D/components/game/triggerComponent.cpp diff --git a/Engine/source/T3D/components/Game/triggerComponent.h b/Engine/source/T3D/components/game/triggerComponent.h similarity index 100% rename from Engine/source/T3D/components/Game/triggerComponent.h rename to Engine/source/T3D/components/game/triggerComponent.h diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.cpp b/Engine/source/T3D/components/physics/physicsBehavior.cpp similarity index 100% rename from Engine/source/T3D/components/Physics/physicsBehavior.cpp rename to Engine/source/T3D/components/physics/physicsBehavior.cpp diff --git a/Engine/source/T3D/components/Physics/physicsBehavior.h b/Engine/source/T3D/components/physics/physicsBehavior.h similarity index 100% rename from Engine/source/T3D/components/Physics/physicsBehavior.h rename to Engine/source/T3D/components/physics/physicsBehavior.h diff --git a/Engine/source/T3D/components/Physics/physicsComponentInterface.cpp b/Engine/source/T3D/components/physics/physicsComponentInterface.cpp similarity index 100% rename from Engine/source/T3D/components/Physics/physicsComponentInterface.cpp rename to Engine/source/T3D/components/physics/physicsComponentInterface.cpp diff --git a/Engine/source/T3D/components/Physics/physicsComponentInterface.h b/Engine/source/T3D/components/physics/physicsComponentInterface.h similarity index 100% rename from Engine/source/T3D/components/Physics/physicsComponentInterface.h rename to Engine/source/T3D/components/physics/physicsComponentInterface.h diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.cpp b/Engine/source/T3D/components/physics/playerControllerComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Physics/playerControllerComponent.cpp rename to Engine/source/T3D/components/physics/playerControllerComponent.cpp diff --git a/Engine/source/T3D/components/Physics/playerControllerComponent.h b/Engine/source/T3D/components/physics/playerControllerComponent.h similarity index 100% rename from Engine/source/T3D/components/Physics/playerControllerComponent.h rename to Engine/source/T3D/components/physics/playerControllerComponent.h diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.cpp b/Engine/source/T3D/components/physics/rigidBodyComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Physics/rigidBodyComponent.cpp rename to Engine/source/T3D/components/physics/rigidBodyComponent.cpp diff --git a/Engine/source/T3D/components/Physics/rigidBodyComponent.h b/Engine/source/T3D/components/physics/rigidBodyComponent.h similarity index 100% rename from Engine/source/T3D/components/Physics/rigidBodyComponent.h rename to Engine/source/T3D/components/physics/rigidBodyComponent.h diff --git a/Engine/source/T3D/components/Render/MeshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp similarity index 100% rename from Engine/source/T3D/components/Render/MeshComponent.cpp rename to Engine/source/T3D/components/render/meshComponent.cpp diff --git a/Engine/source/T3D/components/Render/MeshComponent.h b/Engine/source/T3D/components/render/meshComponent.h similarity index 100% rename from Engine/source/T3D/components/Render/MeshComponent.h rename to Engine/source/T3D/components/render/meshComponent.h diff --git a/Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h b/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h similarity index 100% rename from Engine/source/T3D/components/Render/MeshComponent_ScriptBinding.h rename to Engine/source/T3D/components/render/meshComponent_ScriptBinding.h diff --git a/Engine/source/T3D/components/Render/renderComponentInterface.h b/Engine/source/T3D/components/render/renderComponentInterface.h similarity index 100% rename from Engine/source/T3D/components/Render/renderComponentInterface.h rename to Engine/source/T3D/components/render/renderComponentInterface.h From fd715f3ef3a466547ae3c74a818ef3579e584907 Mon Sep 17 00:00:00 2001 From: blackwc Date: Fri, 27 May 2016 02:22:39 -0400 Subject: [PATCH 59/71] add loop playback to GuiTheoraCtrl --- Engine/source/gui/theora/guiTheoraCtrl.cpp | 12 +++++++++++- Engine/source/gui/theora/guiTheoraCtrl.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Engine/source/gui/theora/guiTheoraCtrl.cpp b/Engine/source/gui/theora/guiTheoraCtrl.cpp index 145b3474c..f6d5fd213 100644 --- a/Engine/source/gui/theora/guiTheoraCtrl.cpp +++ b/Engine/source/gui/theora/guiTheoraCtrl.cpp @@ -73,6 +73,7 @@ GuiTheoraCtrl::GuiTheoraCtrl() mPlayOnWake = true; mRenderDebugInfo = false; mTranscoder = OggTheoraDecoder::TRANSCODER_Auto; + mLoop = false; mBackgroundColor.set( 0, 0, 0, 255); } @@ -89,6 +90,8 @@ void GuiTheoraCtrl::initPersistFields() "Fill color when video is not playing." ); addField( "playOnWake", TypeBool, Offset( mPlayOnWake, GuiTheoraCtrl ), "Whether to start playing video when control is woken up." ); + addField( "loop", TypeBool, Offset( mLoop, GuiTheoraCtrl ), + "Loop playback." ); addField( "stopOnSleep", TypeBool, Offset( mStopOnSleep, GuiTheoraCtrl ), "Whether to stop video when control is set to sleep.\n\n" "If this is not set to true, the video will be paused when the control is put to sleep. This is because there is no support " @@ -221,7 +224,14 @@ void GuiTheoraCtrl::onRender(Point2I offset, const RectI &updateRect) } } else - mDone = true; + { + if(mLoop) + { + play(); + } else { + mDone = true; + } + } } else GFX->getDrawUtil()->drawRectFill(rect, mBackgroundColor); // black rect diff --git a/Engine/source/gui/theora/guiTheoraCtrl.h b/Engine/source/gui/theora/guiTheoraCtrl.h index e85ff6986..635c515da 100644 --- a/Engine/source/gui/theora/guiTheoraCtrl.h +++ b/Engine/source/gui/theora/guiTheoraCtrl.h @@ -57,6 +57,8 @@ class GuiTheoraCtrl : public GuiControl /// If true, playback will start automatically when the control receives its /// onWake(). bool mPlayOnWake; + + bool mLoop; /// Which transcoder to use on the Theora decoder. This is mostly /// meant as a development aid. From 86f9c6f2e750714ea9b7c9f0e9a293e99d9782c9 Mon Sep 17 00:00:00 2001 From: Areloch Date: Fri, 27 May 2016 14:32:36 -0500 Subject: [PATCH 60/71] When using bullet physics, it ensures the player does not move when the world sim is paused, as well as correcting the surface check when walking to test against the max run angle. --- Engine/source/T3D/physics/bullet/btPlayer.cpp | 25 +++++++++++-------- Engine/source/T3D/physics/bullet/btPlayer.h | 4 +++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Engine/source/T3D/physics/bullet/btPlayer.cpp b/Engine/source/T3D/physics/bullet/btPlayer.cpp index 6e22b0cf8..793f6053c 100644 --- a/Engine/source/T3D/physics/bullet/btPlayer.cpp +++ b/Engine/source/T3D/physics/bullet/btPlayer.cpp @@ -71,6 +71,7 @@ void BtPlayer::init( const char *type, mObject = obj; mWorld = (BtWorld*)world; + mSlopeAngle = runSurfaceCos; mStepHeight = stepHeight; //if ( dStricmp( type, "Capsule" ) == 0 ) @@ -102,6 +103,17 @@ Point3F BtPlayer::move( const VectorF &disp, CollisionList &outCol ) { AssertFatal( mGhostObject, "BtPlayer::move - The controller is null!" ); + if (!mWorld->isEnabled()) + { + btTransform currentTrans = mGhostObject->getWorldTransform(); + btVector3 currentPos = currentTrans.getOrigin(); + + Point3F returnPos = btCast(currentPos); + + returnPos.z -= mOriginOffset; + return returnPos; + } + // First recover from any penetrations from the previous tick. U32 numPenetrationLoops = 0; bool touchingContact = false; @@ -305,16 +317,9 @@ bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, Collision col.normal = btCast( callback.m_hitNormalWorld ); col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() ); - if (disp.z() < 0.0f) - { - // We're sweeping down as part of the stepping routine. In this - // case we want to have the collision normal only point in the opposite direction. - // i.e. up If we include the sideways part of the normal then the Player class - // velocity calculations using this normal will affect the player's forwards - // momentum. This is especially noticable on stairs as the rounded bottom of - // the capsule slides up the corner of a stair. - col.normal.set(0.0f, 0.0f, 1.0f); - } + F32 vd = col.normal.z; + if (vd < mSlopeAngle) + return false; } return true; diff --git a/Engine/source/T3D/physics/bullet/btPlayer.h b/Engine/source/T3D/physics/bullet/btPlayer.h index 388035431..2ad89a946 100644 --- a/Engine/source/T3D/physics/bullet/btPlayer.h +++ b/Engine/source/T3D/physics/bullet/btPlayer.h @@ -57,6 +57,10 @@ protected: /// F32 mOriginOffset; + /// + F32 mSlopeAngle; + /// + /// F32 mStepHeight; /// From 510b726f6fa3aaeac1a4ed69aa88f918fa0315a7 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 29 May 2016 00:58:02 -0500 Subject: [PATCH 61/71] Final Linux compliance changes(renames, tweaks for gcc compliance, etc) --- .../components/animation/animationComponent.cpp | 4 ++-- .../animation/animationComponent_ScriptBinding.h | 2 +- .../T3D/components/camera/cameraComponent.cpp | 2 +- .../camera/cameraComponent_ScriptBinding.h | 2 +- .../components/camera/cameraOrbiterComponent.cpp | 2 +- .../components/camera/cameraOrbiterComponent.h | 2 +- .../components/collision/collisionComponent.cpp | 2 +- .../collision/collisionComponent_ScriptBinding.h | 2 +- .../components/collision/collisionInterfaces.cpp | 4 ++-- .../components/collision/collisionInterfaces.h | 6 +++--- Engine/source/T3D/components/game/stateMachine.h | 2 +- .../components/game/stateMachineComponent.cpp | 2 +- .../T3D/components/game/triggerComponent.cpp | 5 +++-- .../physics/physicsComponentInterface.h | 2 +- .../physics/playerControllerComponent.cpp | 2 +- .../physics/playerControllerComponent.h | 2 +- .../components/physics/rigidBodyComponent.cpp | 4 ++-- .../T3D/components/physics/rigidBodyComponent.h | 2 +- .../T3D/components/render/meshComponent.cpp | 6 ++++-- .../source/T3D/components/render/meshComponent.h | 2 +- .../render/meshComponent_ScriptBinding.h | 2 +- .../components/render/renderComponentInterface.h | 8 ++++---- Engine/source/T3D/entity.h | 8 ++------ .../gui/editor/inspector/mountingGroup.cpp | 2 +- Tools/CMake/torque3d.cmake | 16 +++++++++------- 25 files changed, 47 insertions(+), 46 deletions(-) diff --git a/Engine/source/T3D/components/animation/animationComponent.cpp b/Engine/source/T3D/components/animation/animationComponent.cpp index 5c17a2369..4c009f599 100644 --- a/Engine/source/T3D/components/animation/animationComponent.cpp +++ b/Engine/source/T3D/components/animation/animationComponent.cpp @@ -20,9 +20,9 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/animation/animationcomponent.h" +#include "T3D/components/animation/animationComponent.h" #include "T3D/components/animation/animationComponent_ScriptBinding.h" -#include "T3D/components/render/meshcomponent.h" +#include "T3D/components/render/meshComponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h b/Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h index 366cbb6ba..2d26c5da1 100644 --- a/Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/animation/animationComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/components/animation/animationcomponent.h" +#include "T3D/components/animation/animationComponent.h" DefineEngineMethod(AnimationComponent, playThread, bool, (S32 slot, const char* name, bool transition, F32 transitionTime), (-1, "", true, 0.5), "@brief Start a new animation thread, or restart one that has been paused or " diff --git a/Engine/source/T3D/components/camera/cameraComponent.cpp b/Engine/source/T3D/components/camera/cameraComponent.cpp index c42fb96ad..60c62fb3a 100644 --- a/Engine/source/T3D/components/camera/cameraComponent.cpp +++ b/Engine/source/T3D/components/camera/cameraComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/camera/cameracomponent.h" +#include "T3D/components/camera/cameraComponent.h" #include "T3D/components/camera/cameraComponent_ScriptBinding.h" #include "platform/platform.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h b/Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h index caa6a38e7..2c3f1dbef 100644 --- a/Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/camera/cameraComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/components/camera/cameracomponent.h" +#include "T3D/components/camera/cameraComponent.h" //Basically, this only exists for backwards compatibility for parts of the editors ConsoleMethod(CameraComponent, getMode, const char*, 2, 2, "() - We get the first behavior of the requested type on our owner object.\n" diff --git a/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp b/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp index af91347ab..dbc7cde69 100644 --- a/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp +++ b/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/camera/cameraOrbitercomponent.h" +#include "T3D/components/camera/cameraOrbiterComponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" diff --git a/Engine/source/T3D/components/camera/cameraOrbiterComponent.h b/Engine/source/T3D/components/camera/cameraOrbiterComponent.h index b4b495a1d..8fb584a3e 100644 --- a/Engine/source/T3D/components/camera/cameraOrbiterComponent.h +++ b/Engine/source/T3D/components/camera/cameraOrbiterComponent.h @@ -27,7 +27,7 @@ #include "T3D/components/component.h" #endif #ifndef CAMERA_COMPONENT_H -#include "T3D/components/camera/cameracomponent.h" +#include "T3D/components/camera/cameraComponent.h" #endif ////////////////////////////////////////////////////////////////////////// diff --git a/Engine/source/T3D/components/collision/collisionComponent.cpp b/Engine/source/T3D/components/collision/collisionComponent.cpp index 0698b4b39..e680665dc 100644 --- a/Engine/source/T3D/components/collision/collisionComponent.cpp +++ b/Engine/source/T3D/components/collision/collisionComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/collision/collisioncomponent.h" +#include "T3D/components/collision/collisionComponent.h" #include "T3D/components/collision/collisionComponent_ScriptBinding.h" #include "T3D/components/physics/physicsBehavior.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h b/Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h index 3d7bf6bb3..3b8e83d11 100644 --- a/Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/collision/collisionComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/components/collision/collisioncomponent.h" +#include "T3D/components/collision/collisionComponent.h" #include "materials/baseMatInstance.h" DefineConsoleMethod(CollisionComponent, getNumberOfContacts, S32, (), , diff --git a/Engine/source/T3D/components/collision/collisionInterfaces.cpp b/Engine/source/T3D/components/collision/collisionInterfaces.cpp index 9ddf01a40..c45dbde48 100644 --- a/Engine/source/T3D/components/collision/collisionInterfaces.cpp +++ b/Engine/source/T3D/components/collision/collisionInterfaces.cpp @@ -126,7 +126,7 @@ void CollisionInterface::handleCollisionNotifyList() mCollisionNotifyList.clear(); } -Chunker sTimeoutChunker; +Chunker sCollisionTimeoutChunker; CollisionInterface::CollisionTimeout* CollisionInterface::sFreeTimeoutList = 0; void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec) @@ -174,7 +174,7 @@ void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec) } else { - ptr = sTimeoutChunker.alloc(); + ptr = sCollisionTimeoutChunker.alloc(); } ptr->object = obj; diff --git a/Engine/source/T3D/components/collision/collisionInterfaces.h b/Engine/source/T3D/components/collision/collisionInterfaces.h index 675230e07..6592d6015 100644 --- a/Engine/source/T3D/components/collision/collisionInterfaces.h +++ b/Engine/source/T3D/components/collision/collisionInterfaces.h @@ -82,8 +82,8 @@ public: VectorF vector; }; - Signal< void( SceneObject* ) > CollisionInterface::onCollisionSignal; - Signal< void( SceneObject* ) > CollisionInterface::onContactSignal; + Signal< void( SceneObject* ) > onCollisionSignal; + Signal< void( SceneObject* ) > onContactSignal; protected: CollisionTimeout* mTimeoutList; @@ -149,7 +149,7 @@ public: virtual PhysicsCollision* getCollisionData() = 0; - Signal< void(PhysicsCollision* collision) > CollisionInterface::onCollisionChanged; + Signal< void(PhysicsCollision* collision) > onCollisionChanged; }; class BuildConvexInterface //: public Interface diff --git a/Engine/source/T3D/components/game/stateMachine.h b/Engine/source/T3D/components/game/stateMachine.h index 8bf7b15fb..9ccc540e8 100644 --- a/Engine/source/T3D/components/game/stateMachine.h +++ b/Engine/source/T3D/components/game/stateMachine.h @@ -160,7 +160,7 @@ public: return mFields[index]; } - Signal< void(StateMachine*, S32 stateIdx) > StateMachine::onStateChanged; + Signal< void(StateMachine*, S32 stateIdx) > onStateChanged; // inline bool readStateName(State* state, SimXMLDocument* reader) diff --git a/Engine/source/T3D/components/game/stateMachineComponent.cpp b/Engine/source/T3D/components/game/stateMachineComponent.cpp index 572f845e9..991d41ce1 100644 --- a/Engine/source/T3D/components/game/stateMachineComponent.cpp +++ b/Engine/source/T3D/components/game/stateMachineComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/game/StateMachinecomponent.h" +#include "T3D/components/game/stateMachineComponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" diff --git a/Engine/source/T3D/components/game/triggerComponent.cpp b/Engine/source/T3D/components/game/triggerComponent.cpp index a9697af50..290fab437 100644 --- a/Engine/source/T3D/components/game/triggerComponent.cpp +++ b/Engine/source/T3D/components/game/triggerComponent.cpp @@ -3,7 +3,7 @@ // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "console/consoleTypes.h" -#include "T3D/components/game/Triggercomponent.h" +#include "T3D/components/game/triggerComponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" @@ -234,7 +234,8 @@ bool TriggerComponent::testObject(SceneObject* enter) //anywho, build our list and then we'll check intersections ClippedPolyList myList; - myList.setTransform(&(mOwner->getTransform()), mOwner->getScale()); + MatrixF ownerTransform = mOwner->getTransform(); + myList.setTransform(&ownerTransform, mOwner->getScale()); myList.setObject(mOwner); myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere); diff --git a/Engine/source/T3D/components/physics/physicsComponentInterface.h b/Engine/source/T3D/components/physics/physicsComponentInterface.h index 3d233a222..57f00b8d4 100644 --- a/Engine/source/T3D/components/physics/physicsComponentInterface.h +++ b/Engine/source/T3D/components/physics/physicsComponentInterface.h @@ -43,7 +43,7 @@ public: F32 getMass() { return mMass; } - Signal< void(VectorF normal, Vector overlappedObjects) > PhysicsComponentInterface::onPhysicsCollision; + Signal< void(VectorF normal, Vector overlappedObjects) > onPhysicsCollision; }; #endif \ No newline at end of file diff --git a/Engine/source/T3D/components/physics/playerControllerComponent.cpp b/Engine/source/T3D/components/physics/playerControllerComponent.cpp index 53283ac34..77db8dd1f 100644 --- a/Engine/source/T3D/components/physics/playerControllerComponent.cpp +++ b/Engine/source/T3D/components/physics/playerControllerComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/physics/playerControllercomponent.h" +#include "T3D/components/physics/playerControllerComponent.h" #include "platform/platform.h" #include "console/consoleTypes.h" #include "core/util/safeDelete.h" diff --git a/Engine/source/T3D/components/physics/playerControllerComponent.h b/Engine/source/T3D/components/physics/playerControllerComponent.h index d38410888..49d4c175c 100644 --- a/Engine/source/T3D/components/physics/playerControllerComponent.h +++ b/Engine/source/T3D/components/physics/playerControllerComponent.h @@ -203,7 +203,7 @@ public: //This is a weird artifact of the PhysicsReps. We want the collision component to be privvy to any events that happen //so when the physics components do a findContact test during their update, they'll have a signal collision components //can be listening to to update themselves with that info - Signal< void(SceneObject*) > PlayerControllerComponent::onContactSignal; + Signal< void(SceneObject*) > onContactSignal; // DECLARE_CALLBACK(void, updateMove, (PlayerControllerComponent* obj)); diff --git a/Engine/source/T3D/components/physics/rigidBodyComponent.cpp b/Engine/source/T3D/components/physics/rigidBodyComponent.cpp index bdabafe3c..21e9ecdbe 100644 --- a/Engine/source/T3D/components/physics/rigidBodyComponent.cpp +++ b/Engine/source/T3D/components/physics/rigidBodyComponent.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "T3D/components/physics/rigidBodycomponent.h" +#include "T3D/components/physics/rigidBodyComponent.h" #include "core/util/safeDelete.h" #include "console/consoleTypes.h" #include "console/consoleObject.h" @@ -31,7 +31,7 @@ #include "T3D/physics/physicsPlugin.h" #include "T3D/physics/physicsWorld.h" #include "T3D/physics/physicsCollision.h" -#include "T3D/components/collision/collisioncomponent.h" +#include "T3D/components/collision/collisionComponent.h" bool RigidBodyComponent::smNoCorrections = false; bool RigidBodyComponent::smNoSmoothing = false; diff --git a/Engine/source/T3D/components/physics/rigidBodyComponent.h b/Engine/source/T3D/components/physics/rigidBodyComponent.h index 3c9aea61d..4bbe1f927 100644 --- a/Engine/source/T3D/components/physics/rigidBodyComponent.h +++ b/Engine/source/T3D/components/physics/rigidBodyComponent.h @@ -30,7 +30,7 @@ #include "T3D/physics/physicsCommon.h" #endif #ifndef COLLISION_COMPONENT_H -#include "T3D/components/collision/collisioncomponent.h" +#include "T3D/components/collision/collisionComponent.h" #endif #ifndef PHYSICS_COMPONENT_INTERFACE_H #include "T3D/components/physics/physicsComponentInterface.h" diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index e84c43ace..fdb005adf 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "platform/platform.h" #include "console/consoleTypes.h" -#include "T3D/components/render/meshcomponent.h" +#include "T3D/components/render/meshComponent.h" #include "core/util/safeDelete.h" #include "core/resourceManager.h" #include "core/stream/fileStream.h" @@ -222,7 +222,9 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) for(U32 i=0; i < mChangingMaterials.size(); i++) { stream->writeInt(mChangingMaterials[i].slot, 16); - con->packNetStringHandleU(stream, NetStringHandle(mChangingMaterials[i].matName)); + + NetStringHandle matNameStr = mChangingMaterials[i].matName.c_str(); + con->packNetStringHandleU(stream, matNameStr); } mChangingMaterials.clear(); diff --git a/Engine/source/T3D/components/render/meshComponent.h b/Engine/source/T3D/components/render/meshComponent.h index 8aa02a64d..6adc2633e 100644 --- a/Engine/source/T3D/components/render/meshComponent.h +++ b/Engine/source/T3D/components/render/meshComponent.h @@ -153,7 +153,7 @@ public: virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; } virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; } - Resource getShapeResource() { if (mMeshAsset) return mMeshAsset->getShapeResource(); else return NULL; } + Resource getShapeResource() { return mMeshAsset->getShapeResource(); } void _onResourceChanged(const Torque::Path &path); diff --git a/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h b/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h index 8181b3e7d..5a19b8f08 100644 --- a/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h +++ b/Engine/source/T3D/components/render/meshComponent_ScriptBinding.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/engineAPI.h" -#include "T3D/components/render/meshcomponent.h" +#include "T3D/components/render/meshComponent.h" #include "scene/sceneObject.h" #include "math/mTransform.h" diff --git a/Engine/source/T3D/components/render/renderComponentInterface.h b/Engine/source/T3D/components/render/renderComponentInterface.h index 6948f3866..ff51098f2 100644 --- a/Engine/source/T3D/components/render/renderComponentInterface.h +++ b/Engine/source/T3D/components/render/renderComponentInterface.h @@ -24,10 +24,10 @@ #define RENDER_COMPONENT_INTERFACE_H #ifndef _TSSHAPE_H_ -#include "ts/TSShape.h" +#include "ts/tsShape.h" #endif #ifndef _TSSHAPEINSTANCE_H_ -#include "ts/TSShapeInstance.h" +#include "ts/tsShapeInstance.h" #endif #ifndef CORE_INTERFACES_H #include "T3D/components/coreInterfaces.h" @@ -40,7 +40,7 @@ public: virtual TSShape* getShape() = 0; - Signal< void(RenderComponentInterface*) > RenderComponentInterface::onShapeChanged; + Signal< void(RenderComponentInterface*) > onShapeChanged; virtual TSShapeInstance* getShapeInstance() = 0; @@ -50,7 +50,7 @@ public: virtual void setNodeTransforms(Vector transforms) = 0; - Signal< void(RenderComponentInterface*) > RenderComponentInterface::onShapeInstanceChanged; + Signal< void(RenderComponentInterface*) > onShapeInstanceChanged; }; class CastRayRenderedInterface// : public Interface diff --git a/Engine/source/T3D/entity.h b/Engine/source/T3D/entity.h index faaaea4cf..52818f6f9 100644 --- a/Engine/source/T3D/entity.h +++ b/Engine/source/T3D/entity.h @@ -32,13 +32,12 @@ #ifndef COMPONENT_H #include "T3D/components/component.h" #endif -#ifndef MROTATION_H -#include "math/mRotation.h" -#endif #ifndef _CONTAINERQUERY_H_ #include "T3D/containerQuery.h" #endif +class Component; + //************************************************************************** // Entity //************************************************************************** @@ -272,9 +271,6 @@ Vector Entity::getComponents() // Loop through our child objects. for (U32 i = 0; i < mComponents.size(); i++) { - if (!mComponents[i]->isEnabled()) - continue; - curObj = dynamic_cast(mComponents[i]); // Add this child object if appropriate. diff --git a/Engine/source/gui/editor/inspector/mountingGroup.cpp b/Engine/source/gui/editor/inspector/mountingGroup.cpp index bce47f66a..7afa53105 100644 --- a/Engine/source/gui/editor/inspector/mountingGroup.cpp +++ b/Engine/source/gui/editor/inspector/mountingGroup.cpp @@ -77,7 +77,7 @@ GuiControl* GuiInspectorMountingGroup::buildMenuCtrl() //GuiInspectorTypeMenuBase::_registerEditControl( retCtrl ); char szName[512]; - dSprintf( szName, 512, "IE_%s_%d_%s_Field", retCtrl->getClassName(), mParentInspector->getInspectObject()->getId(), mCaption); + dSprintf( szName, 512, "IE_%s_%d_%s_Field", retCtrl->getClassName(), mParentInspector->getInspectObject()->getId(), mCaption.c_str()); // Register the object retCtrl->registerObject( szName ); diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index fc7e2a920..63a8c9ca9 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -35,6 +35,8 @@ if(UNIX) # for asm files SET (CMAKE_ASM_NASM_OBJECT_FORMAT "elf") ENABLE_LANGUAGE (ASM_NASM) + + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() # TODO: fmod support @@ -257,7 +259,7 @@ addPath("${srcDir}/gui/3d") addPath("${srcDir}/postFx") if(NOT TORQUE_EXPERIMENTAL_EC) - set(BLACKLIST "Entity.cpp;Entity.h" ) + set(BLACKLIST "entity.cpp;entity.h" ) endif() addPath("${srcDir}/T3D") set(BLACKLIST "" ) @@ -274,12 +276,12 @@ addPath("${srcDir}/T3D/turret") if( TORQUE_EXPERIMENTAL_EC ) addPath("${srcDir}/T3D/components/") - addPath("${srcDir}/T3D/components/Animation") - addPath("${srcDir}/T3D/components/Camera") - addPath("${srcDir}/T3D/components/Collision") - addPath("${srcDir}/T3D/components/Game") - addPath("${srcDir}/T3D/components/Physics") - addPath("${srcDir}/T3D/components/Render") + addPath("${srcDir}/T3D/components/animation") + addPath("${srcDir}/T3D/components/camera") + addPath("${srcDir}/T3D/components/collision") + addPath("${srcDir}/T3D/components/game") + addPath("${srcDir}/T3D/components/physics") + addPath("${srcDir}/T3D/components/render") endif() addPath("${srcDir}/main/") From e48ee1a03a5f0cb583b20e3317ea7962239873ab Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 29 May 2016 00:58:39 -0500 Subject: [PATCH 62/71] Fixes the recursive directory dump in the Linux platform code so that module/asset parsing works as expected. --- .../source/platformX86UNIX/x86UNIXFileio.cpp | 96 +++++++++++++------ 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp index 6c2dd6955..6e51b85e1 100644 --- a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp +++ b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp @@ -1151,45 +1151,79 @@ bool dPathCopy(const char *fromName, const char *toName, bool nooverwrite) DIR *dip; struct dirent *d; - if (subPath && (dStrncmp(subPath, "", 1) != 0)) - { - if ((basePath[dStrlen(basePath) - 1]) == '/') - dSprintf(Path, 1024, "%s%s", basePath, subPath); - else - dSprintf(Path, 1024, "%s/%s", basePath, subPath); - } + dsize_t trLen = basePath ? dStrlen(basePath) : 0; + dsize_t subtrLen = subPath ? dStrlen(subPath) : 0; + char trail = trLen > 0 ? basePath[trLen - 1] : '\0'; + char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0'; + char subLead = subtrLen > 0 ? subPath[0] : '\0'; + + if (trail == '/') + { + if (subPath && (dStrncmp(subPath, "", 1) != 0)) + { + if (subTrail == '/') + dSprintf(Path, 1024, "%s%s", basePath, subPath); + else + dSprintf(Path, 1024, "%s%s/", basePath, subPath); + } + else + dSprintf(Path, 1024, "%s", basePath); + } else - dSprintf(Path, 1024, "%s", basePath); + { + if (subPath && (dStrncmp(subPath, "", 1) != 0)) + { + if (subTrail == '/') + dSprintf(Path, 1024, "%s%s", basePath, subPath); + else + dSprintf(Path, 1024, "%s%s/", basePath, subPath); + } + else + dSprintf(Path, 1024, "%s/", basePath); + } + dip = opendir(Path); if (dip == NULL) return false; + ////////////////////////////////////////////////////////////////////////// // add path to our return list ( provided it is valid ) ////////////////////////////////////////////////////////////////////////// if (!Platform::isExcludedDirectory(subPath)) - { - if (noBasePath) - { - // We have a path and it's not an empty string or an excluded directory - if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) ) - directoryVector.push_back(StringTable->insert(subPath)); - } - else - { - if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) - { - char szPath[1024]; - dMemset(szPath, 0, 1024); - if ( (basePath[dStrlen(basePath) - 1]) != '/') - dSprintf(szPath, 1024, "%s%s", basePath, subPath); - else - dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]); - directoryVector.push_back(StringTable->insert(szPath)); - } - else - directoryVector.push_back(StringTable->insert(basePath)); - } - } + { + if (noBasePath) + { + // We have a path and it's not an empty string or an excluded directory + if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) ) + directoryVector.push_back(StringTable->insert(subPath)); + } + else + { + if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) + { + char szPath[1024]; + dMemset(szPath, 0, 1024); + if (trail == '/') + { + if ((basePath[dStrlen(basePath) - 1]) != '/') + dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]); + else + dSprintf(szPath, 1024, "%s%s", basePath, subPath); + } + else + { + if ((basePath[dStrlen(basePath) - 1]) != '/') + dSprintf(szPath, 1024, "%s%s", basePath, subPath); + else + dSprintf(szPath, 1024, "%s/%s", basePath, subPath); + } + + directoryVector.push_back(StringTable->insert(szPath)); + } + else + directoryVector.push_back(StringTable->insert(basePath)); + } + } ////////////////////////////////////////////////////////////////////////// // Iterate through and grab valid directories ////////////////////////////////////////////////////////////////////////// From 18184747e39d59b3b163f01389fbebfe22993f82 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 29 May 2016 11:54:50 -0500 Subject: [PATCH 63/71] Fixes an issue where script-based components listed in the scene tree would not have a name on their tree item. --- Engine/source/T3D/assets/ComponentAsset.h | 6 ++++ Engine/source/T3D/entity.cpp | 44 +++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/assets/ComponentAsset.h b/Engine/source/T3D/assets/ComponentAsset.h index 0eaa5a86b..1db53b8c8 100644 --- a/Engine/source/T3D/assets/ComponentAsset.h +++ b/Engine/source/T3D/assets/ComponentAsset.h @@ -66,6 +66,12 @@ public: /// Declare Console Object. DECLARE_CONOBJECT(ComponentAsset); + StringTableEntry getComponentName() { return mComponentName; } + StringTableEntry getComponentClass() { return mComponentClass; } + StringTableEntry getFriendlyName() { return mFriendlyName; } + StringTableEntry getFriendlyType() { return mComponentType; } + StringTableEntry getDescription() { return mDescription; } + protected: virtual void initializeAsset(void) {} virtual void onAssetRefresh(void) {} diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index bff589570..ae6586360 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -39,6 +39,9 @@ #include "T3D/components/collision/collisionInterfaces.h" #include "gui/controls/guiTreeViewCtrl.h" +#include "assets/assetManager.h" +#include "assets/assetQuery.h" +#include "T3D/assets/ComponentAsset.h" #include "console/consoleInternal.h" #include "T3D/gameBase/std/stdMoveList.h" @@ -1353,7 +1356,8 @@ Component *Entity::getComponent(String componentType) void Entity::onInspect() { Vector updaters = getComponents(); - for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) { + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { (*it)->onInspect(); } @@ -1374,9 +1378,45 @@ void Entity::onInspect() newItem->mState.set(GuiTreeViewCtrl::Item::ForceItemName); //newItem->mInspectorInfo.mObject = this; - for (U32 i = 0; i < mComponents.size(); i++) + AssetManager *assetDB = dynamic_cast(Sim::findObject("AssetDatabase")); + if (!assetDB) + return; + + //This is used in the event of script-created assets, which likely only have + //the name and other 'friendly' properties stored in a ComponentAsset. + //So we'll do a query for those assets and find the asset based on the component's + //class name + AssetQuery* qry = new AssetQuery(); + qry->registerObject(); + + assetDB->findAssetType(qry, "ComponentAsset"); + + for (U32 i = 0; i < mComponents.size(); ++i) { String compName = mComponents[i]->getFriendlyName(); + + if (compName == String("")) + { + String componentClass = mComponents[i]->getClassNamespace(); + + //Means that it's a script-derived component and we should consult the asset to try + //to get the info for it + S32 compAssetCount = qry->mAssetList.size(); + for (U32 c = 0; c < compAssetCount; ++c) + { + StringTableEntry assetID = qry->mAssetList[c]; + + ComponentAsset* compAsset = assetDB->acquireAsset(assetID); + + String compAssetClass = compAsset->getComponentName(); + if (componentClass == compAssetClass) + { + compName = compAsset->getFriendlyName(); + break; + } + } + } + S32 compID = editorTree->insertItem(componentID, compName); newItem = editorTree->getItem(compID); newItem->mInspectorInfo.mObject = mComponents[i]; From 74a2005d1527b1b1fd0cb1818aac1344bddec87f Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 30 May 2016 02:29:20 -0500 Subject: [PATCH 64/71] Fixes mistake where GuiInspectorEntityGroup's onAdd doesn't explicitly return true, which can cause problems in some compilers. --- Engine/source/gui/editor/inspector/entityGroup.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Engine/source/gui/editor/inspector/entityGroup.cpp b/Engine/source/gui/editor/inspector/entityGroup.cpp index 2fd6e6172..c833d336d 100644 --- a/Engine/source/gui/editor/inspector/entityGroup.cpp +++ b/Engine/source/gui/editor/inspector/entityGroup.cpp @@ -41,6 +41,8 @@ bool GuiInspectorEntityGroup::onAdd() { if (!Parent::onAdd()) return false; + + return true; } //----------------------------------------------------------------------------- From 553cf260f1ca168777e1b9c544ae22c1072ddd2f Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 30 May 2016 03:13:19 -0500 Subject: [PATCH 65/71] Some converts of usage of Shapebase for Gamebase to make camera/control object swapping easier. --- Engine/source/T3D/fps/guiCrossHairHud.cpp | 2 +- Engine/source/T3D/gameFunctions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/fps/guiCrossHairHud.cpp b/Engine/source/T3D/fps/guiCrossHairHud.cpp index a8cd3e1ba..01761b707 100644 --- a/Engine/source/T3D/fps/guiCrossHairHud.cpp +++ b/Engine/source/T3D/fps/guiCrossHairHud.cpp @@ -117,7 +117,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect) GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; - ShapeBase* control = dynamic_cast(conn->getControlObject()); + GameBase* control = dynamic_cast(conn->getCameraObject()); if (!control || !(control->getTypeMask() & ObjectMask) || !conn->isFirstPerson()) return; diff --git a/Engine/source/T3D/gameFunctions.cpp b/Engine/source/T3D/gameFunctions.cpp index 7def7c252..3c71b57b5 100644 --- a/Engine/source/T3D/gameFunctions.cpp +++ b/Engine/source/T3D/gameFunctions.cpp @@ -339,7 +339,7 @@ bool GameProcessCameraQuery(CameraQuery *query) if (connection && connection->getControlCameraTransform(0.032f, &query->cameraMatrix)) { - query->object = dynamic_cast(connection->getControlObject()); + query->object = dynamic_cast(connection->getCameraObject()); query->nearPlane = gClientSceneGraph->getNearClip(); // Scale the normal visible distance by the performance From bbf7865a7719550ffb9e6cfd151c9190ff005554 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 30 May 2016 21:30:02 -0500 Subject: [PATCH 66/71] Makes sure if you don't spawn a game object into MissionGroup, it spawns it into MissionCleanup. --- .../Full/game/scripts/server/gameObjects/GameObjectManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs index 57c47c5cf..f0b618920 100644 --- a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs +++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs @@ -77,8 +77,10 @@ function spawnGameObject(%name, %addToMissionGroup) { %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); - if(%addToMissionGroup == true) + if(%addToMissionGroup == true) //save instance when saving level MissionGroup.add(%newSGOObject); + else // clear instance on level exit + MissionCleanup.add(%newSGOObject); return %newSGOObject; } From 2464b620ba92adf0062dd9cfd28e4da8dffe2b99 Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 31 May 2016 12:51:23 -0500 Subject: [PATCH 67/71] Fixes several minor initialization issues that were causing problems with deletion/management of components and entities. Also makes the ThirdPersonPlayer game object editor selectable again by removing an erroneously set field. --- .../animation/animationComponent.cpp | 6 +++-- .../camera/cameraOrbiterComponent.cpp | 26 +++++++++++++++++++ .../camera/cameraOrbiterComponent.h | 3 +++ .../physics/playerControllerComponent.cpp | 4 ++- .../T3D/components/render/meshComponent.cpp | 1 + Engine/source/T3D/entity.cpp | 14 ++++++---- .../gameObjects/ThirdPersonPlayerObject.taml | 1 - 7 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Engine/source/T3D/components/animation/animationComponent.cpp b/Engine/source/T3D/components/animation/animationComponent.cpp index 4c009f599..e1a71511c 100644 --- a/Engine/source/T3D/components/animation/animationComponent.cpp +++ b/Engine/source/T3D/components/animation/animationComponent.cpp @@ -149,6 +149,8 @@ bool AnimationComponent::onAdd() void AnimationComponent::onRemove() { Parent::onRemove(); + + mOwnerRenderInst = NULL; } void AnimationComponent::onComponentAdd() @@ -387,7 +389,7 @@ S32 AnimationComponent::getThreadSequenceID(S32 slot) void AnimationComponent::updateThread(Thread& st) { - if (!mOwnerShapeInstance) + if (!mOwnerRenderInst) return; switch (st.state) @@ -628,7 +630,7 @@ void AnimationComponent::startSequenceSound(Thread& thread) void AnimationComponent::advanceThreads(F32 dt) { - if (!mOwnerShapeInstance) + if (!mOwnerRenderInst) return; for (U32 i = 0; i < MaxScriptThreads; i++) diff --git a/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp b/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp index dbc7cde69..7e53924d3 100644 --- a/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp +++ b/Engine/source/T3D/components/camera/cameraOrbiterComponent.cpp @@ -92,6 +92,32 @@ void CameraOrbiterComponent::onComponentRemove() Parent::onComponentRemove(); } +void CameraOrbiterComponent::componentAddedToOwner(Component *comp) +{ + if (comp->getId() == getId()) + return; + + //test if this is a shape component! + CameraComponent *camComponent = dynamic_cast(comp); + if (camComponent) + { + mCamera = camComponent; + } +} + +void CameraOrbiterComponent::componentRemovedFromOwner(Component *comp) +{ + if (comp->getId() == getId()) //????????? + return; + + //test if this is a shape component! + CameraComponent *camComponent = dynamic_cast(comp); + if (camComponent) + { + mCamera = NULL; + } +} + U32 CameraOrbiterComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream) { U32 retMask = Parent::packUpdate(con, mask, stream); diff --git a/Engine/source/T3D/components/camera/cameraOrbiterComponent.h b/Engine/source/T3D/components/camera/cameraOrbiterComponent.h index 8fb584a3e..2a091e15e 100644 --- a/Engine/source/T3D/components/camera/cameraOrbiterComponent.h +++ b/Engine/source/T3D/components/camera/cameraOrbiterComponent.h @@ -62,6 +62,9 @@ public: virtual void onComponentAdd(); virtual void onComponentRemove(); + virtual void componentAddedToOwner(Component *comp); + virtual void componentRemovedFromOwner(Component *comp); + virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream); virtual void unpackUpdate(NetConnection *con, BitStream *stream); diff --git a/Engine/source/T3D/components/physics/playerControllerComponent.cpp b/Engine/source/T3D/components/physics/playerControllerComponent.cpp index 77db8dd1f..60945f68e 100644 --- a/Engine/source/T3D/components/physics/playerControllerComponent.cpp +++ b/Engine/source/T3D/components/physics/playerControllerComponent.cpp @@ -69,6 +69,8 @@ PlayerControllerComponent::PlayerControllerComponent() : Component() mFriction = 0.3f; mElasticity = 0.4f; mMaxVelocity = 3000.f; + mVelocity = VectorF::Zero; + mContactTimer = 0; mSticky = false; mFalling = false; @@ -88,7 +90,7 @@ PlayerControllerComponent::PlayerControllerComponent() : Component() mDescription = getDescriptionText("A general-purpose physics player controller."); - mNetFlags.set(Ghostable | ScopeAlways); + //mNetFlags.set(Ghostable | ScopeAlways); mMass = 9.0f; // from ShapeBase mDrag = 1.0f; // from ShapeBase diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index fdb005adf..50c8f7506 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -53,6 +53,7 @@ MeshComponent::MeshComponent() : Component() { mShapeName = StringTable->insert(""); mShapeAsset = StringTable->insert(""); + mShapeInstance = NULL; mChangingMaterials.clear(); diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index ae6586360..f5ca1adb1 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -405,8 +405,9 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream) //mathWrite( *stream, getScale() ); //stream->writeAffineTransform(mObjToWorld); //mathWrite(*stream, getPosition()); - mathWrite(*stream, mPos); + //mathWrite(*stream, mPos); + stream->writeCompressedPoint(mPos); mathWrite(*stream, getRotation()); mDelta.move.pack(stream); @@ -500,7 +501,8 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream) Point3F pos; - mathRead(*stream, &pos); + stream->readCompressedPoint(&pos); + //mathRead(*stream, &pos); RotationF rot; @@ -893,8 +895,10 @@ void Entity::setMountRotation(EulerF rotOffset) void Entity::getCameraTransform(F32* pos, MatrixF* mat) { Vector updaters = getComponents(); - for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) { - if ((*it)->getCameraTransform(pos, mat)) { + for (Vector::iterator it = updaters.begin(); it != updaters.end(); it++) + { + if ((*it)->getCameraTransform(pos, mat)) + { return; } } @@ -1210,7 +1214,7 @@ void Entity::removeObject(SimObject* object) bool Entity::addComponent(Component *comp) { - if (comp == NULL || !comp->isProperlyAdded()) + if (comp == NULL) return false; //double-check were not re-adding anything diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml index fcfead0d4..df2397bb5 100644 --- a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml +++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml @@ -1,6 +1,5 @@ Date: Thu, 2 Jun 2016 22:40:29 -0500 Subject: [PATCH 68/71] Hooks the component fields back into the inspector so they are registered as proper fields of their types, as opposed to the regular string-only dynamic fields. --- Engine/source/T3D/components/component.cpp | 16 +- .../T3D/components/render/meshComponent.cpp | 2 + Engine/source/T3D/entity.cpp | 2 +- .../source/gui/controls/guiTreeViewCtrl.cpp | 2 +- Engine/source/gui/editor/guiInspector.cpp | 12 + .../gui/editor/inspector/componentGroup.cpp | 260 ++++++++++++++++++ .../gui/editor/inspector/componentGroup.h | 70 +++++ .../gui/editor/inspector/dynamicGroup.cpp | 14 + 8 files changed, 369 insertions(+), 9 deletions(-) create mode 100644 Engine/source/gui/editor/inspector/componentGroup.cpp create mode 100644 Engine/source/gui/editor/inspector/componentGroup.h diff --git a/Engine/source/T3D/components/component.cpp b/Engine/source/T3D/components/component.cpp index 607df5e30..47784d4b2 100644 --- a/Engine/source/T3D/components/component.cpp +++ b/Engine/source/T3D/components/component.cpp @@ -410,20 +410,22 @@ void Component::addComponentField(const char *fieldName, const char *desc, const S32 fieldTypeMask = -1; StringTableEntry fieldType = StringTable->insert(type); - if (fieldType == StringTable->insert("TypeS32")) + if (fieldType == StringTable->insert("int")) fieldTypeMask = TypeS32; - else if (fieldType == StringTable->insert("TypeF32")) + else if (fieldType == StringTable->insert("float")) fieldTypeMask = TypeF32; - else if (fieldType == StringTable->insert("TypePoint3F")) + else if (fieldType == StringTable->insert("vector")) fieldTypeMask = TypePoint3F; - else if (fieldType == StringTable->insert("TypeMaterialName")) + else if (fieldType == StringTable->insert("material")) fieldTypeMask = TypeMaterialName; - else if (fieldType == StringTable->insert("TypeImageFilename")) + else if (fieldType == StringTable->insert("image")) fieldTypeMask = TypeImageFilename; - else if (fieldType == StringTable->insert("TypeShapeFilename")) + else if (fieldType == StringTable->insert("shape")) fieldTypeMask = TypeShapeFilename; - else if (fieldType == StringTable->insert("TypeBool")) + else if (fieldType == StringTable->insert("bool")) fieldTypeMask = TypeBool; + else if (fieldType == StringTable->insert("object")) + fieldTypeMask = TypeSimObjectPtr; else fieldTypeMask = TypeString; diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index 50c8f7506..6f4835666 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -115,6 +115,8 @@ void MeshComponent::onRemove() { Parent::onRemove(); + mMeshAsset.clear(); + SAFE_DELETE(mShapeInstance); } diff --git a/Engine/source/T3D/entity.cpp b/Engine/source/T3D/entity.cpp index f5ca1adb1..00ecedad0 100644 --- a/Engine/source/T3D/entity.cpp +++ b/Engine/source/T3D/entity.cpp @@ -230,7 +230,7 @@ bool Entity::onAdd() void Entity::onRemove() { - clearComponents(false); + clearComponents(true); removeFromScene(); diff --git a/Engine/source/gui/controls/guiTreeViewCtrl.cpp b/Engine/source/gui/controls/guiTreeViewCtrl.cpp index f8bc41c2e..a5e833a19 100644 --- a/Engine/source/gui/controls/guiTreeViewCtrl.cpp +++ b/Engine/source/gui/controls/guiTreeViewCtrl.cpp @@ -3798,7 +3798,7 @@ void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event) if (item->isInspectorData()) { Entity* e = dynamic_cast(item->getObject()); - if (item->mScriptInfo.mText != StringTable->insert("Components")) + //if (item->mScriptInfo.mText != StringTable->insert("Components")) { Entity* e = dynamic_cast(item->getObject()); if (e) diff --git a/Engine/source/gui/editor/guiInspector.cpp b/Engine/source/gui/editor/guiInspector.cpp index 811441e2d..565597571 100644 --- a/Engine/source/gui/editor/guiInspector.cpp +++ b/Engine/source/gui/editor/guiInspector.cpp @@ -32,6 +32,7 @@ #ifdef TORQUE_EXPERIMENTAL_EC #include "gui/editor/inspector/entityGroup.h" #include "gui/editor/inspector/mountingGroup.h" +#include "gui/editor/inspector/componentGroup.h" #endif IMPLEMENT_CONOBJECT(GuiInspector); @@ -609,6 +610,17 @@ void GuiInspector::refresh() addObject(mounting); } } + + if (mTargets.first()->getClassRep()->isSubclassOf("Component")) + { + //Build the component field groups as the component describes it + Component* comp = dynamic_cast(mTargets.first().getPointer()); + + GuiInspectorComponentGroup *compGroup = new GuiInspectorComponentGroup("Component Fields", this); + compGroup->registerObject(); + mGroups.push_back(compGroup); + addObject(compGroup); + } #endif // Create the inspector groups for static fields. diff --git a/Engine/source/gui/editor/inspector/componentGroup.cpp b/Engine/source/gui/editor/inspector/componentGroup.cpp new file mode 100644 index 000000000..6dd6f379c --- /dev/null +++ b/Engine/source/gui/editor/inspector/componentGroup.cpp @@ -0,0 +1,260 @@ +//----------------------------------------------------------------------------- +// 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 "gui/buttons/guiIconButtonCtrl.h" +#include "gui/editor/guiInspector.h" +#include "gui/editor/inspector/componentGroup.h" +#include "core/strings/stringUnit.h" +#include "T3D/components/component.h" +#include "gui/editor/inspector/field.h" + +#include "console/engineAPI.h" + +IMPLEMENT_CONOBJECT(GuiInspectorComponentGroup); + +ConsoleDocClass(GuiInspectorComponentGroup, + "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " + "of regular persistent fields.\n\n" + "Editor use only.\n\n" + "@internal" + ); + +GuiInspectorComponentGroup::GuiInspectorComponentGroup(StringTableEntry groupName, SimObjectPtr parent) +: GuiInspectorGroup(groupName, parent) +{ + /*mNeedScroll=false;*/ +}; + +bool GuiInspectorComponentGroup::onAdd() +{ + if (!Parent::onAdd()) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// GuiInspectorComponentGroup - add custom controls +//----------------------------------------------------------------------------- +bool GuiInspectorComponentGroup::createContent() +{ + if(!Parent::createContent()) + return false; + + Con::evaluatef("%d.stack = %d;", this->getId(), mStack->getId()); + + Con::executef(this, "createContent"); + + return true; +} + +//----------------------------------------------------------------------------- +// GuiInspectorComponentGroup - inspectGroup override +//----------------------------------------------------------------------------- +bool GuiInspectorComponentGroup::inspectGroup() +{ + // We can't inspect a group without a target! + if (!mParent || !mParent->getNumInspectObjects()) + return false; + + // to prevent crazy resizing, we'll just freeze our stack for a sec.. + mStack->freeze(true); + + mStack->clear(); + + bool bNoGroup = false; + + // Un-grouped fields are all sorted into the 'general' group + if (dStricmp(mCaption, "General") == 0) + bNoGroup = true; + + // Just delete all fields and recreate them (like the dynamicGroup) + // because that makes creating controls for array fields a lot easier + clearFields(); + + bool bNewItems = false; + bool bMakingArray = false; + GuiStackControl *pArrayStack = NULL; + GuiRolloutCtrl *pArrayRollout = NULL; + bool bGrabItems = false; + + Component* comp = dynamic_cast(getInspector()->getInspectObject(0)); + + //if this isn't a component, what are we even doing here? + if (!comp) + return false; + + for (U32 i = 0; i < comp->getComponentFieldCount(); i++) + { + ComponentField* field = comp->getComponentField(i); + + bNewItems = true; + + GuiInspectorField *fieldGui = constructField(field->mFieldType); + if (fieldGui == NULL) + fieldGui = new GuiInspectorField(); + + fieldGui->init(mParent, this); + + AbstractClassRep::Field *refField; + //check statics + refField = const_cast(comp->findField(field->mFieldName)); + if (!refField) + { + //check dynamics + SimFieldDictionary* fieldDictionary = comp->getFieldDictionary(); + SimFieldDictionaryIterator itr(fieldDictionary); + + while (*itr) + { + SimFieldDictionary::Entry* entry = *itr; + if (entry->slotName == field->mFieldName) + { + AbstractClassRep::Field f; + f.pFieldname = StringTable->insert(field->mFieldName); + + if (field->mFieldDescription) + f.pFieldDocs = field->mFieldDescription; + + f.type = field->mFieldType; + f.offset = -1; + f.elementCount = 1; + f.validator = NULL; + f.flag = 0; //change to be the component type + + f.setDataFn = &defaultProtectedSetFn; + f.getDataFn = &defaultProtectedGetFn; + f.writeDataFn = &defaultProtectedWriteFn; + + if (!dStrcmp(field->mGroup, "")) + f.pGroupname = "Component"; + else + f.pGroupname = field->mGroup; + + ConsoleBaseType* conType = ConsoleBaseType::getType(field->mFieldType); + AssertFatal(conType, "ConsoleObject::addField - invalid console type"); + f.table = conType->getEnumTable(); + + tempFields.push_back(f); + + refField = &f; + + break; + } + ++itr; + } + } + + if (!refField) + continue; + + fieldGui->setInspectorField(&tempFields[tempFields.size() - 1]); + + if (fieldGui->registerObject()) + { +#ifdef DEBUG_SPEW + Platform::outputDebugString("[GuiInspectorGroup] Adding field '%s'", + field->pFieldname); +#endif + + mChildren.push_back(fieldGui); + mStack->addObject(fieldGui); + } + else + { + SAFE_DELETE(fieldGui); + } + } + + mStack->freeze(false); + mStack->updatePanes(); + + // If we've no new items, there's no need to resize anything! + if (bNewItems == false && !mChildren.empty()) + return true; + + sizeToContents(); + + setUpdate(); + + return true; +} + +void GuiInspectorComponentGroup::updateAllFields() +{ + // We overload this to just reinspect the group. + inspectGroup(); +} + +void GuiInspectorComponentGroup::onMouseMove(const GuiEvent &event) +{ + //mParent->mOverDivider = false; +} +ConsoleMethod(GuiInspectorComponentGroup, inspectGroup, bool, 2, 2, "Refreshes the dynamic fields in the inspector.") +{ + return object->inspectGroup(); +} + +void GuiInspectorComponentGroup::clearFields() +{ +} + +SimFieldDictionary::Entry* GuiInspectorComponentGroup::findDynamicFieldInDictionary(StringTableEntry fieldName) +{ + SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); + + for (SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) + { + SimFieldDictionary::Entry * entry = (*ditr); + + if (entry->slotName == fieldName) + return entry; + } + + return NULL; +} + +void GuiInspectorComponentGroup::addDynamicField() +{ +} + +AbstractClassRep::Field* GuiInspectorComponentGroup::findObjectBehaviorField(Component* target, String fieldName) +{ + AbstractClassRep::FieldList& fieldList = target->getClassRep()->mFieldList; + for (AbstractClassRep::FieldList::iterator itr = fieldList.begin(); + itr != fieldList.end(); ++itr) + { + AbstractClassRep::Field* field = &(*itr); + String fldNm(field->pFieldname); + if (fldNm == fieldName) + return field; + } + return NULL; +} +ConsoleMethod(GuiInspectorComponentGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();") +{ + object->addDynamicField(); +} + +ConsoleMethod(GuiInspectorComponentGroup, removeDynamicField, void, 3, 3, "") +{ +} diff --git a/Engine/source/gui/editor/inspector/componentGroup.h b/Engine/source/gui/editor/inspector/componentGroup.h new file mode 100644 index 000000000..34b748c98 --- /dev/null +++ b/Engine/source/gui/editor/inspector/componentGroup.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// 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 GUI_INSPECTOR_COMPONENT_GROUP_H +#define GUI_INSPECTOR_COMPONENT_GROUP_H + +#include "gui/editor/inspector/group.h" +#include "console/simFieldDictionary.h" +#include "T3D/components/component.h" +#include "gui/controls/guiPopUpCtrlEx.h" + +class GuiInspectorComponentGroup : public GuiInspectorGroup +{ +private: + typedef GuiInspectorGroup Parent; + GuiControl* mAddCtrl; + + Vector tempFields; + +public: + DECLARE_CONOBJECT(GuiInspectorComponentGroup); + GuiInspectorComponentGroup() { /*mNeedScroll=false;*/ }; + GuiInspectorComponentGroup(StringTableEntry groupName, SimObjectPtr parent); + + //----------------------------------------------------------------------------- + // inspectGroup is overridden in GuiInspectorComponentGroup to inspect an + // objects FieldDictionary (dynamic fields) instead of regular persistent + // fields. + virtual bool onAdd(); + bool inspectGroup(); + virtual void updateAllFields(); + + void onMouseMove(const GuiEvent &event); + + // For scriptable dynamic field additions + void addDynamicField(); + + // Clear our fields (delete them) + void clearFields(); + + // Find an already existent field by name in the dictionary + virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary(StringTableEntry fieldName); + + AbstractClassRep::Field* findObjectBehaviorField(Component* target, String fieldName); +protected: + // create our inner controls when we add + virtual bool createContent(); + +}; + +#endif diff --git a/Engine/source/gui/editor/inspector/dynamicGroup.cpp b/Engine/source/gui/editor/inspector/dynamicGroup.cpp index ef5d98b3a..78d8c4bd8 100644 --- a/Engine/source/gui/editor/inspector/dynamicGroup.cpp +++ b/Engine/source/gui/editor/inspector/dynamicGroup.cpp @@ -26,6 +26,10 @@ #include "gui/editor/inspector/dynamicField.h" #include "console/engineAPI.h" +#ifdef TORQUE_EXPERIMENTAL_EC +#include "T3D/components/component.h" +#endif + IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup); ConsoleDocClass( GuiInspectorDynamicGroup, @@ -122,6 +126,16 @@ bool GuiInspectorDynamicGroup::inspectGroup() SimFieldDictionary * fieldDictionary = target->getFieldDictionary(); for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) { +#ifdef TORQUE_EXPERIMENTAL_EC + if (target->getClassRep()->isSubclassOf("Component")) + { + Component* compTarget = dynamic_cast(target); + + ComponentField* compField = compTarget->getComponentField((*ditr)->slotName); + if (compField) + continue; + } +#endif if( i == 0 ) { flist.increment(); From 6ec899620dd9553b2c8e1dd7dc57f054b357d156 Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 2 Jun 2016 23:57:46 -0500 Subject: [PATCH 69/71] Tweak to the Component Fields to properly refresh the group. --- Engine/source/gui/editor/guiInspector.cpp | 11 ++- .../gui/editor/inspector/componentGroup.cpp | 82 +++++++++---------- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/Engine/source/gui/editor/guiInspector.cpp b/Engine/source/gui/editor/guiInspector.cpp index 565597571..c1f54a24d 100644 --- a/Engine/source/gui/editor/guiInspector.cpp +++ b/Engine/source/gui/editor/guiInspector.cpp @@ -616,10 +616,13 @@ void GuiInspector::refresh() //Build the component field groups as the component describes it Component* comp = dynamic_cast(mTargets.first().getPointer()); - GuiInspectorComponentGroup *compGroup = new GuiInspectorComponentGroup("Component Fields", this); - compGroup->registerObject(); - mGroups.push_back(compGroup); - addObject(compGroup); + if (comp->getComponentFieldCount() > 0) + { + GuiInspectorComponentGroup *compGroup = new GuiInspectorComponentGroup("Component Fields", this); + compGroup->registerObject(); + mGroups.push_back(compGroup); + addObject(compGroup); + } } #endif diff --git a/Engine/source/gui/editor/inspector/componentGroup.cpp b/Engine/source/gui/editor/inspector/componentGroup.cpp index 6dd6f379c..7d6d30eaa 100644 --- a/Engine/source/gui/editor/inspector/componentGroup.cpp +++ b/Engine/source/gui/editor/inspector/componentGroup.cpp @@ -76,21 +76,13 @@ bool GuiInspectorComponentGroup::inspectGroup() if (!mParent || !mParent->getNumInspectObjects()) return false; + clearFields(); + // to prevent crazy resizing, we'll just freeze our stack for a sec.. mStack->freeze(true); - mStack->clear(); - bool bNoGroup = false; - // Un-grouped fields are all sorted into the 'general' group - if (dStricmp(mCaption, "General") == 0) - bNoGroup = true; - - // Just delete all fields and recreate them (like the dynamicGroup) - // because that makes creating controls for array fields a lot easier - clearFields(); - bool bNewItems = false; bool bMakingArray = false; GuiStackControl *pArrayStack = NULL; @@ -116,52 +108,47 @@ bool GuiInspectorComponentGroup::inspectGroup() fieldGui->init(mParent, this); AbstractClassRep::Field *refField; - //check statics - refField = const_cast(comp->findField(field->mFieldName)); - if (!refField) + + //check dynamics + SimFieldDictionary* fieldDictionary = comp->getFieldDictionary(); + SimFieldDictionaryIterator itr(fieldDictionary); + + while (*itr) { - //check dynamics - SimFieldDictionary* fieldDictionary = comp->getFieldDictionary(); - SimFieldDictionaryIterator itr(fieldDictionary); - - while (*itr) + SimFieldDictionary::Entry* entry = *itr; + if (entry->slotName == field->mFieldName) { - SimFieldDictionary::Entry* entry = *itr; - if (entry->slotName == field->mFieldName) - { - AbstractClassRep::Field f; - f.pFieldname = StringTable->insert(field->mFieldName); + AbstractClassRep::Field f; + f.pFieldname = StringTable->insert(field->mFieldName); - if (field->mFieldDescription) - f.pFieldDocs = field->mFieldDescription; + if (field->mFieldDescription) + f.pFieldDocs = field->mFieldDescription; - f.type = field->mFieldType; - f.offset = -1; - f.elementCount = 1; - f.validator = NULL; - f.flag = 0; //change to be the component type + f.type = field->mFieldType; + f.offset = -1; + f.elementCount = 1; + f.validator = NULL; + f.flag = 0; //change to be the component type - f.setDataFn = &defaultProtectedSetFn; - f.getDataFn = &defaultProtectedGetFn; - f.writeDataFn = &defaultProtectedWriteFn; + f.setDataFn = &defaultProtectedSetFn; + f.getDataFn = &defaultProtectedGetFn; + f.writeDataFn = &defaultProtectedWriteFn; - if (!dStrcmp(field->mGroup, "")) - f.pGroupname = "Component"; - else - f.pGroupname = field->mGroup; + f.pFieldDocs = field->mFieldDescription; - ConsoleBaseType* conType = ConsoleBaseType::getType(field->mFieldType); - AssertFatal(conType, "ConsoleObject::addField - invalid console type"); - f.table = conType->getEnumTable(); + f.pGroupname = "Component Fields"; - tempFields.push_back(f); + ConsoleBaseType* conType = ConsoleBaseType::getType(field->mFieldType); + AssertFatal(conType, "ConsoleObject::addField - invalid console type"); + f.table = conType->getEnumTable(); - refField = &f; + tempFields.push_back(f); - break; - } - ++itr; + refField = &f; + + break; } + ++itr; } if (!refField) @@ -216,6 +203,11 @@ ConsoleMethod(GuiInspectorComponentGroup, inspectGroup, bool, 2, 2, "Refreshes t void GuiInspectorComponentGroup::clearFields() { + // delete everything else + mStack->clear(); + + // clear the mChildren list. + mChildren.clear(); } SimFieldDictionary::Entry* GuiInspectorComponentGroup::findDynamicFieldInDictionary(StringTableEntry fieldName) From 37e030f8f4128976ef7a8f194baed502ebad87d2 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 4 Jun 2016 16:47:03 -0500 Subject: [PATCH 70/71] Makes vehicles work with the physics plugins. Makes vehicles create a basic physics body when using one of the physics plugins so that they can collide with other physics-enabled objects. Based on @rextimmy 's work. --- Engine/source/T3D/physics/bullet/btBody.cpp | 22 +++++++ Engine/source/T3D/physics/bullet/btBody.h | 2 + Engine/source/T3D/physics/physicsBody.h | 4 ++ Engine/source/T3D/physics/physx3/px3Body.cpp | 19 ++++++ Engine/source/T3D/physics/physx3/px3Body.h | 2 + Engine/source/T3D/physics/physx3/px3World.cpp | 59 ++++++++++++++++++- Engine/source/T3D/physics/physx3/px3World.h | 5 ++ Engine/source/T3D/vehicles/vehicle.cpp | 43 +++++++++++++- Engine/source/T3D/vehicles/vehicle.h | 7 +++ 9 files changed, 161 insertions(+), 2 deletions(-) diff --git a/Engine/source/T3D/physics/bullet/btBody.cpp b/Engine/source/T3D/physics/bullet/btBody.cpp index 77c3b8115..95625d520 100644 --- a/Engine/source/T3D/physics/bullet/btBody.cpp +++ b/Engine/source/T3D/physics/bullet/btBody.cpp @@ -378,3 +378,25 @@ void BtBody::setSimulationEnabled( bool enabled ) mIsEnabled = enabled; } + +void BtBody::moveKinematicTo(const MatrixF &transform) +{ + AssertFatal(mActor, "BtBody::moveKinematicTo - The actor is null!"); + + U32 bodyflags = mActor->getCollisionFlags(); + const bool isKinematic = bodyflags & BF_KINEMATIC; + if (!isKinematic) + { + Con::errorf("BtBody::moveKinematicTo is only for kinematic bodies."); + return; + } + + if (mCenterOfMass) + { + MatrixF xfm; + xfm.mul(transform, *mCenterOfMass); + mActor->setCenterOfMassTransform(btCast(xfm)); + } + else + mActor->setCenterOfMassTransform(btCast(transform)); +} \ No newline at end of file diff --git a/Engine/source/T3D/physics/bullet/btBody.h b/Engine/source/T3D/physics/bullet/btBody.h index 0f1ab669c..fa6561c27 100644 --- a/Engine/source/T3D/physics/bullet/btBody.h +++ b/Engine/source/T3D/physics/bullet/btBody.h @@ -111,6 +111,8 @@ public: F32 staticFriction ); virtual void applyCorrection( const MatrixF &xfm ); virtual void applyImpulse( const Point3F &origin, const Point3F &force ); + virtual void moveKinematicTo(const MatrixF &xfm); + }; #endif // _T3D_PHYSICS_BTBODY_H_ diff --git a/Engine/source/T3D/physics/physicsBody.h b/Engine/source/T3D/physics/physicsBody.h index 15e94bcbd..a5250dea6 100644 --- a/Engine/source/T3D/physics/physicsBody.h +++ b/Engine/source/T3D/physics/physicsBody.h @@ -113,6 +113,10 @@ public: /// virtual void applyImpulse( const Point3F &origin, const Point3F &force ) = 0; + + /// + virtual void moveKinematicTo(const MatrixF &xfm) = 0; + }; diff --git a/Engine/source/T3D/physics/physx3/px3Body.cpp b/Engine/source/T3D/physics/physx3/px3Body.cpp index 026309f08..e2fc3916f 100644 --- a/Engine/source/T3D/physics/physx3/px3Body.cpp +++ b/Engine/source/T3D/physics/physx3/px3Body.cpp @@ -417,3 +417,22 @@ void Px3Body::applyImpulse( const Point3F &origin, const Point3F &force ) } +void Px3Body::moveKinematicTo(const MatrixF &transform) +{ + AssertFatal(mActor, "Px3Body::moveKinematicTo - The actor is null!"); + + const bool isKinematic = mBodyFlags & BF_KINEMATIC; + if (!isKinematic) + { + Con::errorf("Px3Body::moveKinematicTo is only for kinematic bodies."); + return; + } + + mWorld->lockScene(); + + physx::PxRigidDynamic *actor = mActor->is(); + actor->setKinematicTarget(px3Cast(transform)); + + mWorld->unlockScene(); +} + diff --git a/Engine/source/T3D/physics/physx3/px3Body.h b/Engine/source/T3D/physics/physx3/px3Body.h index 79096f57b..223418c35 100644 --- a/Engine/source/T3D/physics/physx3/px3Body.h +++ b/Engine/source/T3D/physics/physx3/px3Body.h @@ -117,6 +117,8 @@ public: F32 staticFriction ); virtual void applyCorrection( const MatrixF &xfm ); virtual void applyImpulse( const Point3F &origin, const Point3F &force ); + virtual void moveKinematicTo(const MatrixF &xfm); + }; #endif // _PX3BODY_H_ diff --git a/Engine/source/T3D/physics/physx3/px3World.cpp b/Engine/source/T3D/physics/physx3/px3World.cpp index c073423e9..ca5be2302 100644 --- a/Engine/source/T3D/physics/physx3/px3World.cpp +++ b/Engine/source/T3D/physics/physx3/px3World.cpp @@ -62,7 +62,8 @@ Px3World::Px3World(): mScene( NULL ), mIsEnabled( false ), mEditorTimeScale( 1.0f ), mAccumulator( 0 ), - mControllerManager( NULL ) + mControllerManager(NULL), + mIsSceneLocked(false) { } @@ -335,6 +336,62 @@ void Px3World::releaseWriteLock() //AssertFatal( mScene->isWritable(), "PhysX3World::releaseWriteLock() - We should have been writable now!" ); } +void Px3World::lockScenes() +{ + Px3World *world = dynamic_cast(PHYSICSMGR->getWorld("server")); + + if (world) + world->lockScene(); + + world = dynamic_cast(PHYSICSMGR->getWorld("client")); + + if (world) + world->lockScene(); +} + +void Px3World::unlockScenes() +{ + Px3World *world = dynamic_cast(PHYSICSMGR->getWorld("server")); + + if (world) + world->unlockScene(); + + world = dynamic_cast(PHYSICSMGR->getWorld("client")); + + if (world) + world->unlockScene(); +} + +void Px3World::lockScene() +{ + if (!mScene) + return; + + if (mIsSceneLocked) + { + Con::printf("Px3World: Attempting to lock a scene that is already locked."); + return; + } + + mScene->lockWrite(); + mIsSceneLocked = true; +} + +void Px3World::unlockScene() +{ + if (!mScene) + return; + + if (!mIsSceneLocked) + { + Con::printf("Px3World: Attempting to unlock a scene that is not locked."); + return; + } + + mScene->unlockWrite(); + mIsSceneLocked = false; +} + bool Px3World::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse ) { diff --git a/Engine/source/T3D/physics/physx3/px3World.h b/Engine/source/T3D/physics/physx3/px3World.h index a1235d160..9556aac4b 100644 --- a/Engine/source/T3D/physics/physx3/px3World.h +++ b/Engine/source/T3D/physics/physx3/px3World.h @@ -56,6 +56,7 @@ protected: bool mIsEnabled; bool mIsSimulating; bool mIsServer; + bool mIsSceneLocked; U32 mTickCount; ProcessList *mProcessList; F32 mEditorTimeScale; @@ -96,11 +97,15 @@ public: void releaseWriteLock(); bool isServer(){return mIsServer;} physx::PxController* createController( physx::PxControllerDesc &desc ); + void lockScene(); + void unlockScene(); //static static bool restartSDK( bool destroyOnly = false, Px3World *clientWorld = NULL, Px3World *serverWorld = NULL ); static void releaseWriteLocks(); static physx::PxCooking *getCooking(); static void setTiming(F32 stepTime,U32 maxIterations); + static void lockScenes(); + static void unlockScenes(); }; #endif // _PX3WORLD_H_ diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index 1f18b426f..b6516fc3f 100644 --- a/Engine/source/T3D/vehicles/vehicle.cpp +++ b/Engine/source/T3D/vehicles/vehicle.cpp @@ -46,6 +46,9 @@ #include "gfx/primBuilder.h" #include "gfx/gfxDrawUtil.h" #include "materials/materialDefinition.h" +#include "T3D/physics/physicsPlugin.h" +#include "T3D/physics/physicsBody.h" +#include "T3D/physics/physicsCollision.h" namespace { @@ -203,7 +206,8 @@ VehicleData::VehicleData() dMemset(waterSound, 0, sizeof(waterSound)); collDamageThresholdVel = 20; - collDamageMultiplier = 0.05f; + collDamageMultiplier = 0.05f; + enablePhysicsRep = true; } @@ -315,6 +319,7 @@ void VehicleData::packData(BitStream* stream) stream->write(softSplashSoundVel); stream->write(medSplashSoundVel); stream->write(hardSplashSoundVel); + stream->write(enablePhysicsRep); // write the water sound profiles for(i = 0; i < MaxSounds; i++) @@ -411,6 +416,7 @@ void VehicleData::unpackData(BitStream* stream) stream->read(&softSplashSoundVel); stream->read(&medSplashSoundVel); stream->read(&hardSplashSoundVel); + stream->read(&enablePhysicsRep); // write the water sound profiles for(i = 0; i < MaxSounds; i++) @@ -465,6 +471,11 @@ void VehicleData::unpackData(BitStream* stream) void VehicleData::initPersistFields() { + addGroup("Physics"); + addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, VehicleData), + "@brief Creates a representation of the object in the physics plugin.\n"); + endGroup("Physics"); + addField( "jetForce", TypeF32, Offset(jetForce, VehicleData), "@brief Additional force applied to the vehicle when it is jetting.\n\n" "For WheeledVehicles, the force is applied in the forward direction. For " @@ -682,6 +693,8 @@ Vehicle::Vehicle() mWorkingQueryBox.minExtents.set(-1e9f, -1e9f, -1e9f); mWorkingQueryBox.maxExtents.set(-1e9f, -1e9f, -1e9f); mWorkingQueryBoxCountDown = sWorkingQueryBoxStaleThreshold; + + mPhysicsRep = NULL; } U32 Vehicle::getCollisionMask() @@ -695,6 +708,25 @@ Point3F Vehicle::getVelocity() const return mRigid.linVelocity; } +void Vehicle::_createPhysics() +{ + SAFE_DELETE(mPhysicsRep); + + if (!PHYSICSMGR || !mDataBlock->enablePhysicsRep) + return; + + TSShape *shape = mShapeInstance->getShape(); + PhysicsCollision *colShape = NULL; + colShape = shape->buildColShape(false, getScale()); + + if (colShape) + { + PhysicsWorld *world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); + mPhysicsRep = PHYSICSMGR->createBody(); + mPhysicsRep->init(colShape, 0, PhysicsBody::BF_KINEMATIC, this, world); + mPhysicsRep->setTransform(getTransform()); + } +} //---------------------------------------------------------------------------- bool Vehicle::onAdd() @@ -776,11 +808,15 @@ bool Vehicle::onAdd() mConvex.box.maxExtents.convolve(mObjScale); mConvex.findNodeTransform(); + _createPhysics(); + return true; } void Vehicle::onRemove() { + SAFE_DELETE(mPhysicsRep); + U32 i=0; for( i=0; ienablePhysicsRep is false as mPhysicsRep will be NULL if it is + if (mPhysicsRep) + mPhysicsRep->moveKinematicTo(getTransform()); } } diff --git a/Engine/source/T3D/vehicles/vehicle.h b/Engine/source/T3D/vehicles/vehicle.h index 695c16686..dd8619fd6 100644 --- a/Engine/source/T3D/vehicles/vehicle.h +++ b/Engine/source/T3D/vehicles/vehicle.h @@ -127,6 +127,8 @@ struct VehicleData: public ShapeBaseData F32 splashFreqMod; F32 splashVelEpsilon; + bool enablePhysicsRep; + // VehicleData(); bool preload(bool server, String &errorStr); @@ -142,6 +144,7 @@ struct VehicleData: public ShapeBaseData //---------------------------------------------------------------------------- +class PhysicsBody; class Vehicle: public ShapeBase { @@ -177,6 +180,8 @@ class Vehicle: public ShapeBase Point3F cameraRotVec; }; + PhysicsBody *mPhysicsRep; + StateDelta mDelta; S32 mPredictionCount; ///< Number of ticks to predict VehicleData* mDataBlock; @@ -262,6 +267,8 @@ public: bool onAdd(); void onRemove(); + void _createPhysics(); + /// Interpolates between move ticks @see processTick /// @param dt Change in time between the last call and this call to the function void interpolateTick(F32 dt); From 0ec9438429ea745f8e72397c714496bc97cd6de8 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 6 Jun 2016 21:20:00 -0500 Subject: [PATCH 71/71] The default configuration is for the asset database to automatically unload an asset when it's no longer referenced. This causes problems when we would delete objects and then go to make more instances that reference the same asset while the same mission is going. So autounload is disabled to prevent excessive unloading of assets before the level is concluded. --- Engine/source/T3D/assets/ShapeAsset.cpp | 6 ++++-- Engine/source/T3D/assets/ShapeAsset.h | 2 +- Engine/source/T3D/components/render/meshComponent.cpp | 3 ++- Engine/source/assets/assetManager.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Engine/source/T3D/assets/ShapeAsset.cpp b/Engine/source/T3D/assets/ShapeAsset.cpp index 9b2aec3de..ea4882add 100644 --- a/Engine/source/T3D/assets/ShapeAsset.cpp +++ b/Engine/source/T3D/assets/ShapeAsset.cpp @@ -100,8 +100,6 @@ mAcquireReferenceCount(0), mpOwningAssetManager(NULL), mAssetInitialized(false) { - // Generate an asset definition. - mpAssetDefinition = new AssetDefinition(); } //----------------------------------------------------------------------------- @@ -154,4 +152,8 @@ void ShapeAsset::copyTo(SimObject* object) { // Call to parent. Parent::copyTo(object); +} + +void ShapeAsset::onAssetRefresh(void) +{ } \ No newline at end of file diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index 6766d1682..d727d0a1c 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -79,7 +79,7 @@ public: Resource getShapeResource() { return mShape; } protected: - virtual void onAssetRefresh(void) {} + virtual void onAssetRefresh(void); }; DefineConsoleType(TypeShapeAssetPtr, ShapeAsset) diff --git a/Engine/source/T3D/components/render/meshComponent.cpp b/Engine/source/T3D/components/render/meshComponent.cpp index 6f4835666..708a48ae1 100644 --- a/Engine/source/T3D/components/render/meshComponent.cpp +++ b/Engine/source/T3D/components/render/meshComponent.cpp @@ -167,7 +167,8 @@ bool MeshComponent::setMeshAsset(const char* assetName) { // Fetch the asset Id. mMeshAssetId = StringTable->insert(assetName); - mMeshAsset.setAssetId(mMeshAssetId); + + mMeshAsset = mMeshAssetId; if (mMeshAsset.isNull()) { diff --git a/Engine/source/assets/assetManager.cpp b/Engine/source/assets/assetManager.cpp index bfd21c699..66df77d11 100644 --- a/Engine/source/assets/assetManager.cpp +++ b/Engine/source/assets/assetManager.cpp @@ -76,7 +76,7 @@ AssetManager::AssetManager() : mMaxLoadedPrivateAssetsCount( 0 ), mAcquiredReferenceCount( 0 ), mEchoInfo( false ), - mIgnoreAutoUnload( false ) + mIgnoreAutoUnload( true ) { }