tsStatic.cpp
Engine/source/T3D/tsStatic.cpp
Public Variables
Public Functions
ConsoleDocClass(TSStatic , "@brief A static object derived from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D model <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and placed within the game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "<a href="/coding/class/classtsstatic/">TSStatic</a> is the most basic 3D shape in Torque. Unlike <a href="/coding/class/classstaticshape/">StaticShape</a> it doesn'<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> make use of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock. It derrives directly from SceneObject. This makes <a href="/coding/class/classtsstatic/">TSStatic</a> extremely light " " weight, which is why the Tools use this class when you want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> drop in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> DTS or DAE <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "While <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classtsstatic/">TSStatic</a> doesn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> provide any motion -- it stays were you initally put it -- it does allow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single ambient animation sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the object is first added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classtsstatic/">TSStatic</a>(Team1Base) {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeName=\"art/shapes/desertStructures/station01.dts\";\n" " playAmbient = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " receiveSunLight = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " receiveLMLighting = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " useCustomAmbientLighting = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " customAmbientLighting = \"0 0 0 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " collisionType = \"Visible Mesh\";\n" " decalType = \"Collision Mesh\";\n" " allowPlayerStep = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " renderNormals = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " forceDetail = \"-1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = \"315.18 -180.418 244.313\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " rotation = \"0 0 1 195.952\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " scale = \"1 1 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " isRenderEnabled = \"true\";\n" " canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(TSStatic , changeMaterial , void , (const char *mapTo, Material *oldMat, Material *newMat) , ("", nullAsType< Material * >(), nullAsType< Material * >()) , "@brief Change one of the materials on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "This method changes materials per mapTo with others. The material that " "is being replaced is mapped <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> unmapped_mat as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> part of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transition.\n</a>" "@note Warning)
DefineEngineMethod(TSStatic , getModelFile , const char * , () )
DefineEngineMethod(TSStatic , getTargetCount , S32 , () , "Get the number of materials in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@return the number of materials in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@see getTargetName()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(TSStatic , getTargetName , const char * , (S32 index) , (0) , "Get the name of the indexed shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">material.\n</a>" "@param index index of the material <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get (valid range is 0 - getTargetCount()-1).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return the name of the indexed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">material.\n</a>" "@see getTargetCount()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
ImplementEnumType(TSMeshType , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )
Detailed Description
Public Variables
F32 AnimSpeedMax
EndImplementEnumType
bool gEditingMission
For frame signal.
FRangeValidator percentValidator (0.0f, 1.0f)
FRangeValidator speedValidator (0.0f, AnimSpeedMax)
Public Functions
ConsoleDocClass(TSStatic , "@brief A static object derived from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 3D model <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and placed within the game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "<a href="/coding/class/classtsstatic/">TSStatic</a> is the most basic 3D shape in Torque. Unlike <a href="/coding/class/classstaticshape/">StaticShape</a> it doesn'<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> make use of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock. It derrives directly from SceneObject. This makes <a href="/coding/class/classtsstatic/">TSStatic</a> extremely light " " weight, which is why the Tools use this class when you want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> drop in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> DTS or DAE <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "While <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classtsstatic/">TSStatic</a> doesn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> provide any motion -- it stays were you initally put it -- it does allow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single ambient animation sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the object is first added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classtsstatic/">TSStatic</a>(Team1Base) {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeName=\"art/shapes/desertStructures/station01.dts\";\n" " playAmbient = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " receiveSunLight = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " receiveLMLighting = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " useCustomAmbientLighting = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " customAmbientLighting = \"0 0 0 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " collisionType = \"Visible Mesh\";\n" " decalType = \"Collision Mesh\";\n" " allowPlayerStep = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " renderNormals = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " forceDetail = \"-1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = \"315.18 -180.418 244.313\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " rotation = \"0 0 1 195.952\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " scale = \"1 1 1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " isRenderEnabled = \"true\";\n" " canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(TSStatic , changeMaterial , void , (const char *mapTo, Material *oldMat, Material *newMat) , ("", nullAsType< Material * >(), nullAsType< Material * >()) , "@brief Change one of the materials on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "This method changes materials per mapTo with others. The material that " "is being replaced is mapped <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> unmapped_mat as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> part of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transition.\n</a>" "@note Warning)
DefineEngineMethod(TSStatic , getModelFile , const char * , () )
DefineEngineMethod(TSStatic , getTargetCount , S32 , () , "Get the number of materials in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@return the number of materials in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@see getTargetName()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(TSStatic , getTargetName , const char * , (S32 index) , (0) , "Get the name of the indexed shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">material.\n</a>" "@param index index of the material <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get (valid range is 0 - getTargetCount()-1).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return the name of the indexed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">material.\n</a>" "@see getTargetCount()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
IMPLEMENT_CO_NETOBJECT_V1(TSStatic )
ImplementEnumType(TSMeshType , "Type of mesh data available in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n</a>" "@ingroup gameObjects" )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "T3D/tsStatic.h" 31 32#include "core/resourceManager.h" 33#include "core/stream/bitStream.h" 34#include "scene/sceneRenderState.h" 35#include "scene/sceneManager.h" 36#include "scene/sceneObjectLightingPlugin.h" 37#include "lighting/lightManager.h" 38#include "math/mathIO.h" 39#include "ts/tsShapeInstance.h" 40#include "ts/tsMaterialList.h" 41#include "console/consoleTypes.h" 42#include "T3D/shapeBase.h" 43#include "sim/netConnection.h" 44#include "gfx/gfxDevice.h" 45#include "gfx/gfxTransformSaver.h" 46#include "ts/tsRenderState.h" 47#include "collision/boxConvex.h" 48#include "T3D/physics/physicsPlugin.h" 49#include "T3D/physics/physicsBody.h" 50#include "T3D/physics/physicsCollision.h" 51#include "materials/materialDefinition.h" 52#include "materials/materialManager.h" 53#include "materials/matInstance.h" 54#include "materials/materialFeatureData.h" 55#include "materials/materialFeatureTypes.h" 56#include "console/engineAPI.h" 57#include "T3D/accumulationVolume.h" 58 59#include "gui/editor/inspector/group.h" 60#include "console/typeValidators.h" 61using namespace Torque; 62 63extern bool gEditingMission; 64#ifdef TORQUE_AFX_ENABLED 65#include "afx/ce/afxZodiacMgr.h" 66#endif 67 68IMPLEMENT_CO_NETOBJECT_V1(TSStatic); 69 70ConsoleDocClass(TSStatic, 71 "@brief A static object derived from a 3D model file and placed within the game world.\n\n" 72 73 "TSStatic is the most basic 3D shape in Torque. Unlike StaticShape it doesn't make use of " 74 "a datablock. It derrives directly from SceneObject. This makes TSStatic extremely light " 75 "weight, which is why the Tools use this class when you want to drop in a DTS or DAE object.\n\n" 76 77 "While a TSStatic doesn't provide any motion -- it stays were you initally put it -- it does allow for " 78 "a single ambient animation sequence to play when the object is first added to the scene.\n\n" 79 80 "@tsexample\n" 81 "new TSStatic(Team1Base) {\n" 82 " shapeName = \"art/shapes/desertStructures/station01.dts\";\n" 83 " playAmbient = \"1\";\n" 84 " receiveSunLight = \"1\";\n" 85 " receiveLMLighting = \"1\";\n" 86 " useCustomAmbientLighting = \"0\";\n" 87 " customAmbientLighting = \"0 0 0 1\";\n" 88 " collisionType = \"Visible Mesh\";\n" 89 " decalType = \"Collision Mesh\";\n" 90 " allowPlayerStep = \"1\";\n" 91 " renderNormals = \"0\";\n" 92 " forceDetail = \"-1\";\n" 93 " position = \"315.18 -180.418 244.313\";\n" 94 " rotation = \"0 0 1 195.952\";\n" 95 " scale = \"1 1 1\";\n" 96 " isRenderEnabled = \"true\";\n" 97 " canSaveDynamicFields = \"1\";\n" 98 "};\n" 99 "@endtsexample\n" 100 101 "@ingroup gameObjects\n" 102); 103 104bool TSStatic::smUseStaticObjectFade = false; 105F32 TSStatic::smStaticObjectFadeStart = 50; 106F32 TSStatic::smStaticObjectFadeEnd = 75; 107F32 TSStatic::smStaticObjectUnfadeableSize = 75; 108 109TSStatic::TSStatic() 110 : 111 cubeDescId(0), 112 reflectorDesc(NULL) 113{ 114 mNetFlags.set(Ghostable | ScopeAlways); 115 116 mTypeMask |= StaticObjectType | StaticShapeObjectType; 117 118 mShapeName = ""; 119 mShapeInstance = NULL; 120 121 mPlayAmbient = true; 122 mAmbientThread = NULL; 123 124 mAllowPlayerStep = false; 125 126 mConvexList = new Convex; 127 128 mRenderNormalScalar = 0; 129 mForceDetail = -1; 130 131 mMeshCulling = false; 132 mUseOriginSort = false; 133 134 mUseAlphaFade = false; 135 mAlphaFadeStart = 100.0f; 136 mAlphaFadeEnd = 150.0f; 137 mInvertAlphaFade = false; 138 mAlphaFade = 1.0f; 139 mPhysicsRep = NULL; 140 141 mCollisionType = CollisionMesh; 142 mDecalType = CollisionMesh; 143 144 mIgnoreZodiacs = false; 145 mHasGradients = false; 146 mInvertGradientRange = false; 147 mGradientRangeUser.set(0.0f, 180.0f); 148#ifdef TORQUE_AFX_ENABLED 149 afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser); 150#endif 151 mAnimOffset = 0.0f; 152 mAnimSpeed = 1.0f; 153 154 mShapeAsset = StringTable->EmptyString(); 155 mShapeAssetId = StringTable->EmptyString(); 156} 157 158TSStatic::~TSStatic() 159{ 160 delete mConvexList; 161 mConvexList = NULL; 162} 163 164ImplementEnumType(TSMeshType, 165 "Type of mesh data available in a shape.\n" 166 "@ingroup gameObjects") 167{ 168 TSStatic::None, "None", "No mesh data." 169}, 170 { TSStatic::Bounds, "Bounds", "Bounding box of the shape." }, 171 { TSStatic::CollisionMesh, "Collision Mesh", "Specifically desingated \"collision\" meshes." }, 172 { TSStatic::VisibleMesh, "Visible Mesh", "Rendered mesh polygons." }, 173 EndImplementEnumType; 174 175FRangeValidator percentValidator(0.0f, 1.0f); 176F32 AnimSpeedMax = 4.0f; 177FRangeValidator speedValidator(0.0f, AnimSpeedMax); 178 179void TSStatic::initPersistFields() 180{ 181 addFieldV("AnimOffset", TypeF32, Offset(mAnimOffset, TSStatic), &percentValidator, 182 "Percent Animation Offset."); 183 184 addFieldV("AnimSpeed", TypeF32, Offset(mAnimSpeed, TSStatic), &speedValidator, 185 "Percent Animation Speed."); 186 addGroup("Shape"); 187 188 addProtectedField("shapeAsset", TypeShapeAssetId, Offset(mShapeAssetId, TSStatic), 189 &TSStatic::_setShapeAsset, &defaultProtectedGetFn, 190 "The source shape asset."); 191 192 addProtectedField("shapeName", TypeShapeFilename, Offset(mShapeName, TSStatic), 193 &TSStatic::_setShapeName, &defaultProtectedGetFn, 194 "%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic. Legacy field. Any loose files assigned here will attempt to be auto-imported in as an asset."); 195 196 endGroup("Shape"); 197 198 addGroup("Materials"); 199 addProtectedField("skin", TypeRealString, Offset(mAppliedSkinName, TSStatic), &_setFieldSkin, &_getFieldSkin, 200 "@brief The skin applied to the shape.\n\n" 201 202 "'Skinning' the shape effectively renames the material targets, allowing " 203 "different materials to be used on different instances of the same model.\n\n" 204 205 "Any material targets that start with the old skin name have that part " 206 "of the name replaced with the new skin name. The initial old skin name is " 207 "\"base\". For example, if a new skin of \"blue\" was applied to a model " 208 "that had material targets <i>base_body</i> and <i>face</i>, the new targets " 209 "would be <i>blue_body</i> and <i>face</i>. Note that <i>face</i> was not " 210 "renamed since it did not start with the old skin name of \"base\".\n\n" 211 212 "To support models that do not use the default \"base\" naming convention, " 213 "you can also specify the part of the name to replace in the skin field " 214 "itself. For example, if a model had a material target called <i>shapemat</i>, " 215 "we could apply a new skin \"shape=blue\", and the material target would be " 216 "renamed to <i>bluemat</i> (note \"shape\" has been replaced with \"blue\").\n\n" 217 218 "Multiple skin updates can also be applied at the same time by separating " 219 "them with a semicolon. For example: \"base=blue;face=happy_face\".\n\n" 220 221 "Material targets are only renamed if an existing Material maps to that " 222 "name, or if there is a diffuse texture in the model folder with the same " 223 "name as the new target.\n\n"); 224 endGroup("Materials"); 225 226 addGroup("Rendering"); 227 228 addField("playAmbient", TypeBool, Offset(mPlayAmbient, TSStatic), 229 "Enables automatic playing of the animation sequence named \"ambient\" (if it exists) when the TSStatic is loaded."); 230 addField("meshCulling", TypeBool, Offset(mMeshCulling, TSStatic), 231 "Enables detailed culling of meshes within the TSStatic. Should only be used " 232 "with large complex shapes like buildings which contain many submeshes."); 233 addField("originSort", TypeBool, Offset(mUseOriginSort, TSStatic), 234 "Enables translucent sorting of the TSStatic by its origin instead of the bounds."); 235 236 endGroup("Rendering"); 237 238 addGroup("Reflection"); 239 addField("cubeReflectorDesc", TypeRealString, Offset(cubeDescName, TSStatic), 240 "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n"); 241 endGroup("Reflection"); 242 243 addGroup("Collision"); 244 245 addField("collisionType", TypeTSMeshType, Offset(mCollisionType, TSStatic), 246 "The type of mesh data to use for collision queries."); 247 addField("decalType", TypeTSMeshType, Offset(mDecalType, TSStatic), 248 "The type of mesh data used to clip decal polygons against."); 249 addField("allowPlayerStep", TypeBool, Offset(mAllowPlayerStep, TSStatic), 250 "@brief Allow a Player to walk up sloping polygons in the TSStatic (based on the collisionType).\n\n" 251 "When set to false, the slightest bump will stop the player from walking on top of the object.\n"); 252 253 endGroup("Collision"); 254 255 addGroup("AlphaFade"); 256 addField("alphaFadeEnable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade"); 257 addField("alphaFadeStart", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade"); 258 addField("alphaFadeEnd", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade"); 259 addField("alphaFadeInverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance"); 260 endGroup("AlphaFade"); 261 262 addGroup("Debug"); 263 264 addField("renderNormals", TypeF32, Offset(mRenderNormalScalar, TSStatic), 265 "Debug rendering mode shows the normals for each point in the TSStatic's mesh."); 266 addField("forceDetail", TypeS32, Offset(mForceDetail, TSStatic), 267 "Forces rendering to a particular detail level."); 268 269 endGroup("Debug"); 270 271 addGroup("AFX"); 272 addField("ignoreZodiacs", TypeBool, Offset(mIgnoreZodiacs, TSStatic)); 273 addField("useGradientRange", TypeBool, Offset(mHasGradients, TSStatic)); 274 addField("gradientRange", TypePoint2F, Offset(mGradientRangeUser, TSStatic)); 275 addField("invertGradientRange", TypeBool, Offset(mInvertGradientRange, TSStatic)); 276 endGroup("AFX"); 277 Parent::initPersistFields(); 278} 279 280void TSStatic::consoleInit() 281{ 282 Parent::consoleInit(); 283 284 // Vars for debug rendering while the RoadEditor is open, only used if smEditorOpen is true. 285 Con::addVariable("$pref::useStaticObjectFade", TypeBool, &TSStatic::smUseStaticObjectFade, "Indicates if all statics should utilize the distance-based object fadeout logic.\n"); 286 Con::addVariable("$pref::staticObjectFadeStart", TypeF32, &TSStatic::smStaticObjectFadeStart, "Distance at which static object fading begins if $pref::useStaticObjectFade is on.\n"); 287 Con::addVariable("$pref::staticObjectFadeEnd", TypeF32, &TSStatic::smStaticObjectFadeEnd, "Distance at which static object fading should have fully faded if $pref::useStaticObjectFade is on.\n"); 288 Con::addVariable("$pref::staticObjectUnfadeableSize", TypeF32, &TSStatic::smStaticObjectUnfadeableSize, "Size of object where if the bounds is at or bigger than this, it will be ignored in the $pref::useStaticObjectFade logic. Useful for very large, distance-important objects.\n"); 289} 290 291bool TSStatic::_setShapeAsset(void* obj, const char* index, const char* data) 292{ 293 TSStatic* ts = static_cast<TSStatic*>(obj);// ->setFile(FileName(data)); 294 295 ts->mShapeAssetId = StringTable->insert(data); 296 297 return ts->setShapeAsset(ts->mShapeAssetId); 298} 299 300bool TSStatic::_setShapeName(void* obj, const char* index, const char* data) 301{ 302 TSStatic* ts = static_cast<TSStatic*>(obj);// ->setFile(FileName(data)); 303 304 StringTableEntry assetId = ShapeAsset::getAssetIdByFilename(StringTable->insert(data)); 305 if (assetId != StringTable->EmptyString()) 306 { 307 //Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break 308 //the TSStatic 309 if (ts->setShapeAsset(assetId)) 310 { 311 if (assetId == StringTable->insert("Core_Rendering:noShape")) 312 { 313 ts->mShapeName = data; 314 ts->mShapeAssetId = StringTable->EmptyString(); 315 316 return true; 317 } 318 else 319 { 320 ts->mShapeAssetId = assetId; 321 ts->mShapeName = StringTable->EmptyString(); 322 323 return false; 324 } 325 } 326 } 327 else 328 { 329 ts->mShapeAsset = StringTable->EmptyString(); 330 } 331 332 return true; 333} 334 335bool TSStatic::_setFieldSkin(void* object, const char* index, const char* data) 336{ 337 TSStatic* ts = static_cast<TSStatic*>(object); 338 if (ts) 339 ts->setSkinName(data); 340 return false; 341} 342 343const char* TSStatic::_getFieldSkin(void* object, const char* data) 344{ 345 TSStatic* ts = static_cast<TSStatic*>(object); 346 return ts ? ts->mSkinNameHandle.getString() : ""; 347} 348 349void TSStatic::inspectPostApply() 350{ 351 // Apply any transformations set in the editor 352 Parent::inspectPostApply(); 353 354 if (isServerObject()) 355 { 356 setMaskBits(-1); 357 prepCollision(); 358 } 359 360 _updateShouldTick(); 361} 362 363bool TSStatic::onAdd() 364{ 365 PROFILE_SCOPE(TSStatic_onAdd); 366 367 if (isServerObject()) 368 { 369 // Handle the old "usePolysoup" field 370 SimFieldDictionary* fieldDict = getFieldDictionary(); 371 372 if (fieldDict) 373 { 374 StringTableEntry slotName = StringTable->insert("usePolysoup"); 375 376 SimFieldDictionary::Entry* entry = fieldDict->findDynamicField(slotName); 377 378 if (entry) 379 { 380 // Was "usePolysoup" set? 381 bool usePolysoup = dAtob(entry->value); 382 383 // "usePolysoup" maps to the new VisibleMesh type 384 if (usePolysoup) 385 mCollisionType = VisibleMesh; 386 387 // Remove the field in favor on the new "collisionType" field 388 fieldDict->setFieldValue(slotName, ""); 389 } 390 } 391 } 392 393 if (!Parent::onAdd()) 394 return false; 395 396 // Setup the shape. 397 if (!_createShape()) 398 { 399 Con::errorf("TSStatic::onAdd() - Shape creation failed!"); 400 return false; 401 } 402 403 setRenderTransform(mObjToWorld); 404 405 // Register for the resource change signal. 406 //ResourceManager::get().getChangedSignal().notify(this, &TSStatic::_onResourceChanged); 407 408 addToScene(); 409 410 if (isClientObject()) 411 { 412 mCubeReflector.unregisterReflector(); 413 414 if (reflectorDesc) 415 mCubeReflector.registerReflector(this, reflectorDesc); 416 } 417 418 _updateShouldTick(); 419 420 // Accumulation and environment mapping 421 if (isClientObject() && mShapeInstance) 422 { 423 AccumulationVolume::addObject(this); 424 } 425 426 return true; 427} 428 429bool TSStatic::setShapeAsset(const StringTableEntry shapeAssetId) 430{ 431 if (!mShapeAsset.isNull()) 432 { 433 mShapeAsset->getChangedSignal().remove(this, &TSStatic::_onAssetChanged); 434 } 435 436 if (ShapeAsset::getAssetById(shapeAssetId, &mShapeAsset)) 437 { 438 //Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break 439 //the TSStatic 440 if (mShapeAsset.getAssetId() != StringTable->insert("Core_Rendering:noshape")) 441 { 442 mShapeName = StringTable->EmptyString(); 443 444 mShapeAsset->getChangedSignal().notify(this, &TSStatic::_onAssetChanged); 445 } 446 447 _createShape(); 448 449 setMaskBits(-1); 450 451 return true; 452 } 453 454 return false; 455} 456 457bool TSStatic::_createShape() 458{ 459 // Cleanup before we create. 460 mCollisionDetails.clear(); 461 mDecalDetails.clear(); 462 mDecalDetailsPtr = 0; 463 mLOSDetails.clear(); 464 SAFE_DELETE(mPhysicsRep); 465 SAFE_DELETE(mShapeInstance); 466 mAmbientThread = NULL; 467 mShape = NULL; 468 469 if(!mShapeAsset.isNull()) 470 { 471 //Special-case handling, usually because we set noShape 472 mShape = mShapeAsset->getShapeResource(); 473 } 474 475 if (!mShape) 476 { 477 Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId()); 478 return false; 479 } 480 481 if (isClientObject() && 482 !mShape->preloadMaterialList(mShape.getPath()) && 483 NetConnection::filesWereDownloaded()) 484 return false; 485 486 mObjBox = mShape->mBounds; 487 resetWorldBox(); 488 489 mShapeInstance = new TSShapeInstance(mShape, isClientObject()); 490 if (isClientObject()) 491 mShapeInstance->cloneMaterialList(); 492 493 if (isGhost()) 494 { 495 // Reapply the current skin 496 mAppliedSkinName = ""; 497 reSkin(); 498 } 499 500 prepCollision(); 501 502 // Find the "ambient" animation if it exists 503 S32 ambientSeq = mShape->findSequence("ambient"); 504 505 if (ambientSeq > -1 && !mAmbientThread) 506 mAmbientThread = mShapeInstance->addThread(); 507 508 if ( mAmbientThread ) 509 mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset); 510 511 // Resolve CubeReflectorDesc. 512 if (cubeDescName.isNotEmpty()) 513 { 514 Sim::findObject(cubeDescName, reflectorDesc); 515 } 516 else if (cubeDescId > 0) 517 { 518 Sim::findObject(cubeDescId, reflectorDesc); 519 } 520 521 //Set up the material slot vars for easy manipulation 522 /*S32 materialCount = mShape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount(); 523 524 //Temporarily disabled until fixup of materialName->assetId lookup logic is sorted for easy persistance 525 if (isServerObject()) 526 { 527 char matFieldName[128]; 528 529 for (U32 i = 0; i < materialCount; i++) 530 { 531 StringTableEntry materialname = StringTable->insert(mShape->materialList->getMaterialName(i).c_str()); 532 533 dSprintf(matFieldName, 128, "MaterialSlot%d", i); 534 StringTableEntry matFld = StringTable->insert(matFieldName); 535 536 setDataField(matFld, NULL, materialname); 537 } 538 }*/ 539 540 return true; 541} 542 543void TSStatic::onDynamicModified(const char* slotName, const char* newValue) 544{ 545 if (FindMatch::isMatch("materialslot*", slotName, false)) 546 { 547 if (!getShape()) 548 return; 549 550 S32 slot = -1; 551 String outStr(String::GetTrailingNumber(slotName, slot)); 552 553 if (slot == -1) 554 return; 555 556 //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name 557 MaterialAsset* matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newValue); 558 if (!matAsset) 559 return; 560 561 bool found = false; 562 for (U32 i = 0; i < mChangingMaterials.size(); i++) 563 { 564 if (mChangingMaterials[i].slot == slot) 565 { 566 mChangingMaterials[i].matAsset = matAsset; 567 mChangingMaterials[i].assetId = newValue; 568 found = true; 569 } 570 } 571 572 if (!found) 573 { 574 matMap newMatMap; 575 newMatMap.slot = slot; 576 newMatMap.matAsset = matAsset; 577 newMatMap.assetId = newValue; 578 579 mChangingMaterials.push_back(newMatMap); 580 } 581 582 setMaskBits(MaterialMask); 583 } 584 585 Parent::onDynamicModified(slotName, newValue); 586} 587 588void TSStatic::prepCollision() 589{ 590 // Let the client know that the collision was updated 591 setMaskBits(UpdateCollisionMask); 592 593 // Allow the ShapeInstance to prep its collision if it hasn't already 594 if (mShapeInstance) 595 mShapeInstance->prepCollision(); 596 597 // Cleanup any old collision data 598 mCollisionDetails.clear(); 599 mDecalDetails.clear(); 600 mDecalDetailsPtr = 0; 601 mLOSDetails.clear(); 602 mConvexList->nukeList(); 603 604 if (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh) 605 { 606 mShape->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails); 607 if (mDecalType == mCollisionType) 608 { 609 mDecalDetailsPtr = &mCollisionDetails; 610 } 611 else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) 612 { 613 mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0); 614 mDecalDetailsPtr = &mDecalDetails; 615 } 616 } 617 else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh) 618 { 619 mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0); 620 mDecalDetailsPtr = &mDecalDetails; 621 } 622 623 _updatePhysics(); 624} 625 626void TSStatic::_updatePhysics() 627{ 628 SAFE_DELETE(mPhysicsRep); 629 630 if (!PHYSICSMGR || mCollisionType == None) 631 return; 632 633 PhysicsCollision* colShape = NULL; 634 if (mCollisionType == Bounds) 635 { 636 MatrixF offset(true); 637 offset.setPosition(mShape->center); 638 colShape = PHYSICSMGR->createCollision(); 639 colShape->addBox(getObjBox().getExtents() * 0.5f * mObjScale, offset); 640 } 641 else 642 colShape = mShape->buildColShape(mCollisionType == VisibleMesh, getScale()); 643 644 if (colShape) 645 { 646 PhysicsWorld* world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client"); 647 mPhysicsRep = PHYSICSMGR->createBody(); 648 mPhysicsRep->init(colShape, 0, 0, this, world); 649 mPhysicsRep->setTransform(getTransform()); 650 } 651} 652 653void TSStatic::onRemove() 654{ 655 SAFE_DELETE(mPhysicsRep); 656 657 // Accumulation 658 if (isClientObject() && mShapeInstance) 659 { 660 if (mShapeInstance->hasAccumulation()) 661 AccumulationVolume::removeObject(this); 662 } 663 664 mConvexList->nukeList(); 665 666 removeFromScene(); 667 668 // Remove the resource change signal. 669 //ResourceManager::get().getChangedSignal().remove(this, &TSStatic::_onResourceChanged); 670 671 delete mShapeInstance; 672 mShapeInstance = NULL; 673 674 mAmbientThread = NULL; 675 if (isClientObject()) 676 mCubeReflector.unregisterReflector(); 677 678 if(!mShapeAsset.isNull()) 679 mShapeAsset->getChangedSignal().remove(this, &TSStatic::_onAssetChanged); 680 681 Parent::onRemove(); 682} 683 684void TSStatic::_onResourceChanged(const Torque::Path& path) 685{ 686 if (path != Path(mShapeName)) 687 return; 688 689 _createShape(); 690 _updateShouldTick(); 691} 692 693void TSStatic::_onAssetChanged() 694{ 695 _createShape(); 696 _updateShouldTick(); 697} 698 699void TSStatic::setSkinName(const char* name) 700{ 701 if (!isGhost()) 702 { 703 if (name[0] != '\0') 704 { 705 // Use tags for better network performance 706 // Should be a tag, but we'll convert to one if it isn't. 707 if (name[0] == StringTagPrefixByte) 708 mSkinNameHandle = NetStringHandle(U32(dAtoi(name + 1))); 709 else 710 mSkinNameHandle = NetStringHandle(name); 711 } 712 else 713 mSkinNameHandle = NetStringHandle(); 714 715 setMaskBits(SkinMask); 716 } 717} 718 719void TSStatic::reSkin() 720{ 721 if (isGhost() && mShapeInstance) 722 { 723 if (mSkinNameHandle.isValidString()) 724 { 725 mShapeInstance->resetMaterialList(); 726 Vector<String> skins; 727 String(mSkinNameHandle.getString()).split(";", skins); 728 729 for (S32 i = 0; i < skins.size(); i++) 730 { 731 String oldSkin(mAppliedSkinName.c_str()); 732 String newSkin(skins[i]); 733 734 // Check if the skin handle contains an explicit "old" base string. This 735 // allows all models to support skinning, even if they don't follow the 736 // "base_xxx" material naming convention. 737 S32 split = newSkin.find('='); // "old=new" format skin? 738 if (split != String::NPos) 739 { 740 oldSkin = newSkin.substr(0, split); 741 newSkin = newSkin.erase(0, split + 1); 742 } 743 else 744 { 745 oldSkin = ""; 746 } 747 mShapeInstance->reSkin(newSkin, oldSkin); 748 mAppliedSkinName = newSkin; 749 } 750 } 751 else 752 { 753 mShapeInstance->reSkin("", mAppliedSkinName); 754 mAppliedSkinName = ""; 755 } 756 } 757} 758 759void TSStatic::processTick(const Move* move) 760{ 761 if ( isServerObject() && mPlayAmbient && mAmbientThread ) 762 { 763 mShapeInstance->setTimeScale(mAmbientThread, mAnimSpeed); 764 mShapeInstance->advanceTime( TickSec, mAmbientThread ); 765 } 766 if (isMounted()) 767 { 768 MatrixF mat(true); 769 mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat); 770 setTransform(mat); 771 } 772} 773 774void TSStatic::interpolateTick(F32 delta) 775{ 776} 777 778void TSStatic::advanceTime(F32 dt) 779{ 780 if ( mPlayAmbient && mAmbientThread ) 781 { 782 mShapeInstance->setTimeScale(mAmbientThread, mAnimSpeed); 783 mShapeInstance->advanceTime( dt, mAmbientThread ); 784 } 785 786 if (isMounted()) 787 { 788 MatrixF mat(true); 789 mMount.object->getRenderMountTransform(dt, mMount.node, mMount.xfm, &mat); 790 setRenderTransform(mat); 791 } 792} 793 794void TSStatic::_updateShouldTick() 795{ 796 bool shouldTick = (mPlayAmbient && mAmbientThread) || isMounted(); 797 798 if (isTicking() != shouldTick) 799 setProcessTick(shouldTick); 800} 801 802void TSStatic::prepRenderImage(SceneRenderState* state) 803{ 804 if (!mShapeInstance) 805 return; 806 807 Point3F cameraOffset; 808 getRenderTransform().getColumn(3, &cameraOffset); 809 cameraOffset -= state->getDiffuseCameraPosition(); 810 F32 dist = cameraOffset.len(); 811 if (dist < 0.01f) 812 dist = 0.01f; 813 814 if (mUseAlphaFade) 815 { 816 mAlphaFade = 1.0f; 817 if ((mAlphaFadeStart < mAlphaFadeEnd) && mAlphaFadeStart > 0.1f) 818 { 819 if (mInvertAlphaFade) 820 { 821 if (dist <= mAlphaFadeStart) 822 { 823 return; 824 } 825 if (dist < mAlphaFadeEnd) 826 { 827 mAlphaFade = ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart)); 828 } 829 } 830 else 831 { 832 if (dist >= mAlphaFadeEnd) 833 { 834 return; 835 } 836 if (dist > mAlphaFadeStart) 837 { 838 mAlphaFade -= ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart)); 839 } 840 } 841 } 842 } 843 else if (smUseStaticObjectFade) 844 { 845 F32 boundsLen = getWorldSphere().radius; 846 847 if (boundsLen < smStaticObjectUnfadeableSize) 848 { 849 F32 distAdjust = (boundsLen) / (smStaticObjectUnfadeableSize); 850 distAdjust = 1 - distAdjust; 851 852 dist *= distAdjust; 853 854 mAlphaFade = 1.0f; 855 if ((smStaticObjectFadeStart < smStaticObjectFadeEnd) && smStaticObjectFadeStart > 0.1f) 856 { 857 if (dist >= smStaticObjectFadeEnd) 858 { 859 return; 860 } 861 if (dist > smStaticObjectFadeStart) 862 { 863 mAlphaFade -= ((dist - smStaticObjectFadeStart) / (smStaticObjectFadeEnd - smStaticObjectFadeStart)); 864 } 865 } 866 } 867 } 868 869 F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); 870 871 // If we're currently rendering our own reflection we 872 // don't want to render ourselves into it. 873 if (mCubeReflector.isRendering()) 874 return; 875 876 877 if (mForceDetail == -1) 878 mShapeInstance->setDetailFromDistance(state, dist * invScale); 879 else 880 mShapeInstance->setCurrentDetail(mForceDetail); 881 882 if (mShapeInstance->getCurrentDetail() < 0) 883 return; 884 885 GFXTransformSaver saver; 886 887 // Set up our TS render state. 888 TSRenderState rdata; 889 rdata.setSceneState(state); 890 rdata.setFadeOverride(1.0f); 891 rdata.setOriginSort(mUseOriginSort); 892 893 if (mCubeReflector.isEnabled()) 894 rdata.setCubemap(mCubeReflector.getCubemap()); 895 896 // Acculumation 897 rdata.setAccuTex(mAccuTex); 898 899 // If we have submesh culling enabled then prepare 900 // the object space frustum to pass to the shape. 901 Frustum culler; 902 if (mMeshCulling) 903 { 904 culler = state->getCullingFrustum(); 905 MatrixF xfm(true); 906 xfm.scale(Point3F::One / getScale()); 907 xfm.mul(getRenderWorldTransform()); 908 xfm.mul(culler.getTransform()); 909 culler.setTransform(xfm); 910 rdata.setCuller(&culler); 911 } 912 913 // We might have some forward lit materials 914 // so pass down a query to gather lights. 915 LightQuery query; 916 query.init(getWorldSphere()); 917 rdata.setLightQuery(&query); 918 919 MatrixF mat = getRenderTransform(); 920 mat.scale(mObjScale); 921 GFX->setWorldMatrix(mat); 922 923 if (state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery()) 924 { 925 RenderPassManager* pass = state->getRenderPass(); 926 OccluderRenderInst* ri = pass->allocInst<OccluderRenderInst>(); 927 928 ri->type = RenderPassManager::RIT_Occluder; 929 ri->query = mCubeReflector.getOcclusionQuery(); 930 mObjToWorld.mulP(mObjBox.getCenter(), &ri->position); 931 ri->scale.set(mObjBox.getExtents()); 932 ri->orientation = pass->allocUniqueXform(mObjToWorld); 933 ri->isSphere = false; 934 state->getRenderPass()->addInst(ri); 935 } 936 937 if (mShapeInstance) 938 { 939 mShapeInstance->animate(); 940 941 if (mUseAlphaFade || smUseStaticObjectFade) 942 { 943 mShapeInstance->setAlphaAlways(mAlphaFade); 944 S32 s = mShapeInstance->mMeshObjects.size(); 945 946 for (S32 x = 0; x < s; x++) 947 { 948 mShapeInstance->mMeshObjects[x].visible = mAlphaFade; 949 } 950 } 951 } 952 mShapeInstance->render(rdata); 953#ifdef TORQUE_AFX_ENABLED 954 if (!mIgnoreZodiacs && mDecalDetailsPtr != 0) 955 afxZodiacMgr::renderPolysoupZodiacs(state, this); 956#endif 957 if (mRenderNormalScalar > 0) 958 { 959 ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 960 ri->renderDelegate.bind(this, &TSStatic::_renderNormals); 961 ri->type = RenderPassManager::RIT_Editor; 962 state->getRenderPass()->addInst(ri); 963 } 964} 965 966void TSStatic::_renderNormals(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat) 967{ 968 PROFILE_SCOPE(TSStatic_RenderNormals); 969 970 GFXTransformSaver saver; 971 972 MatrixF mat = getRenderTransform(); 973 mat.scale(mObjScale); 974 GFX->multWorld(mat); 975 976 S32 dl = mShapeInstance->getCurrentDetail(); 977 mShapeInstance->renderDebugNormals(mRenderNormalScalar, dl); 978} 979 980void TSStatic::onScaleChanged() 981{ 982 Parent::onScaleChanged(); 983 984 if (mPhysicsRep) 985 { 986 // If the editor is enabled delay the scale operation 987 // by a few milliseconds so that we're not rebuilding 988 // during an active scale drag operation. 989 if (gEditingMission) 990 mPhysicsRep->queueCallback(500, Delegate<void()>(this, &TSStatic::_updatePhysics)); 991 else 992 _updatePhysics(); 993 } 994 995 setMaskBits(ScaleMask); 996} 997 998void TSStatic::setTransform(const MatrixF& mat) 999{ 1000 Parent::setTransform(mat); 1001 if (!isMounted()) 1002 setMaskBits(TransformMask); 1003 1004 if (mPhysicsRep) 1005 mPhysicsRep->setTransform(mat); 1006 1007 // Accumulation 1008 if (isClientObject() && mShapeInstance) 1009 { 1010 if (mShapeInstance->hasAccumulation()) 1011 AccumulationVolume::updateObject(this); 1012 } 1013 1014 // Since this is a static it's render transform changes 1 1015 // to 1 with it's collision transform... no interpolation. 1016 setRenderTransform(mat); 1017} 1018 1019U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream) 1020{ 1021 U32 retMask = Parent::packUpdate(con, mask, stream); 1022 1023 if (stream->writeFlag(mask & TransformMask)) 1024 mathWrite(*stream, getTransform()); 1025 1026 if (stream->writeFlag(mask & ScaleMask)) 1027 { 1028 // Only write one bit if the scale is one. 1029 if (stream->writeFlag(mObjScale != Point3F::One)) 1030 mathWrite(*stream, mObjScale); 1031 } 1032 1033 if (stream->writeFlag(mask & UpdateCollisionMask)) 1034 stream->write((U32)mCollisionType); 1035 1036 if (stream->writeFlag(mask & SkinMask)) 1037 con->packNetStringHandleU(stream, mSkinNameHandle); 1038 1039 if (stream->writeFlag(mask & AdvancedStaticOptionsMask)) 1040 { 1041 stream->writeString(mShapeAsset.getAssetId()); 1042 stream->writeString(mShapeName); 1043 1044 stream->write((U32)mDecalType); 1045 1046 stream->writeFlag(mAllowPlayerStep); 1047 stream->writeFlag(mMeshCulling); 1048 stream->writeFlag(mUseOriginSort); 1049 1050 stream->write(mRenderNormalScalar); 1051 1052 stream->write(mForceDetail); 1053 1054 if (stream->writeFlag(mAnimOffset != 0.0f)) 1055 stream->writeFloat(mAnimOffset, 7); 1056 1057 if (stream->writeFlag(mAnimSpeed != 1.0f)) 1058 stream->writeSignedFloat(mAnimSpeed / AnimSpeedMax, 7); 1059 1060 stream->writeFlag(mPlayAmbient); 1061 } 1062 1063 if (stream->writeFlag(mUseAlphaFade)) 1064 { 1065 stream->write(mAlphaFadeStart); 1066 stream->write(mAlphaFadeEnd); 1067 stream->write(mInvertAlphaFade); 1068 } 1069 1070 stream->writeFlag(mIgnoreZodiacs); 1071 if (stream->writeFlag(mHasGradients)) 1072 { 1073 stream->writeFlag(mInvertGradientRange); 1074 stream->write(mGradientRange.x); 1075 stream->write(mGradientRange.y); 1076 } 1077 if (mLightPlugin) 1078 retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream); 1079 1080 if (stream->writeFlag(reflectorDesc != NULL)) 1081 { 1082 stream->writeRangedU32(reflectorDesc->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast); 1083 } 1084 1085 stream->write(mOverrideColor); 1086 1087 if (stream->writeFlag(mask & MaterialMask)) 1088 { 1089 stream->writeInt(mChangingMaterials.size(), 16); 1090 1091 for (U32 i = 0; i < mChangingMaterials.size(); i++) 1092 { 1093 stream->writeInt(mChangingMaterials[i].slot, 16); 1094 1095 NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str(); 1096 con->packNetStringHandleU(stream, matNameStr); 1097 } 1098 1099 mChangingMaterials.clear(); 1100 } 1101 1102 return retMask; 1103} 1104 1105void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream) 1106{ 1107 Parent::unpackUpdate(con, stream); 1108 1109 if (stream->readFlag()) // TransformMask 1110 { 1111 MatrixF mat; 1112 mathRead(*stream, &mat); 1113 setTransform(mat); 1114 setRenderTransform(mat); 1115 } 1116 1117 if (stream->readFlag()) // ScaleMask 1118 { 1119 if (stream->readFlag()) 1120 { 1121 VectorF scale; 1122 mathRead(*stream, &scale); 1123 setScale(scale); 1124 } 1125 else 1126 setScale(Point3F::One); 1127 } 1128 1129 if (stream->readFlag()) // UpdateCollisionMask 1130 { 1131 U32 collisionType = CollisionMesh; 1132 1133 stream->read(&collisionType); 1134 1135 // Handle it if we have changed CollisionType's 1136 if ((MeshType)collisionType != mCollisionType) 1137 { 1138 mCollisionType = (MeshType)collisionType; 1139 1140 if (isProperlyAdded() && mShapeInstance) 1141 prepCollision(); 1142 } 1143 } 1144 1145 if (stream->readFlag()) // SkinMask 1146 { 1147 NetStringHandle skinDesiredNameHandle = con->unpackNetStringHandleU(stream);; 1148 if (mSkinNameHandle != skinDesiredNameHandle) 1149 { 1150 mSkinNameHandle = skinDesiredNameHandle; 1151 reSkin(); 1152 } 1153 } 1154 1155 if (stream->readFlag()) // AdvancedStaticOptionsMask 1156 { 1157 char buffer[256]; 1158 stream->readString(buffer); 1159 setShapeAsset(StringTable->insert(buffer)); 1160 1161 mShapeName = stream->readSTString(); 1162 1163 stream->read((U32*)&mDecalType); 1164 1165 mAllowPlayerStep = stream->readFlag(); 1166 mMeshCulling = stream->readFlag(); 1167 mUseOriginSort = stream->readFlag(); 1168 1169 stream->read(&mRenderNormalScalar); 1170 1171 stream->read(&mForceDetail); 1172 1173 if (stream->readFlag()) 1174 mAnimOffset = stream->readFloat(7); 1175 1176 if (stream->readFlag()) 1177 mAnimSpeed = stream->readSignedFloat(7) * AnimSpeedMax; 1178 1179 mPlayAmbient = stream->readFlag(); 1180 1181 1182 } 1183 1184 mUseAlphaFade = stream->readFlag(); 1185 if (mUseAlphaFade) 1186 { 1187 stream->read(&mAlphaFadeStart); 1188 stream->read(&mAlphaFadeEnd); 1189 stream->read(&mInvertAlphaFade); 1190 } 1191 1192 mIgnoreZodiacs = stream->readFlag(); 1193 mHasGradients = stream->readFlag(); 1194 if (mHasGradients) 1195 { 1196 mInvertGradientRange = stream->readFlag(); 1197 stream->read(&mGradientRange.x); 1198 stream->read(&mGradientRange.y); 1199 } 1200 if (mLightPlugin) 1201 { 1202 mLightPlugin->unpackUpdate(this, con, stream); 1203 } 1204 1205 if (stream->readFlag()) 1206 { 1207 cubeDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); 1208 } 1209 1210 stream->read(&mOverrideColor); 1211 1212 if (stream->readFlag()) 1213 { 1214 mChangingMaterials.clear(); 1215 U32 materialCount = stream->readInt(16); 1216 1217 for (U32 i = 0; i < materialCount; i++) 1218 { 1219 matMap newMatMap; 1220 newMatMap.slot = stream->readInt(16); 1221 newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString()); 1222 1223 //do the lookup, now 1224 newMatMap.matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newMatMap.assetId); 1225 1226 mChangingMaterials.push_back(newMatMap); 1227 } 1228 1229 updateMaterials(); 1230 } 1231 1232 if (isProperlyAdded()) 1233 _updateShouldTick(); 1234 set_special_typing(); 1235} 1236 1237//---------------------------------------------------------------------------- 1238bool TSStatic::castRay(const Point3F& start, const Point3F& end, RayInfo* info) 1239{ 1240 if (mCollisionType == None) 1241 return false; 1242 1243 if (!mShapeInstance) 1244 return false; 1245 1246 if (mCollisionType == Bounds) 1247 { 1248 F32 fst; 1249 if (!mObjBox.collideLine(start, end, &fst, &info->normal)) 1250 return false; 1251 1252 info->t = fst; 1253 info->object = this; 1254 info->point.interpolate(start, end, fst); 1255 info->material = NULL; 1256 return true; 1257 } 1258 else 1259 { 1260 RayInfo shortest = *info; 1261 RayInfo localInfo; 1262 shortest.t = 1e8f; 1263 localInfo.generateTexCoord = info->generateTexCoord; 1264 1265 for (U32 i = 0; i < mLOSDetails.size(); i++) 1266 { 1267 mShapeInstance->animate(mLOSDetails[i]); 1268 1269 if (mShapeInstance->castRayOpcode(mLOSDetails[i], start, end, &localInfo)) 1270 { 1271 localInfo.object = this; 1272 1273 if (localInfo.t < shortest.t) 1274 shortest = localInfo; 1275 } 1276 } 1277 1278 if (shortest.object == this) 1279 { 1280 // Copy out the shortest time... 1281 *info = shortest; 1282 return true; 1283 } 1284 } 1285 1286 return false; 1287} 1288 1289bool TSStatic::castRayRendered(const Point3F& start, const Point3F& end, RayInfo* info) 1290{ 1291 if (!mShapeInstance) 1292 return false; 1293 1294 // Cast the ray against the currently visible detail 1295 RayInfo localInfo; 1296 if (info && info->generateTexCoord) 1297 localInfo.generateTexCoord = true; 1298 bool res = mShapeInstance->castRayOpcode(mShapeInstance->getCurrentDetail(), start, end, &localInfo); 1299 1300 if (res) 1301 { 1302 *info = localInfo; 1303 info->object = this; 1304 return true; 1305 } 1306 1307 return false; 1308} 1309 1310bool TSStatic::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF&) 1311{ 1312 if (!mShapeInstance) 1313 return false; 1314 1315 // This is safe to set even if we're not outputing 1316 polyList->setTransform(&mObjToWorld, mObjScale); 1317 polyList->setObject(this); 1318 1319 if (context == PLC_Export) 1320 { 1321 // Use highest detail level 1322 S32 dl = 0; 1323 1324 // Try to call on the client so we can export materials 1325 if (isServerObject() && getClientObject()) 1326 dynamic_cast<TSStatic*>(getClientObject())->mShapeInstance->buildPolyList(polyList, dl); 1327 else 1328 mShapeInstance->buildPolyList(polyList, dl); 1329 } 1330 else if (context == PLC_Selection) 1331 { 1332 // Use the last rendered detail level 1333 S32 dl = mShapeInstance->getCurrentDetail(); 1334 mShapeInstance->buildPolyListOpcode(dl, polyList, box); 1335 } 1336 else 1337 { 1338 // Figure out the mesh type we're looking for. 1339 MeshType meshType = (context == PLC_Decal) ? mDecalType : mCollisionType; 1340 1341 if (meshType == None) 1342 return false; 1343 else if (meshType == Bounds) 1344 polyList->addBox(mObjBox); 1345 else if (meshType == VisibleMesh) 1346 mShapeInstance->buildPolyList(polyList, 0); 1347 else if (context == PLC_Decal && mDecalDetailsPtr != 0) 1348 { 1349 for (U32 i = 0; i < mDecalDetailsPtr->size(); i++) 1350 mShapeInstance->buildPolyListOpcode((*mDecalDetailsPtr)[i], polyList, box); 1351 } 1352 else 1353 { 1354 // Everything else is done from the collision meshes 1355 // which may be built from either the visual mesh or 1356 // special collision geometry. 1357 for (U32 i = 0; i < mCollisionDetails.size(); i++) 1358 mShapeInstance->buildPolyListOpcode(mCollisionDetails[i], polyList, box); 1359 } 1360 } 1361 1362 return true; 1363} 1364 1365bool TSStatic::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF&) 1366{ 1367 if (!mShapeInstance) 1368 return false; 1369 1370 if (mCollisionType == Bounds) 1371 { 1372 ColladaUtils::ExportData::colMesh* colMesh; 1373 exportData->colMeshes.increment(); 1374 colMesh = &exportData->colMeshes.last(); 1375 1376 colMesh->mesh.setTransform(&mObjToWorld, mObjScale); 1377 colMesh->mesh.setObject(this); 1378 1379 colMesh->mesh.addBox(mObjBox); 1380 1381 colMesh->colMeshName = String::ToString("ColBox%d-1", exportData->colMeshes.size()); 1382 } 1383 else if (mCollisionType == VisibleMesh) 1384 { 1385 ColladaUtils::ExportData::colMesh* colMesh; 1386 exportData->colMeshes.increment(); 1387 colMesh = &exportData->colMeshes.last(); 1388 1389 colMesh->mesh.setTransform(&mObjToWorld, mObjScale); 1390 colMesh->mesh.setObject(this); 1391 1392 mShapeInstance->buildPolyList(&colMesh->mesh, 0); 1393 1394 colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size()); 1395 } 1396 else if (mCollisionType == CollisionMesh) 1397 { 1398 // Everything else is done from the collision meshes 1399 // which may be built from either the visual mesh or 1400 // special collision geometry. 1401 for (U32 i = 0; i < mCollisionDetails.size(); i++) 1402 { 1403 ColladaUtils::ExportData::colMesh* colMesh; 1404 exportData->colMeshes.increment(); 1405 colMesh = &exportData->colMeshes.last(); 1406 1407 colMesh->mesh.setTransform(&mObjToWorld, mObjScale); 1408 colMesh->mesh.setObject(this); 1409 1410 mShapeInstance->buildPolyListOpcode(mCollisionDetails[i], &colMesh->mesh, box); 1411 1412 colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size()); 1413 } 1414 } 1415 1416 //Next, process the LOD levels and materials. 1417 if (isServerObject() && getClientObject()) 1418 { 1419 TSStatic* clientShape = dynamic_cast<TSStatic*>(getClientObject()); 1420 1421 exportData->meshData.increment(); 1422 1423 //Prep a meshData for this shape in particular 1424 ColladaUtils::ExportData::meshLODData* meshData = &exportData->meshData.last(); 1425 1426 //Fill out the info we'll need later to actually append our mesh data for the detail levels during the processing phase 1427 meshData->shapeInst = clientShape->mShapeInstance; 1428 meshData->originatingObject = this; 1429 meshData->meshTransform = mObjToWorld; 1430 meshData->scale = mObjScale; 1431 1432 //Iterate over all our detail levels 1433 for (U32 i = 0; i < clientShape->mShapeInstance->getNumDetails(); i++) 1434 { 1435 TSShape::Detail detail = clientShape->mShapeInstance->getShape()->details[i]; 1436 1437 String detailName = String::ToLower(clientShape->mShapeInstance->getShape()->getName(detail.nameIndex)); 1438 1439 //Skip it if it's a collision or line of sight element 1440 if (detailName.startsWith("col") || detailName.startsWith("los")) 1441 continue; 1442 1443 meshData->meshDetailLevels.increment(); 1444 1445 ColladaUtils::ExportData::detailLevel* curDetail = &meshData->meshDetailLevels.last(); 1446 1447 //Make sure we denote the size this detail level has 1448 curDetail->size = getNextPow2(detail.size); 1449 } 1450 } 1451 1452 return true; 1453} 1454 1455void TSStatic::buildConvex(const Box3F& box, Convex* convex) 1456{ 1457 if (mCollisionType == None) 1458 return; 1459 1460 if (mShapeInstance == NULL) 1461 return; 1462 1463 // These should really come out of a pool 1464 mConvexList->collectGarbage(); 1465 1466 if (mCollisionType == Bounds) 1467 { 1468 // Just return a box convex for the entire shape... 1469 Convex* cc = 0; 1470 CollisionWorkingList& wl = convex->getWorkingList(); 1471 for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) 1472 { 1473 if (itr->mConvex->getType() == BoxConvexType && 1474 itr->mConvex->getObject() == this) 1475 { 1476 cc = itr->mConvex; 1477 break; 1478 } 1479 } 1480 if (cc) 1481 return; 1482 1483 // Create a new convex. 1484 BoxConvex* cp = new BoxConvex; 1485 mConvexList->registerObject(cp); 1486 convex->addToWorkingList(cp); 1487 cp->init(this); 1488 1489 mObjBox.getCenter(&cp->mCenter); 1490 cp->mSize.x = mObjBox.len_x() / 2.0f; 1491 cp->mSize.y = mObjBox.len_y() / 2.0f; 1492 cp->mSize.z = mObjBox.len_z() / 2.0f; 1493 } 1494 else // CollisionMesh || VisibleMesh 1495 { 1496 TSStaticPolysoupConvex::smCurObject = this; 1497 1498 for (U32 i = 0; i < mCollisionDetails.size(); i++) 1499 mShapeInstance->buildConvexOpcode(mObjToWorld, mObjScale, mCollisionDetails[i], box, convex, mConvexList); 1500 1501 TSStaticPolysoupConvex::smCurObject = NULL; 1502 } 1503} 1504 1505SceneObject* TSStaticPolysoupConvex::smCurObject = NULL; 1506 1507TSStaticPolysoupConvex::TSStaticPolysoupConvex() 1508 : box(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), 1509 normal(0.0f, 0.0f, 0.0f, 0.0f), 1510 idx(0), 1511 mesh(NULL) 1512{ 1513 mType = TSPolysoupConvexType; 1514 1515 for (U32 i = 0; i < 4; ++i) 1516 { 1517 verts[i].set(0.0f, 0.0f, 0.0f); 1518 } 1519} 1520 1521Point3F TSStaticPolysoupConvex::support(const VectorF& vec) const 1522{ 1523 F32 bestDot = mDot(verts[0], vec); 1524 1525 const Point3F* bestP = &verts[0]; 1526 for (S32 i = 1; i < 4; i++) 1527 { 1528 F32 newD = mDot(verts[i], vec); 1529 if (newD > bestDot) 1530 { 1531 bestDot = newD; 1532 bestP = &verts[i]; 1533 } 1534 } 1535 1536 return *bestP; 1537} 1538 1539Box3F TSStaticPolysoupConvex::getBoundingBox() const 1540{ 1541 Box3F wbox = box; 1542 wbox.minExtents.convolve(mObject->getScale()); 1543 wbox.maxExtents.convolve(mObject->getScale()); 1544 mObject->getTransform().mul(wbox); 1545 return wbox; 1546} 1547 1548Box3F TSStaticPolysoupConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const 1549{ 1550 AssertISV(false, "TSStaticPolysoupConvex::getBoundingBox(m,p) - Not implemented. -- XEA"); 1551 return box; 1552} 1553 1554void TSStaticPolysoupConvex::getPolyList(AbstractPolyList* list) 1555{ 1556 // Transform the list into object space and set the pointer to the object 1557 MatrixF i(mObject->getTransform()); 1558 Point3F iS(mObject->getScale()); 1559 list->setTransform(&i, iS); 1560 list->setObject(mObject); 1561 1562 // Add only the original collision triangle 1563 S32 base = list->addPoint(verts[0]); 1564 list->addPoint(verts[2]); 1565 list->addPoint(verts[1]); 1566 1567 list->begin(0, (U32)idx ^ (uintptr_t)mesh); 1568 list->vertex(base + 2); 1569 list->vertex(base + 1); 1570 list->vertex(base + 0); 1571 list->plane(base + 0, base + 1, base + 2); 1572 list->end(); 1573} 1574 1575void TSStaticPolysoupConvex::getFeatures(const MatrixF& mat, const VectorF& n, ConvexFeature* cf) 1576{ 1577 cf->material = 0; 1578 cf->mObject = mObject; 1579 1580 // For a tetrahedron this is pretty easy... first 1581 // convert everything into world space. 1582 Point3F tverts[4]; 1583 mat.mulP(verts[0], &tverts[0]); 1584 mat.mulP(verts[1], &tverts[1]); 1585 mat.mulP(verts[2], &tverts[2]); 1586 mat.mulP(verts[3], &tverts[3]); 1587 1588 // points... 1589 S32 firstVert = cf->mVertexList.size(); 1590 cf->mVertexList.increment(); cf->mVertexList.last() = tverts[0]; 1591 cf->mVertexList.increment(); cf->mVertexList.last() = tverts[1]; 1592 cf->mVertexList.increment(); cf->mVertexList.last() = tverts[2]; 1593 cf->mVertexList.increment(); cf->mVertexList.last() = tverts[3]; 1594 1595 // edges... 1596 cf->mEdgeList.increment(); 1597 cf->mEdgeList.last().vertex[0] = firstVert + 0; 1598 cf->mEdgeList.last().vertex[1] = firstVert + 1; 1599 1600 cf->mEdgeList.increment(); 1601 cf->mEdgeList.last().vertex[0] = firstVert + 1; 1602 cf->mEdgeList.last().vertex[1] = firstVert + 2; 1603 1604 cf->mEdgeList.increment(); 1605 cf->mEdgeList.last().vertex[0] = firstVert + 2; 1606 cf->mEdgeList.last().vertex[1] = firstVert + 0; 1607 1608 cf->mEdgeList.increment(); 1609 cf->mEdgeList.last().vertex[0] = firstVert + 3; 1610 cf->mEdgeList.last().vertex[1] = firstVert + 0; 1611 1612 cf->mEdgeList.increment(); 1613 cf->mEdgeList.last().vertex[0] = firstVert + 3; 1614 cf->mEdgeList.last().vertex[1] = firstVert + 1; 1615 1616 cf->mEdgeList.increment(); 1617 cf->mEdgeList.last().vertex[0] = firstVert + 3; 1618 cf->mEdgeList.last().vertex[1] = firstVert + 2; 1619 1620 // triangles... 1621 cf->mFaceList.increment(); 1622 cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[0]); 1623 cf->mFaceList.last().vertex[0] = firstVert + 2; 1624 cf->mFaceList.last().vertex[1] = firstVert + 1; 1625 cf->mFaceList.last().vertex[2] = firstVert + 0; 1626 1627 cf->mFaceList.increment(); 1628 cf->mFaceList.last().normal = PlaneF(tverts[1], tverts[0], tverts[3]); 1629 cf->mFaceList.last().vertex[0] = firstVert + 1; 1630 cf->mFaceList.last().vertex[1] = firstVert + 0; 1631 cf->mFaceList.last().vertex[2] = firstVert + 3; 1632 1633 cf->mFaceList.increment(); 1634 cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[3]); 1635 cf->mFaceList.last().vertex[0] = firstVert + 2; 1636 cf->mFaceList.last().vertex[1] = firstVert + 1; 1637 cf->mFaceList.last().vertex[2] = firstVert + 3; 1638 1639 cf->mFaceList.increment(); 1640 cf->mFaceList.last().normal = PlaneF(tverts[0], tverts[2], tverts[3]); 1641 cf->mFaceList.last().vertex[0] = firstVert + 0; 1642 cf->mFaceList.last().vertex[1] = firstVert + 2; 1643 cf->mFaceList.last().vertex[2] = firstVert + 3; 1644 1645 // All done! 1646} 1647 1648void TSStatic::onMount(SceneObject* obj, S32 node) 1649{ 1650 Parent::onMount(obj, node); 1651 _updateShouldTick(); 1652} 1653 1654void TSStatic::onUnmount(SceneObject* obj, S32 node) 1655{ 1656 Parent::onUnmount(obj, node); 1657 setMaskBits(TransformMask); 1658 _updateShouldTick(); 1659} 1660 1661U32 TSStatic::getNumDetails() 1662{ 1663 if (isServerObject() && getClientObject()) 1664 { 1665 TSStatic* clientShape = dynamic_cast<TSStatic*>(getClientObject()); 1666 return clientShape->mShapeInstance->getNumDetails(); 1667 } 1668 return 0; 1669}; 1670 1671void TSStatic::updateMaterials() 1672{ 1673 if (mChangingMaterials.empty() || !mShape) 1674 return; 1675 1676 TSMaterialList* pMatList = mShapeInstance->getMaterialList(); 1677 1678 String path; 1679 if (mShapeAsset->isAssetValid()) 1680 path = mShapeAsset->getShapeFilename(); 1681 else 1682 path = mShapeName; 1683 1684 pMatList->setTextureLookupPath(path); 1685 1686 bool found = false; 1687 const Vector<String>& materialNames = pMatList->getMaterialNameList(); 1688 for (S32 i = 0; i < materialNames.size(); i++) 1689 { 1690 if (found) 1691 break; 1692 1693 for (U32 m = 0; m < mChangingMaterials.size(); m++) 1694 { 1695 if (mChangingMaterials[m].slot == i) 1696 { 1697 //Fetch the actual material asset 1698 pMatList->renameMaterial(i, mChangingMaterials[m].matAsset->getMaterialDefinitionName()); 1699 found = true; 1700 break; 1701 } 1702 } 1703 } 1704 1705 mChangingMaterials.clear(); 1706 1707 // Initialize the material instances 1708 mShapeInstance->initMaterialList(); 1709} 1710 1711void TSStatic::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList) 1712{ 1713 if(!mShapeAsset.isNull() && mShapeAsset->getAssetId() != StringTable->insert("Core_Rendering:noShape")) 1714 usedAssetsList->push_back_unique(mShapeAsset->getAssetId()); 1715 1716} 1717 1718//------------------------------------------------------------------------ 1719//These functions are duplicated in tsStatic and shapeBase. 1720//They each function a little differently; but achieve the same purpose of gathering 1721//target names/counts without polluting simObject. 1722 1723void TSStatic::onInspect(GuiInspector* inspector) 1724{ 1725 if (mShapeAsset == nullptr) 1726 return; 1727 1728 //Put the GameObject group before everything that'd be gameobject-effecting, for orginazational purposes 1729 GuiInspectorGroup* materialGroup = inspector->findExistentGroup(StringTable->insert("Materials")); 1730 if (!materialGroup) 1731 return; 1732 1733 GuiControl* stack = dynamic_cast<GuiControl*>(materialGroup->findObjectByInternalName(StringTable->insert("Stack"))); 1734 1735 //Do this on both the server and client 1736 S32 materialCount = mShapeAsset->getShape()->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount(); 1737 1738 if (isServerObject()) 1739 { 1740 //we need to update the editor 1741 /*for (U32 i = 0; i < mFields.size(); i++) 1742 { 1743 //find any with the materialslot title and clear them out 1744 if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false)) 1745 { 1746 setDataField(mFields[i].mFieldName, NULL, ""); 1747 mFields.erase(i); 1748 continue; 1749 } 1750 }*/ 1751 1752 //next, get a listing of our materials in the shape, and build our field list for them 1753 char matFieldName[128]; 1754 1755 for (U32 i = 0; i < materialCount; i++) 1756 { 1757 StringTableEntry materialname = StringTable->insert(mShapeAsset->getShape()->materialList->getMaterialName(i).c_str()); 1758 1759 //Iterate through our assetList to find the compliant entry in our matList 1760 for (U32 m = 0; m < mShapeAsset->getMaterialCount(); m++) 1761 { 1762 AssetPtr<MaterialAsset> matAsset = mShapeAsset->getMaterialAsset(m); 1763 1764 if (matAsset->getMaterialDefinitionName() == materialname) 1765 { 1766 dSprintf(matFieldName, 128, "MaterialSlot%d", i); 1767 1768 //addComponentField(matFieldName, "A material used in the shape file", "Material", matAsset->getAssetId(), ""); 1769 //Con::executef(this, "onConstructComponentField", mTargetComponent, field->mFieldName); 1770 Con::printf("Added material field for MaterialSlot %d", i); 1771 1772 GuiInspectorField* fieldGui = materialGroup->constructField(TypeMaterialAssetPtr); 1773 fieldGui->init(inspector, materialGroup); 1774 1775 fieldGui->setSpecialEditField(true); 1776 fieldGui->setTargetObject(this); 1777 1778 StringTableEntry fldnm = StringTable->insert(matFieldName); 1779 1780 fieldGui->setSpecialEditVariableName(fldnm); 1781 1782 fieldGui->setInspectorField(NULL, fldnm); 1783 fieldGui->setDocs(""); 1784 1785 if (fieldGui->registerObject()) 1786 { 1787 fieldGui->setValue(materialname); 1788 1789 stack->addObject(fieldGui); 1790 } 1791 else 1792 { 1793 SAFE_DELETE(fieldGui); 1794 } 1795 1796 /*if (materialGroup->isMethod("onConstructField")) 1797 { 1798 //ensure our stack variable is bound if we need it 1799 //Con::evaluatef("%d.stack = %d;", materialGroup->getId(), materialGroup->at(0)->getId()); 1800 1801 Con::executef(materialGroup, "onConstructField", matFieldName, 1802 matFieldName, "material", matFieldName, 1803 materialname, "", "", this); 1804 }*/ 1805 break; 1806 } 1807 } 1808 } 1809 } 1810} 1811 1812DefineEngineMethod(TSStatic, getTargetName, const char*, (S32 index), (0), 1813 "Get the name of the indexed shape material.\n" 1814 "@param index index of the material to get (valid range is 0 - getTargetCount()-1).\n" 1815 "@return the name of the indexed material.\n" 1816 "@see getTargetCount()\n") 1817{ 1818 TSStatic* obj = dynamic_cast<TSStatic*> (object); 1819 if (obj) 1820 { 1821 // Try to use the client object (so we get the reskinned targets in the Material Editor) 1822 if ((TSStatic*)obj->getClientObject()) 1823 obj = (TSStatic*)obj->getClientObject(); 1824 1825 return obj->getShapeInstance()->getTargetName(index); 1826 } 1827 1828 return ""; 1829} 1830 1831DefineEngineMethod(TSStatic, getTargetCount, S32, (), , 1832 "Get the number of materials in the shape.\n" 1833 "@return the number of materials in the shape.\n" 1834 "@see getTargetName()\n") 1835{ 1836 TSStatic* obj = dynamic_cast<TSStatic*> (object); 1837 if (obj) 1838 { 1839 // Try to use the client object (so we get the reskinned targets in the Material Editor) 1840 if ((TSStatic*)obj->getClientObject()) 1841 obj = (TSStatic*)obj->getClientObject(); 1842 1843 return obj->getShapeInstance()->getTargetCount(); 1844 } 1845 1846 return -1; 1847} 1848 1849// This method is able to change materials per map to with others. The material that is being replaced is being mapped to 1850// unmapped_mat as a part of this transition 1851 1852DefineEngineMethod(TSStatic, changeMaterial, void, (const char* mapTo, Material* oldMat, Material* newMat), ("", nullAsType<Material*>(), nullAsType<Material*>()), 1853 "@brief Change one of the materials on the shape.\n\n" 1854 1855 "This method changes materials per mapTo with others. The material that " 1856 "is being replaced is mapped to unmapped_mat as a part of this transition.\n" 1857 1858 "@note Warning, right now this only sort of works. It doesn't do a live " 1859 "update like it should.\n" 1860 1861 "@param mapTo the name of the material target to remap (from getTargetName)\n" 1862 "@param oldMat the old Material that was mapped \n" 1863 "@param newMat the new Material to map\n\n" 1864 1865 "@tsexample\n" 1866 "// remap the first material in the shape\n" 1867 "%mapTo = %obj.getTargetName( 0 );\n" 1868 "%obj.changeMaterial( %mapTo, 0, MyMaterial );\n" 1869 "@endtsexample\n") 1870{ 1871 // if no valid new material, theres no reason for doing this 1872 if (!newMat) 1873 { 1874 Con::errorf("TSShape::changeMaterial failed: New material does not exist!"); 1875 return; 1876 } 1877 1878 TSMaterialList* shapeMaterialList = object->getShape()->materialList; 1879 1880 // Check the mapTo name exists for this shape 1881 S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo)); 1882 if (matIndex < 0) 1883 { 1884 Con::errorf("TSShape::changeMaterial failed: Invalid mapTo name '%s'", mapTo); 1885 return; 1886 } 1887 1888 // Lets remap the old material off, so as to let room for our current material room to claim its spot 1889 if (oldMat) 1890 oldMat->mMapTo = String("unmapped_mat"); 1891 1892 newMat->mMapTo = mapTo; 1893 1894 // Map the material by name in the matmgr 1895 MATMGR->mapMaterial(mapTo, newMat->getName()); 1896 1897 // Replace instances with the new material being traded in. Lets make sure that we only 1898 // target the specific targets per inst, this is actually doing more than we thought 1899 delete shapeMaterialList->mMatInstList[matIndex]; 1900 shapeMaterialList->mMatInstList[matIndex] = newMat->createMatInstance(); 1901 1902 // Finish up preparing the material instances for rendering 1903 const GFXVertexFormat* flags = getGFXVertexFormat<GFXVertexPNTTB>(); 1904 FeatureSet features = MATMGR->getDefaultFeatures(); 1905 shapeMaterialList->getMaterialInst(matIndex)->init(features, flags); 1906} 1907 1908DefineEngineMethod(TSStatic, getModelFile, const char*, (), , 1909 "@brief Get the model filename used by this shape.\n\n" 1910 1911 "@return the shape filename\n\n" 1912 "@tsexample\n" 1913 "// Acquire the model filename used on this shape.\n" 1914 "%modelFilename = %obj.getModelFile();\n" 1915 "@endtsexample\n" 1916) 1917{ 1918 return object->getShapeFileName(); 1919} 1920 1921void TSStatic::set_special_typing() 1922{ 1923 if (mCollisionType == VisibleMesh || mCollisionType == CollisionMesh) 1924 mTypeMask |= InteriorLikeObjectType; 1925 else 1926 mTypeMask &= ~<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084ae7ac7d67ceb85fd2c0e1b83e6acd6634">InteriorLikeObjectType</a>; 1927} 1928 1929void TSStatic::onStaticModified(const char* slotName, const char* newValue) 1930{ 1931#ifdef TORQUE_AFX_ENABLED 1932 if (slotName == afxZodiacData::GradientRangeSlot) 1933 { 1934 afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser); 1935 return; 1936 } 1937#endif 1938 1939 set_special_typing(); 1940} 1941 1942void TSStatic::setSelectionFlags(U8 flags) 1943{ 1944 Parent::setSelectionFlags(flags); 1945 1946 if (!mShapeInstance || !isClientObject()) 1947 return; 1948 1949 if (!mShapeInstance->ownMaterialList()) 1950 return; 1951 1952 TSMaterialList* pMatList = mShapeInstance->getMaterialList(); 1953 for (S32 j = 0; j < pMatList->size(); j++) 1954 { 1955 BaseMatInstance* bmi = pMatList->getMaterialInst(j); 1956 bmi->setSelectionHighlighting(needsSelectionHighlighting()); 1957 } 1958} 1959 1960