sceneObject.cpp
Engine/source/scene/sceneObject.cpp
Public Functions
ConsoleDocClass(SceneObject , "@brief A networkable object that exists in the 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "The <a href="/coding/class/classsceneobject/">SceneObject</a> class provides the foundation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> 3D objects in the Engine. It " "exposes the functionality <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for:\n\n</a>" "<ul><li> Position, rotation and scale within the world.</li >" "< li >Working with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene graph, allowing efficient " "and robust rendering of the game scene.</li >" "< li >Various helper functions, including functions <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get bounding information " "and momentum/velocity.</li >" "< li >Mounting one <a href="/coding/class/classsceneobject/">SceneObject</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another.</li >" "< li >An interface <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> collision detection, as well as ray casting.</li >" "< li >Lighting. SceneObjects can register lights both at lightmap generation " " time, and dynamic lights at runtime, but does not <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client on its own. The " "same is true of collision detection beyond that of the bounding box. Instead you " "use one of the many classes that derrive from SceneObject, such as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TSStatic.\n\n</a>" " @section SceneObject_Hiding Difference Between setHidden() and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">isRenderEnabled\n\n</a>" "When it comes time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> decide <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> should <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> or not, there are two " "methods that can stop the <a href="/coding/class/classsceneobject/">SceneObject</a> from rendering at all. You need <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be aware of " "the differences between these two methods as they impact how the <a href="/coding/class/classsceneobject/">SceneObject</a> is networked " "from the server <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n\n</a>" "The first method of manually controlling <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> is rendered is through its " "<a href="/coding/class/classsceneobject/#classsceneobject_1ae41e1b7a91fa4be04cb7fa0e7b9901d9">SceneObject::isRenderEnabled</a> property. When set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false the <a href="/coding/class/classsceneobject/">SceneObject</a> is considered invisible but " "still present within the scene. This means it still takes part in collisions and continues " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">networked.\n\n</a>" "The second method is using the setHidden() method. This will actually remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> " "from the scene and it will no longer be networked from the server <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the cleint. Any client-side " "ghost of the object will be deleted as the server no longer considers the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scope.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(SceneObject , attachChild , bool , (const char *_subObject) , "(SceneObject subObject)" "attach an object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this one, preserving its present transform." )
DefineEngineMethod(SceneObject , attachChildAt , bool , (SceneObject *_subObject, MatrixF _offset, S32 _node) , (nullAsType< SceneObject * >(), MatrixF::Identity, 0) , "(SceneObject subObject, <a href="/coding/class/classmatrixf/">MatrixF</a> offset, <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> offset)" "Mount object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this one with the specified offset expressed in our coordinate space." )
DefineEngineMethod(SceneObject , attachToParent , bool , (const char *_sceneObject) , "attachToParent(<a href="/coding/class/classsceneobject/">SceneObject</a>)" "specify <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> null or non-null parent" )
DefineEngineMethod(SceneObject , detachChild , bool , (const char *_subObject) , "SceneObject subObject" )
DefineEngineMethod(SceneObject , getChild , S32 , (S32 _index) , (0) , "getChild(<a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> index) -- returns child <a href="/coding/class/classsceneobject/">SceneObject</a> at given index" )
DefineEngineMethod(SceneObject , getEulerRotation , Point3F , () , "Get Euler rotation of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return the orientation of the object in the form of rotations around the " " X, Y and Z axes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n</a>" )
DefineEngineMethod(SceneObject , getForwardVector , VectorF , () , "Get the direction this object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">facing.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the direction this object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">facing.\n</a>" "@note This is the object's y axis." )
DefineEngineMethod(SceneObject , getInverseTransform , TransformF , () , "Get the object's inverse <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n</a>" "@return the inverse transform of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getMountedObject , S32 , (S32 slot) , "Get the object mounted at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particular <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot.\n</a>" "@param slot mount slot index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return ID of the object mounted in the slot, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> no object." )
DefineEngineMethod(SceneObject , getMountedObjectCount , S32 , () , "Get the number of objects mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">us.\n</a>" "@return the number of mounted objects." )
DefineEngineMethod(SceneObject , getMountedObjectNode , S32 , (S32 slot) , "@brief Get the mount node index of the object mounted at our given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot.\n\n</a>" "@param slot mount slot index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return index of the mount node used by the object mounted in this slot." )
DefineEngineMethod(SceneObject , getMountNodeObject , S32 , (S32 node) , "@brief Get the object mounted at our given node <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n\n</a>" "@param node mount node index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return ID of the first object mounted at the node, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> none found." )
DefineEngineMethod(SceneObject , getNumChildren , S32 , () , "returns number of direct child objects" )
DefineEngineMethod(SceneObject , getNumProgeny , S32 , () , "returns number of recursively-nested child objects" )
DefineEngineMethod(SceneObject , getObjectBox , Box3F , () , "Get the object's bounding box (relative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object's origin).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return six fields, two Point3Fs, containing the min and max points of the " "objectbox." )
DefineEngineMethod(SceneObject , getObjectMount , S32 , () , "@brief Get the object we are mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return the SimObjectID of the object we're mounted to, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not mounted." )
DefineEngineMethod(SceneObject , getParent , S32 , () , "returns ID of parent <a href="/coding/class/classsceneobject/">SceneObject</a>" )
DefineEngineMethod(SceneObject , getPosition , Point3F , () , "Get the object's world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" "@return the current world position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getRightVector , VectorF , () , "Get the right vector of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the right direction of this object." "@note This is the object's x axis." )
DefineEngineMethod(SceneObject , getScale , Point3F , () , "Get the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scale.\n</a>" "@return object scale as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classpoint3f/">Point3F</a>" )
DefineEngineMethod(SceneObject , getTransform , TransformF , () , "Get the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n</a>" "@return the current transform of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getType , S32 , () , "Return the type mask <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The numeric type mask <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the object." )
DefineEngineMethod(SceneObject , getUpVector , VectorF , () , "Get the up vector of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the up direction of this object." "@note This is the object's z axis." )
DefineEngineMethod(SceneObject , getWorldBox , Box3F , () , "Get the object's world bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box.\n</a>" "@return six fields, two Point3Fs, containing the min and max points of the " "worldbox." )
DefineEngineMethod(SceneObject , getWorldBoxCenter , Point3F , () , "Get the center of the object's world bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box.\n</a>" "@return the center of the world bounding box <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )
DefineEngineMethod(SceneObject , isGlobalBounds , bool , () , "Check <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> this object has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> global bounds <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "If global bounds are set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be true, then the object is assumed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have an " "infinitely large bounding box <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> collision and rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">purposes.\n</a>" " @return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> global bounds." )
DefineEngineMethod(SceneObject , isMounted , bool , () , "@brief Check <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> we are mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another object, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not mounted." )
DefineEngineMethod(SceneObject , mountObject , bool , (SceneObject *objB, S32 slot, TransformF txfm) , (TransformF::Identity) , "@brief Mount objB <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this object at the desired slot with optional <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n\n</a>" "@param objB <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount onto <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">us\n</a>" "@param slot Mount slot <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ID\n</a>" "@param txfm (optional) mount offset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> successful, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> failed(objB is not valid)" )
DefineEngineMethod(SceneObject , setForwardVector , void , (VectorF newForward, VectorF upVector) , (VectorF(0, 0, 0), VectorF(0, 0, 1)) , "Sets the forward vector of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene object, making it face Y+along the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @param The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> forward vector <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" " @param(Optional) The up vector <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> help orient the rotation." )
DefineEngineMethod(SceneObject , setPosition , void , (Point3F pos) , "Set the object's world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" "@param pos the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> world position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , setScale , void , (Point3F scale) , "Set the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scale.\n</a>" "@param scale object scale <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set\n</a>" )
DefineEngineMethod(SceneObject , setTransform , void , (TransformF txfm) , "Set the object's transform (orientation and position)." "@param txfm object transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set" )
DefineEngineMethod(SceneObject , unmount , void , () , "Unmount us from the currently mounted object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n</a>" )
DefineEngineMethod(SceneObject , unmountObject , bool , (SceneObject *target) , "@brief Unmount an object from <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ourselves.\n\n</a>" "@param target object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unmount\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> successful, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">failed\n</a>" )
scopeCallback(SceneObject * obj, void * conPtr)
Detailed Description
Public Functions
ConsoleDocClass(SceneObject , "@brief A networkable object that exists in the 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">world.\n\n</a>" "The <a href="/coding/class/classsceneobject/">SceneObject</a> class provides the foundation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> 3D objects in the Engine. It " "exposes the functionality <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">for:\n\n</a>" "<ul><li> Position, rotation and scale within the world.</li >" "< li >Working with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene graph, allowing efficient " "and robust rendering of the game scene.</li >" "< li >Various helper functions, including functions <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> get bounding information " "and momentum/velocity.</li >" "< li >Mounting one <a href="/coding/class/classsceneobject/">SceneObject</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another.</li >" "< li >An interface <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> collision detection, as well as ray casting.</li >" "< li >Lighting. SceneObjects can register lights both at lightmap generation " " time, and dynamic lights at runtime, but does not <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client on its own. The " "same is true of collision detection beyond that of the bounding box. Instead you " "use one of the many classes that derrive from SceneObject, such as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TSStatic.\n\n</a>" " @section SceneObject_Hiding Difference Between setHidden() and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">isRenderEnabled\n\n</a>" "When it comes time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> decide <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> should <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> or not, there are two " "methods that can stop the <a href="/coding/class/classsceneobject/">SceneObject</a> from rendering at all. You need <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be aware of " "the differences between these two methods as they impact how the <a href="/coding/class/classsceneobject/">SceneObject</a> is networked " "from the server <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n\n</a>" "The first method of manually controlling <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> is rendered is through its " "<a href="/coding/class/classsceneobject/#classsceneobject_1ae41e1b7a91fa4be04cb7fa0e7b9901d9">SceneObject::isRenderEnabled</a> property. When set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> false the <a href="/coding/class/classsceneobject/">SceneObject</a> is considered invisible but " "still present within the scene. This means it still takes part in collisions and continues " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">networked.\n\n</a>" "The second method is using the setHidden() method. This will actually remove <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsceneobject/">SceneObject</a> " "from the scene and it will no longer be networked from the server <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the cleint. Any client-side " "ghost of the object will be deleted as the server no longer considers the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scope.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(SceneObject , attachChild , bool , (const char *_subObject) , "(SceneObject subObject)" "attach an object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this one, preserving its present transform." )
DefineEngineMethod(SceneObject , attachChildAt , bool , (SceneObject *_subObject, MatrixF _offset, S32 _node) , (nullAsType< SceneObject * >(), MatrixF::Identity, 0) , "(SceneObject subObject, <a href="/coding/class/classmatrixf/">MatrixF</a> offset, <a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> offset)" "Mount object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this one with the specified offset expressed in our coordinate space." )
DefineEngineMethod(SceneObject , attachToParent , bool , (const char *_sceneObject) , "attachToParent(<a href="/coding/class/classsceneobject/">SceneObject</a>)" "specify <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> null or non-null parent" )
DefineEngineMethod(SceneObject , detachChild , bool , (const char *_subObject) , "SceneObject subObject" )
DefineEngineMethod(SceneObject , getChild , S32 , (S32 _index) , (0) , "getChild(<a href="/coding/file/types_8h/#types_8h_1a57a2244776e01ad620c556de58eb7880">S32</a> index) -- returns child <a href="/coding/class/classsceneobject/">SceneObject</a> at given index" )
DefineEngineMethod(SceneObject , getEulerRotation , Point3F , () , "Get Euler rotation of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return the orientation of the object in the form of rotations around the " " X, Y and Z axes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n</a>" )
DefineEngineMethod(SceneObject , getForwardVector , VectorF , () , "Get the direction this object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">facing.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the direction this object is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">facing.\n</a>" "@note This is the object's y axis." )
DefineEngineMethod(SceneObject , getInverseTransform , TransformF , () , "Get the object's inverse <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n</a>" "@return the inverse transform of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getMountedObject , S32 , (S32 slot) , "Get the object mounted at <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particular <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot.\n</a>" "@param slot mount slot index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return ID of the object mounted in the slot, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> no object." )
DefineEngineMethod(SceneObject , getMountedObjectCount , S32 , () , "Get the number of objects mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">us.\n</a>" "@return the number of mounted objects." )
DefineEngineMethod(SceneObject , getMountedObjectNode , S32 , (S32 slot) , "@brief Get the mount node index of the object mounted at our given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot.\n\n</a>" "@param slot mount slot index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return index of the mount node used by the object mounted in this slot." )
DefineEngineMethod(SceneObject , getMountNodeObject , S32 , (S32 node) , "@brief Get the object mounted at our given node <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n\n</a>" "@param node mount node index <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">query\n</a>" "@return ID of the first object mounted at the node, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> none found." )
DefineEngineMethod(SceneObject , getNumChildren , S32 , () , "returns number of direct child objects" )
DefineEngineMethod(SceneObject , getNumProgeny , S32 , () , "returns number of recursively-nested child objects" )
DefineEngineMethod(SceneObject , getObjectBox , Box3F , () , "Get the object's bounding box (relative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the object's origin).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return six fields, two Point3Fs, containing the min and max points of the " "objectbox." )
DefineEngineMethod(SceneObject , getObjectMount , S32 , () , "@brief Get the object we are mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@return the SimObjectID of the object we're mounted to, or 0 <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not mounted." )
DefineEngineMethod(SceneObject , getParent , S32 , () , "returns ID of parent <a href="/coding/class/classsceneobject/">SceneObject</a>" )
DefineEngineMethod(SceneObject , getPosition , Point3F , () , "Get the object's world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" "@return the current world position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getRightVector , VectorF , () , "Get the right vector of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the right direction of this object." "@note This is the object's x axis." )
DefineEngineMethod(SceneObject , getScale , Point3F , () , "Get the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scale.\n</a>" "@return object scale as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classpoint3f/">Point3F</a>" )
DefineEngineMethod(SceneObject , getTransform , TransformF , () , "Get the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n</a>" "@return the current transform of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , getType , S32 , () , "Return the type mask <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return The numeric type mask <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the object." )
DefineEngineMethod(SceneObject , getUpVector , VectorF , () , "Get the up vector of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vector indicating the up direction of this object." "@note This is the object's z axis." )
DefineEngineMethod(SceneObject , getWorldBox , Box3F , () , "Get the object's world bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box.\n</a>" "@return six fields, two Point3Fs, containing the min and max points of the " "worldbox." )
DefineEngineMethod(SceneObject , getWorldBoxCenter , Point3F , () , "Get the center of the object's world bounding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">box.\n</a>" "@return the center of the world bounding box <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this object." )
DefineEngineMethod(SceneObject , isGlobalBounds , bool , () , "Check <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> this object has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> global bounds <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" "If global bounds are set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be true, then the object is assumed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have an " "infinitely large bounding box <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> collision and rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">purposes.\n</a>" " @return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> global bounds." )
DefineEngineMethod(SceneObject , isMounted , bool , () , "@brief Check <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> we are mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another object, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> not mounted." )
DefineEngineMethod(SceneObject , mountObject , bool , (SceneObject *objB, S32 slot, TransformF txfm) , (TransformF::Identity) , "@brief Mount objB <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this object at the desired slot with optional <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform.\n\n</a>" "@param objB <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount onto <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">us\n</a>" "@param slot Mount slot <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ID\n</a>" "@param txfm (optional) mount offset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transform\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> successful, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> failed(objB is not valid)" )
DefineEngineMethod(SceneObject , setForwardVector , void , (VectorF newForward, VectorF upVector) , (VectorF(0, 0, 0), VectorF(0, 0, 1)) , "Sets the forward vector of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene object, making it face Y+along the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @param The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> forward vector <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set.\n</a>" " @param(Optional) The up vector <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> help orient the rotation." )
DefineEngineMethod(SceneObject , setPosition , void , (Point3F pos) , "Set the object's world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" "@param pos the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> world position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" )
DefineEngineMethod(SceneObject , setScale , void , (Point3F scale) , "Set the object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scale.\n</a>" "@param scale object scale <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">set\n</a>" )
DefineEngineMethod(SceneObject , setTransform , void , (TransformF txfm) , "Set the object's transform (orientation and position)." "@param txfm object transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> set" )
DefineEngineMethod(SceneObject , unmount , void , () , "Unmount us from the currently mounted object <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">any.\n</a>" )
DefineEngineMethod(SceneObject , unmountObject , bool , (SceneObject *target) , "@brief Unmount an object from <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ourselves.\n\n</a>" "@param target object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unmount\n</a>" "@return true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> successful, false <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">failed\n</a>" )
IMPLEMENT_CONOBJECT(SceneObject )
scopeCallback(SceneObject * obj, void * conPtr)
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 "scene/sceneObject.h" 31 32#include "platform/profiler.h" 33#include "console/consoleTypes.h" 34#include "console/engineAPI.h" 35#include "console/simPersistID.h" 36#include "sim/netConnection.h" 37#include "core/stream/bitStream.h" 38#include "scene/sceneManager.h" 39#include "scene/sceneTracker.h" 40#include "scene/sceneRenderState.h" 41#include "scene/zones/sceneZoneSpace.h" 42#include "collision/extrudedPolyList.h" 43#include "collision/earlyOutPolyList.h" 44#include "collision/optimizedPolyList.h" 45#include "math/mPolyhedron.h" 46#include "gfx/bitmap/gBitmap.h" 47#include "math/util/frustum.h" 48#include "math/mathIO.h" 49#include "math/mTransform.h" 50#include "T3D/gameBase/gameProcess.h" 51#include "T3D/gameBase/gameConnection.h" 52#include "T3D/accumulationVolume.h" 53 54IMPLEMENT_CONOBJECT(SceneObject); 55 56ConsoleDocClass( SceneObject, 57 "@brief A networkable object that exists in the 3D world.\n\n" 58 59 "The SceneObject class provides the foundation for 3D objects in the Engine. It " 60 "exposes the functionality for:\n\n" 61 62 "<ul><li>Position, rotation and scale within the world.</li>" 63 "<li>Working with a scene graph (in the Zone and Portal sections), allowing efficient " 64 "and robust rendering of the game scene.</li>" 65 "<li>Various helper functions, including functions to get bounding information " 66 "and momentum/velocity.</li>" 67 "<li>Mounting one SceneObject to another.</li>" 68 "<li>An interface for collision detection, as well as ray casting.</li>" 69 "<li>Lighting. SceneObjects can register lights both at lightmap generation " 70 "time, and dynamic lights at runtime (for special effects, such as from flame " 71 "or a projectile, or from an explosion).</li></ul>\n\n" 72 73 "You do not typically work with SceneObjects themselves. The SceneObject provides a reference " 74 "within the game world (the scene), but does not render to the client on its own. The " 75 "same is true of collision detection beyond that of the bounding box. Instead you " 76 "use one of the many classes that derrive from SceneObject, such as TSStatic.\n\n" 77 78 "@section SceneObject_Hiding Difference Between setHidden() and isRenderEnabled\n\n" 79 80 "When it comes time to decide if a SceneObject should render or not, there are two " 81 "methods that can stop the SceneObject from rendering at all. You need to be aware of " 82 "the differences between these two methods as they impact how the SceneObject is networked " 83 "from the server to the client.\n\n" 84 85 "The first method of manually controlling if a SceneObject is rendered is through its " 86 "SceneObject::isRenderEnabled property. When set to false the SceneObject is considered invisible but " 87 "still present within the scene. This means it still takes part in collisions and continues " 88 "to be networked.\n\n" 89 90 "The second method is using the setHidden() method. This will actually remove a SceneObject " 91 "from the scene and it will no longer be networked from the server to the cleint. Any client-side " 92 "ghost of the object will be deleted as the server no longer considers the object to be in scope.\n\n" 93 94 "@ingroup gameObjects\n" 95); 96 97#ifdef TORQUE_TOOLS 98extern bool gEditingMission; 99#endif 100 101Signal< void( SceneObject* ) > SceneObject::smSceneObjectAdd; 102Signal< void( SceneObject* ) > SceneObject::smSceneObjectRemove; 103 104 105//----------------------------------------------------------------------------- 106 107SceneObject::SceneObject() 108{ 109 mContainer = 0; 110 mTypeMask = DefaultObjectType; 111 mCollisionCount = 0; 112 mGlobalBounds = false; 113 114 mObjScale.set(1,1,1); 115 mObjToWorld.identity(); 116 mWorldToObj.identity(); 117 118 mObjBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0)); 119 mWorldBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0)); 120 mWorldSphere = SphereF(Point3F(0, 0, 0), 0); 121 122 mRenderObjToWorld.identity(); 123 mRenderWorldToObj.identity(); 124 mRenderWorldBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0)); 125 mRenderWorldSphere = SphereF(Point3F(0, 0, 0), 0); 126 127 mContainerSeqKey = 0; 128 129 mBinRefHead = NULL; 130 131 mSceneManager = NULL; 132 133 mNumCurrZones = 0; 134 mZoneRefHead = NULL; 135 mZoneRefDirty = false; 136 137 mBinMinX = 0xFFFFFFFF; 138 mBinMaxX = 0xFFFFFFFF; 139 mBinMinY = 0xFFFFFFFF; 140 mBinMaxY = 0xFFFFFFFF; 141 mLightPlugin = NULL; 142 143 mMount.object = NULL; 144 mMount.link = NULL; 145 mMount.list = NULL; 146 mMount.node = -1; 147 mMount.xfm = MatrixF::Identity; 148 mMountPID = NULL; 149 150 mSceneObjectLinks = NULL; 151 152 mObjectFlags.set( RenderEnabledFlag | SelectionEnabledFlag ); 153// PATHSHAPE 154 // init the scenegraph relationships to indicate no parent, no children, and no siblings 155 mGraph.parent = NULL; 156 mGraph.nextSibling = NULL; 157 mGraph.firstChild = NULL; 158 mGraph.objToParent.identity(); 159// PATHSHAPE END 160 mIsScopeAlways = false; 161 162 mAccuTex = NULL; 163 mSelectionFlags = 0; 164 mPathfindingIgnore = false; 165 166 mGameObjectAssetId = StringTable->insert(""); 167 168 mDirtyGameObject = false; 169} 170 171//----------------------------------------------------------------------------- 172 173SceneObject::~SceneObject() 174{ 175 AssertFatal( mZoneRefHead == NULL && mBinRefHead == NULL, 176 "SceneObject::~SceneObject - Object still linked in reference lists!"); 177 AssertFatal( !mSceneObjectLinks, 178 "SceneObject::~SceneObject() - object is still linked to SceneTrackers" ); 179 180 mAccuTex = NULL; 181 unlink(); 182} 183 184//----------------------------------------------------------------------------- 185 186bool SceneObject::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info) 187{ 188 // By default, all ray checking against the rendered mesh will be passed 189 // on to the collision mesh. This saves having to define both methods 190 // for simple objects. 191 return castRay( start, end, info ); 192} 193 194//----------------------------------------------------------------------------- 195 196bool SceneObject::containsPoint( const Point3F& point ) 197{ 198 // If it's not in the AABB, then it can't be in the OBB either, 199 // so early out. 200 201 if( !mWorldBox.isContained( point ) ) 202 return false; 203 204 // Transform point into object space and test it against 205 // our object space bounding box. 206 207 Point3F objPoint( 0, 0, 0 ); 208 getWorldTransform().mulP( point, &objPoint ); 209 objPoint.convolveInverse( getScale() ); 210 211 return ( mObjBox.isContained( objPoint ) ); 212} 213 214//----------------------------------------------------------------------------- 215 216bool SceneObject::collideBox(const Point3F &start, const Point3F &end, RayInfo *info) 217{ 218 const F32 * pStart = (const F32*)start; 219 const F32 * pEnd = (const F32*)end; 220 const F32 * pMin = (const F32*)mObjBox.minExtents; 221 const F32 * pMax = (const F32*)mObjBox.maxExtents; 222 223 F32 maxStartTime = -1; 224 F32 minEndTime = 1; 225 F32 startTime; 226 F32 endTime; 227 228 // used for getting normal 229 U32 hitIndex = 0xFFFFFFFF; 230 U32 side; 231 232 // walk the axis 233 for(U32 i = 0; i < 3; i++) 234 { 235 // 236 if(pStart[i] < pEnd[i]) 237 { 238 if(pEnd[i] < pMin[i] || pStart[i] > pMax[i]) 239 return(false); 240 241 F32 dist = pEnd[i] - pStart[i]; 242 243 startTime = (pStart[i] < pMin[i]) ? (pMin[i] - pStart[i]) / dist : -1; 244 endTime = (pEnd[i] > pMax[i]) ? (pMax[i] - pStart[i]) / dist : 1; 245 side = 1; 246 } 247 else 248 { 249 if(pStart[i] < pMin[i] || pEnd[i] > pMax[i]) 250 return(false); 251 252 F32 dist = pStart[i] - pEnd[i]; 253 startTime = (pStart[i] > pMax[i]) ? (pStart[i] - pMax[i]) / dist : -1; 254 endTime = (pEnd[i] < pMin[i]) ? (pStart[i] - pMin[i]) / dist : 1; 255 side = 0; 256 } 257 258 // 259 if(startTime > maxStartTime) 260 { 261 maxStartTime = startTime; 262 hitIndex = i * 2 + side; 263 } 264 if(endTime < minEndTime) 265 minEndTime = endTime; 266 if(minEndTime < maxStartTime) 267 return(false); 268 } 269 270 // fail if inside 271 if(maxStartTime < 0.f) 272 return(false); 273 274 // 275 static Point3F boxNormals[] = { 276 Point3F( 1, 0, 0), 277 Point3F(-1, 0, 0), 278 Point3F( 0, 1, 0), 279 Point3F( 0,-1, 0), 280 Point3F( 0, 0, 1), 281 Point3F( 0, 0,-1), 282 }; 283 284 // 285 AssertFatal(hitIndex != 0xFFFFFFFF, "SceneObject::collideBox"); 286 info->t = maxStartTime; 287 info->object = this; 288 mObjToWorld.mulV(boxNormals[hitIndex], &info->normal); 289 info->material = 0; 290 return(true); 291} 292 293//----------------------------------------------------------------------------- 294 295void SceneObject::disableCollision() 296{ 297 for (SceneObject* ptr = getMountList(); ptr; ptr = ptr->getMountLink()) 298 ptr->disableCollision(); 299 mCollisionCount++; 300 AssertFatal(mCollisionCount < 50, "SceneObject::disableCollision called 50 times on the same object. Is this inside a circular loop?" ); 301} 302 303//----------------------------------------------------------------------------- 304 305void SceneObject::enableCollision() 306{ 307 for (SceneObject* ptr = getMountList(); ptr; ptr = ptr->getMountLink()) 308 ptr->enableCollision(); 309 if (mCollisionCount) 310 --mCollisionCount; 311} 312 313//----------------------------------------------------------------------------- 314 315bool SceneObject::onAdd() 316{ 317 if ( !Parent::onAdd() ) 318 return false; 319 320 mIsScopeAlways = mNetFlags.test( ScopeAlways ); 321 322 mWorldToObj = mObjToWorld; 323 mWorldToObj.affineInverse(); 324 resetWorldBox(); 325 326 setRenderTransform(mObjToWorld); 327 328 resolveMountPID(); 329 330 smSceneObjectAdd.trigger(this); 331 332 return true; 333} 334 335//----------------------------------------------------------------------------- 336 337void SceneObject::onRemove() 338{ 339 smSceneObjectRemove.trigger(this); 340 341 unmount(); 342 plUnlink(); 343 344 Parent::onRemove(); 345// PATHSHAPE 346 if ( getParent() != NULL) attachToParent( NULL); 347// PATHSHAPE END 348} 349 350//----------------------------------------------------------------------------- 351 352void SceneObject::addToScene() 353{ 354 if( mSceneManager ) 355 return; 356 357 if( isClientObject() ) 358 gClientSceneGraph->addObjectToScene( this ); 359 else 360 gServerSceneGraph->addObjectToScene( this ); 361} 362 363//----------------------------------------------------------------------------- 364 365void SceneObject::removeFromScene() 366{ 367 if( !mSceneManager ) 368 return; 369 370 mSceneManager->removeObjectFromScene( this ); 371} 372 373//----------------------------------------------------------------------------- 374 375void SceneObject::onDeleteNotify( SimObject *obj ) 376{ 377 // We are comparing memory addresses so even if obj really is not a 378 // ProcessObject this cast shouldn't break anything. 379 if ( obj == mAfterObject ) 380 mAfterObject = NULL; 381 382 if ( obj == mMount.object ) 383 unmount(); 384 385 Parent::onDeleteNotify( obj ); 386} 387 388//----------------------------------------------------------------------------- 389 390void SceneObject::inspectPostApply() 391{ 392 if( isServerObject() ) 393 setMaskBits( MountedMask ); 394 Parent::inspectPostApply(); 395} 396 397//----------------------------------------------------------------------------- 398 399void SceneObject::setGlobalBounds() 400{ 401 mGlobalBounds = true; 402 mObjBox.minExtents.set( -1e10, -1e10, -1e10 ); 403 mObjBox.maxExtents.set( 1e10, 1e10, 1e10 ); 404 405 if( mSceneManager ) 406 mSceneManager->notifyObjectDirty( this ); 407} 408 409//----------------------------------------------------------------------------- 410 411void SceneObject::setTransform( const MatrixF& mat ) 412{ 413 // This test is a bit expensive so turn it off in release. 414#ifdef TORQUE_DEBUG 415 //AssertFatal( mat.isAffine(), "SceneObject::setTransform() - Bad transform (non affine)!" ); 416#endif 417 418 PROFILE_SCOPE( SceneObject_setTransform ); 419// PATHSHAPE 420 PerformUpdatesForChildren(mat); 421// PATHSHAPE END 422 423 // Update the transforms. 424 425 mObjToWorld = mWorldToObj = mat; 426 mWorldToObj.affineInverse(); 427 428 // Update the world-space AABB. 429 430 resetWorldBox(); 431 432 // If we're in a SceneManager, sync our scene state. 433 434 if( mSceneManager != NULL ) 435 mSceneManager->notifyObjectDirty( this ); 436 437 setRenderTransform( mat ); 438} 439 440//----------------------------------------------------------------------------- 441 442void SceneObject::setScale( const VectorF &scale ) 443{ 444 AssertFatal( !mIsNaN( scale ), "SceneObject::setScale() - The scale is NaN!" ); 445 446 // Avoid unnecessary scaling operations. 447 if ( mObjScale.equal( scale ) ) 448 return; 449 450 mObjScale = scale; 451 setTransform(MatrixF(mObjToWorld)); 452 453 // Make sure that any subclasses of me get a chance to react to the 454 // scale being changed. 455 onScaleChanged(); 456 457 setMaskBits( ScaleMask ); 458} 459 460void SceneObject::setForwardVector(VectorF newForward, VectorF upVector) 461{ 462 MatrixF mat = getTransform(); 463 464 VectorF up(0.0f, 0.0f, 1.0f); 465 VectorF axisX; 466 VectorF axisY = newForward; 467 VectorF axisZ; 468 469 if (upVector != VectorF::Zero) 470 up = upVector; 471 472 // Validate and normalize input: 473 F32 lenSq; 474 lenSq = axisY.lenSquared(); 475 if (lenSq < 0.000001f) 476 { 477 axisY.set(0.0f, 1.0f, 0.0f); 478 Con::errorf("SceneObject::setForwardVector() - degenerate forward vector"); 479 } 480 else 481 { 482 axisY /= mSqrt(lenSq); 483 } 484 485 486 lenSq = up.lenSquared(); 487 if (lenSq < 0.000001f) 488 { 489 up.set(0.0f, 0.0f, 1.0f); 490 Con::errorf("SceneObject::setForwardVector() - degenerate up vector - too small"); 491 } 492 else 493 { 494 up /= mSqrt(lenSq); 495 } 496 497 if (fabsf(mDot(up, axisY)) > 0.9999f) 498 { 499 Con::errorf("SceneObject::setForwardVector() - degenerate up vector - same as forward"); 500 // I haven't really tested this, but i think it generates something which should be not parallel to the previous vector: 501 F32 tmp = up.x; 502 up.x = -up.y; 503 up.y = up.z; 504 up.z = tmp; 505 } 506 507 // construct the remaining axes: 508 mCross(axisY, up, &axisX); 509 mCross(axisX, axisY, &axisZ); 510 511 mat.setColumn(0, axisX); 512 mat.setColumn(1, axisY); 513 mat.setColumn(2, axisZ); 514 515 setTransform(mat); 516} 517 518//----------------------------------------------------------------------------- 519 520void SceneObject::resetWorldBox() 521{ 522 AssertFatal(mObjBox.isValidBox(), "SceneObject::resetWorldBox - Bad object box!"); 523 524 mWorldBox = mObjBox; 525 mWorldBox.minExtents.convolve(mObjScale); 526 mWorldBox.maxExtents.convolve(mObjScale); 527 mObjToWorld.mul(mWorldBox); 528 529 AssertFatal(mWorldBox.isValidBox(), "SceneObject::resetWorldBox - Bad world box!"); 530 531 // Create mWorldSphere from mWorldBox 532 mWorldBox.getCenter(&mWorldSphere.center); 533 mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len(); 534 535 // Update tracker links. 536 537 for( SceneObjectLink* link = mSceneObjectLinks; link != NULL; 538 link = link->getNextLink() ) 539 link->update(); 540} 541 542//----------------------------------------------------------------------------- 543 544void SceneObject::resetObjectBox() 545{ 546 AssertFatal( mWorldBox.isValidBox(), "SceneObject::resetObjectBox - Bad world box!" ); 547 548 mObjBox = mWorldBox; 549 mWorldToObj.mul( mObjBox ); 550 551 Point3F objScale( mObjScale ); 552 objScale.setMax( Point3F( (F32)POINT_EPSILON, (F32)POINT_EPSILON, (F32)POINT_EPSILON ) ); 553 mObjBox.minExtents.convolveInverse( objScale ); 554 mObjBox.maxExtents.convolveInverse( objScale ); 555 556 AssertFatal( mObjBox.isValidBox(), "SceneObject::resetObjectBox - Bad object box!" ); 557 558 // Update the mWorldSphere from mWorldBox 559 mWorldBox.getCenter( &mWorldSphere.center ); 560 mWorldSphere.radius = ( mWorldBox.maxExtents - mWorldSphere.center ).len(); 561 562 // Update scene managers. 563 564 for( SceneObjectLink* link = mSceneObjectLinks; link != NULL; 565 link = link->getNextLink() ) 566 link->update(); 567} 568 569//----------------------------------------------------------------------------- 570 571void SceneObject::setRenderTransform(const MatrixF& mat) 572{ 573 PROFILE_START(SceneObj_setRenderTransform); 574 mRenderObjToWorld = mRenderWorldToObj = mat; 575 mRenderWorldToObj.affineInverse(); 576 577 AssertFatal(mObjBox.isValidBox(), "Bad object box!"); 578 resetRenderWorldBox(); 579 PROFILE_END(); 580} 581 582//----------------------------------------------------------------------------- 583 584void SceneObject::resetRenderWorldBox() 585{ 586 AssertFatal( mObjBox.isValidBox(), "Bad object box!" ); 587 588 mRenderWorldBox = mObjBox; 589 mRenderWorldBox.minExtents.convolve( mObjScale ); 590 mRenderWorldBox.maxExtents.convolve( mObjScale ); 591 mRenderObjToWorld.mul( mRenderWorldBox ); 592 593 AssertFatal( mRenderWorldBox.isValidBox(), "Bad world box!" ); 594 595 // Create mRenderWorldSphere from mRenderWorldBox. 596 597 mRenderWorldBox.getCenter( &mRenderWorldSphere.center ); 598 mRenderWorldSphere.radius = ( mRenderWorldBox.maxExtents - mRenderWorldSphere.center ).len(); 599} 600 601//----------------------------------------------------------------------------- 602 603void SceneObject::setHidden( bool hidden ) 604{ 605 if( hidden != isHidden() ) 606 { 607 // Add/remove the object from the scene. Removing it 608 // will also cause the NetObject to go out of scope since 609 // the container query will not find it anymore. However, 610 // ScopeAlways objects need to be treated separately as we 611 // do next. 612 613 if( !hidden ) 614 addToScene(); 615 else 616 removeFromScene(); 617 618 // ScopeAlways objects stay in scope no matter what, i.e. even 619 // if they aren't in the scene query anymore. So, to force ghosts 620 // to go away, we need to clear ScopeAlways while we are hidden. 621 622 if( hidden && mIsScopeAlways ) 623 clearScopeAlways(); 624 else if( !hidden && mIsScopeAlways ) 625 setScopeAlways(); 626 627 Parent::setHidden( hidden ); 628 } 629} 630 631//----------------------------------------------------------------------------- 632 633void SceneObject::initPersistFields() 634{ 635 addGroup("GameObject"); 636 addField("GameObject", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, SceneObject), "The asset Id used for the game object this entity is based on."); 637 638 addField("dirtyGameObject", TypeBool, Offset(mDirtyGameObject, SceneObject), "If this entity is a GameObject, it flags if this instance delinates from the template.", 639 AbstractClassRep::FieldFlags::FIELD_HideInInspectors); 640 endGroup("GameObject"); 641 642 addGroup( "Transform" ); 643 644 addProtectedField( "position", TypeMatrixPosition, Offset( mObjToWorld, SceneObject ), 645 &_setFieldPosition, &defaultProtectedGetFn, 646 "Object world position." ); 647 addProtectedField( "rotation", TypeMatrixRotation, Offset( mObjToWorld, SceneObject ), 648 &_setFieldRotation, &defaultProtectedGetFn, 649 "Object world orientation." ); 650 addProtectedField( "scale", TypePoint3F, Offset( mObjScale, SceneObject ), 651 &_setFieldScale, &defaultProtectedGetFn, 652 "Object world scale." ); 653 654 endGroup( "Transform" ); 655 656 addGroup( "Editing" ); 657 658 addProtectedField( "isRenderEnabled", TypeBool, Offset( mObjectFlags, SceneObject ), 659 &_setRenderEnabled, &_getRenderEnabled, 660 "Controls client-side rendering of the object.\n" 661 "@see isRenderable()\n" ); 662 663 addProtectedField( "isSelectionEnabled", TypeBool, Offset( mObjectFlags, SceneObject ), 664 &_setSelectionEnabled, &_getSelectionEnabled, 665 "Determines if the object may be selected from wihin the Tools.\n" 666 "@see isSelectable()\n" ); 667 668 endGroup( "Editing" ); 669 670 addGroup( "Mounting" ); 671 672 addProtectedField( "mountPID", TypePID, Offset( mMountPID, SceneObject ), &_setMountPID, &defaultProtectedGetFn, 673 "@brief PersistentID of object we are mounted to.\n\n" 674 "Unlike the SimObjectID that is determined at run time, the PersistentID of an object is saved with the level/mission and " 675 "may be used to form a link between objects." ); 676 addField( "mountNode", TypeS32, Offset( mMount.node, SceneObject ), "Node we are mounted to." ); 677 addField( "mountPos", TypeMatrixPosition, Offset( mMount.xfm, SceneObject ), "Position we are mounted at ( object space of our mount object )." ); 678 addField( "mountRot", TypeMatrixRotation, Offset( mMount.xfm, SceneObject ), "Rotation we are mounted at ( object space of our mount object )." ); 679 680 endGroup( "Mounting" ); 681 682 Parent::initPersistFields(); 683} 684 685bool SceneObject::_setGameObject(void* object, const char* index, const char* data) 686{ 687 // Sanity! 688 AssertFatal(data != NULL, "Cannot use a NULL asset Id."); 689 690 return true; //rbI->setMeshAsset(data); 691} 692 693//----------------------------------------------------------------------------- 694 695bool SceneObject::_setFieldPosition( void *object, const char *index, const char *data ) 696{ 697 SceneObject* so = static_cast<SceneObject*>( object ); 698 if ( so ) 699 { 700 MatrixF txfm( so->getTransform() ); 701 Con::setData( TypeMatrixPosition, &txfm, 0, 1, &data ); 702 so->setTransform( txfm ); 703 } 704 return false; 705} 706 707//----------------------------------------------------------------------------- 708 709bool SceneObject::_setFieldRotation( void *object, const char *index, const char *data ) 710{ 711 SceneObject* so = static_cast<SceneObject*>( object ); 712 if ( so ) 713 { 714 MatrixF txfm( so->getTransform() ); 715 Con::setData( TypeMatrixRotation, &txfm, 0, 1, &data ); 716 so->setTransform( txfm ); 717 } 718 return false; 719} 720 721//----------------------------------------------------------------------------- 722 723bool SceneObject::_setFieldScale( void *object, const char *index, const char *data ) 724{ 725 SceneObject* so = static_cast<SceneObject*>( object ); 726 if ( so ) 727 { 728 Point3F scale; 729 Con::setData( TypePoint3F, &scale, 0, 1, &data ); 730 so->setScale( scale ); 731 } 732 return false; 733} 734 735//----------------------------------------------------------------------------- 736 737bool SceneObject::writeField( StringTableEntry fieldName, const char* value ) 738{ 739 if( !Parent::writeField( fieldName, value ) ) 740 return false; 741 742 static StringTableEntry sIsRenderEnabled = StringTable->insert( "isRenderEnabled" ); 743 static StringTableEntry sIsSelectionEnabled = StringTable->insert( "isSelectionEnabled" ); 744 static StringTableEntry sMountNode = StringTable->insert( "mountNode" ); 745 static StringTableEntry sMountPos = StringTable->insert( "mountPos" ); 746 static StringTableEntry sMountRot = StringTable->insert( "mountRot" ); 747 748 // Don't write flag fields if they are at their default values. 749 750 if( fieldName == sIsRenderEnabled && dAtob( value ) ) 751 return false; 752 else if( fieldName == sIsSelectionEnabled && dAtob( value ) ) 753 return false; 754 else if ( mMountPID == NULL && ( fieldName == sMountNode || 755 fieldName == sMountPos || 756 fieldName == sMountRot ) ) 757 { 758 return false; 759 } 760 761 762 return true; 763} 764 765//----------------------------------------------------------------------------- 766 767static void scopeCallback( SceneObject* obj, void* conPtr ) 768{ 769 NetConnection* ptr = reinterpret_cast< NetConnection* >( conPtr ); 770 if( obj->isScopeable() ) 771 ptr->objectInScope(obj); 772} 773 774void SceneObject::onCameraScopeQuery( NetConnection* connection, CameraScopeQuery* query ) 775{ 776 SceneManager* sceneManager = getSceneManager(); 777 GameConnection* conn = dynamic_cast<GameConnection*> (connection); 778 if (conn && (query->visibleDistance = conn->getVisibleGhostDistance()) == 0.0f) 779 if ((query->visibleDistance = sceneManager->getVisibleGhostDistance()) == 0.0f) 780 query->visibleDistance = sceneManager->getVisibleDistance(); 781 782 // Object itself is in scope. 783 784 if( this->isScopeable() ) 785 connection->objectInScope( this ); 786 787 // If we're mounted to something, that object is in scope too. 788 789 if( isMounted() ) 790 connection->objectInScope( mMount.object ); 791 792 // If we're added to a scene graph, let the graph do the scene scoping. 793 // Otherwise just put everything in the server container in scope. 794 795 if( getSceneManager() ) 796 getSceneManager()->scopeScene( query, connection ); 797 else 798 gServerContainer.findObjects( 0xFFFFFFFF, scopeCallback, connection ); 799} 800 801//----------------------------------------------------------------------------- 802 803bool SceneObject::isRenderEnabled() const 804{ 805#ifdef TORQUE_TOOLS 806 if (gEditingMission) 807 { 808 AbstractClassRep *classRep = getClassRep(); 809 return (mObjectFlags.test(RenderEnabledFlag) && classRep->isRenderEnabled()); 810 } 811#endif 812 return (mObjectFlags.test(RenderEnabledFlag)); 813} 814 815//----------------------------------------------------------------------------- 816 817void SceneObject::setRenderEnabled( bool value ) 818{ 819 if( value ) 820 mObjectFlags.set( RenderEnabledFlag ); 821 else 822 mObjectFlags.clear( RenderEnabledFlag ); 823 824 setMaskBits( FlagMask ); 825} 826 827//----------------------------------------------------------------------------- 828 829const char* SceneObject::_getRenderEnabled( void* object, const char* data ) 830{ 831 SceneObject* obj = reinterpret_cast< SceneObject* >( object ); 832 if( obj->mObjectFlags.test( RenderEnabledFlag ) ) 833 return "1"; 834 else 835 return "0"; 836} 837 838//----------------------------------------------------------------------------- 839 840bool SceneObject::_setRenderEnabled( void *object, const char *index, const char *data ) 841{ 842 SceneObject* obj = reinterpret_cast< SceneObject* >( object ); 843 obj->setRenderEnabled( dAtob( data ) ); 844 return false; 845} 846 847//----------------------------------------------------------------------------- 848 849bool SceneObject::isSelectionEnabled() const 850{ 851 AbstractClassRep *classRep = getClassRep(); 852 return ( mObjectFlags.test( SelectionEnabledFlag ) && classRep->isSelectionEnabled() ); 853} 854 855//----------------------------------------------------------------------------- 856 857void SceneObject::setSelectionEnabled( bool value ) 858{ 859 if( value ) 860 mObjectFlags.set( SelectionEnabledFlag ); 861 else 862 mObjectFlags.clear( SelectionEnabledFlag ); 863 864 // Not synchronized on network so don't set dirty bit. 865} 866 867//----------------------------------------------------------------------------- 868 869const char* SceneObject::_getSelectionEnabled( void* object, const char* data ) 870{ 871 SceneObject* obj = reinterpret_cast< SceneObject* >( object ); 872 if( obj->mObjectFlags.test( SelectionEnabledFlag ) ) 873 return "true"; 874 else 875 return "false"; 876} 877 878//----------------------------------------------------------------------------- 879 880bool SceneObject::_setSelectionEnabled( void *object, const char *index, const char *data ) 881{ 882 SceneObject* obj = reinterpret_cast< SceneObject* >( object ); 883 obj->setSelectionEnabled( dAtob( data ) ); 884 return false; 885} 886 887//-------------------------------------------------------------------------- 888 889U32 SceneObject::packUpdate( NetConnection* conn, U32 mask, BitStream* stream ) 890{ 891 U32 retMask = Parent::packUpdate( conn, mask, stream ); 892 893 if ( stream->writeFlag( mask & FlagMask ) ) 894 stream->writeRangedU32( (U32)mObjectFlags, 0, getObjectFlagMax() ); 895 896 // PATHSHAPE 897 //Begin attachment 898 retMask = 0; //retry mask 899 900 if (stream->writeFlag(getParent() != NULL)) { 901 stream->writeAffineTransform(mGraph.objToParent); 902 } 903 if (stream->writeFlag(mask & MountedMask)) 904 { 905 // Check to see if we need to write an object ID 906 if (stream->writeFlag(mGraph.parent)) { 907 S32 t = conn->getGhostIndex(mGraph.parent); 908 // Check to see if we can actually ghost this... 909 if (t == -1) { 910 // Cant, try again later 911 retMask |= MountedMask; 912 stream->writeFlag(false); 913 } 914 else { 915 // Can, write it. 916 stream->writeFlag(true); 917 stream->writeRangedU32(U32(t), 0, NetConnection::MaxGhostCount); 918 stream->writeAffineTransform(mGraph.objToParent); 919 //Con::errorf("%d: sent mounted on %d", getId(), mGraph.parent->getId()); 920 } 921 } 922 } 923 // End of Attachment 924 // PATHSHAPE END 925 926 if ( mask & MountedMask ) 927 { 928 if ( mMount.object ) 929 { 930 S32 gIndex = conn->getGhostIndex( mMount.object ); 931 932 if ( stream->writeFlag( gIndex != -1 ) ) 933 { 934 stream->writeFlag( true ); 935 stream->writeInt( gIndex, NetConnection::GhostIdBitSize ); 936 if ( stream->writeFlag( mMount.node != -1 ) ) 937 stream->writeInt( mMount.node, NumMountPointBits ); 938 mathWrite( *stream, mMount.xfm ); 939 } 940 else 941 // Will have to try again later 942 retMask |= MountedMask; 943 } 944 else 945 // Unmount if this isn't the initial packet 946 if ( stream->writeFlag( !(mask & InitialUpdateMask) ) ) 947 stream->writeFlag( false ); 948 } 949 else 950 stream->writeFlag( false ); 951 952 return retMask; 953} 954 955//----------------------------------------------------------------------------- 956 957void SceneObject::unpackUpdate( NetConnection* conn, BitStream* stream ) 958{ 959 Parent::unpackUpdate( conn, stream ); 960 961 // FlagMask 962 if ( stream->readFlag() ) 963 mObjectFlags = stream->readRangedU32( 0, getObjectFlagMax() ); 964 965 // PATHSHAPE 966 // begin of attachment 967 if (stream->readFlag()) 968 { 969 MatrixF m; 970 stream->readAffineTransform(&m); 971 mGraph.objToParent = m; 972 } 973 if (stream->readFlag()) 974 { 975 // Check to see if we need to read an object ID 976 if (stream->readFlag()) 977 { 978 // Check to see if we can actually ghost this... 979 if (stream->readFlag()) 980 { 981 GameBase *newParent = static_cast<GameBase*>(conn->resolveGhost(stream->readRangedU32(0, NetConnection::MaxGhostCount))); 982 MatrixF m; 983 stream->readAffineTransform(&m); 984 985 if (getParent() != newParent) 986 { 987 clearProcessAfter(); 988 processAfter(newParent); 989 } 990 991 attachToParent(newParent, &m); 992 //Con::errorf("%d: got mounted on %d", getId(), mParentObject->getId()); 993 } 994 } 995 else 996 { 997 attachToParent(NULL); 998 } 999 } 1000 // End of attachment 1001 // PATHSHAPE END 1002 1003 // MountedMask 1004 if ( stream->readFlag() ) 1005 { 1006 if ( stream->readFlag() ) 1007 { 1008 S32 gIndex = stream->readInt( NetConnection::GhostIdBitSize ); 1009 SceneObject* obj = dynamic_cast<SceneObject*>( conn->resolveGhost( gIndex ) ); 1010 S32 node = -1; 1011 if ( stream->readFlag() ) // node != -1 1012 node = stream->readInt( NumMountPointBits ); 1013 MatrixF xfm; 1014 mathRead( *stream, &xfm ); 1015 if ( !obj ) 1016 { 1017 conn->setLastError( "Invalid packet from server." ); 1018 return; 1019 } 1020 obj->mountObject( this, node, xfm ); 1021 } 1022 else 1023 unmount(); 1024 } 1025} 1026 1027//----------------------------------------------------------------------------- 1028 1029void SceneObject::_updateZoningState() const 1030{ 1031 if( mZoneRefDirty ) 1032 { 1033 SceneZoneSpaceManager* manager = getSceneManager()->getZoneManager(); 1034 if( manager ) 1035 manager->updateObject( const_cast< SceneObject* >( this ) ); 1036 else 1037 mZoneRefDirty = false; 1038 } 1039} 1040 1041//----------------------------------------------------------------------------- 1042 1043U32 SceneObject::getCurrZone( const U32 index ) const 1044{ 1045 _updateZoningState(); 1046 1047 // Not the most efficient way to do this, walking the list, 1048 // but it's an uncommon call... 1049 ZoneRef* walk = mZoneRefHead; 1050 for( U32 i = 0; i < index; ++ i ) 1051 { 1052 walk = walk->nextInObj; 1053 AssertFatal( walk != NULL, "SceneObject::_getCurrZone - Too few object refs!" ); 1054 } 1055 AssertFatal( walk != NULL, "SceneObject::_getCurrZone - Too few object refs!" ); 1056 1057 return walk->zone; 1058} 1059 1060//----------------------------------------------------------------------------- 1061 1062Point3F SceneObject::getPosition() const 1063{ 1064 Point3F pos; 1065 mObjToWorld.getColumn(3, &pos); 1066 return pos; 1067} 1068 1069//----------------------------------------------------------------------------- 1070 1071Point3F SceneObject::getRenderPosition() const 1072{ 1073 Point3F pos; 1074 mRenderObjToWorld.getColumn(3, &pos); 1075 return pos; 1076} 1077 1078//----------------------------------------------------------------------------- 1079 1080void SceneObject::setPosition(const Point3F &pos) 1081{ 1082 AssertFatal( !mIsNaN( pos ), "SceneObject::setPosition() - The position is NaN!" ); 1083 1084 MatrixF xform = mObjToWorld; 1085 xform.setColumn(3, pos); 1086 setTransform(xform); 1087} 1088 1089//----------------------------------------------------------------------------- 1090 1091F32 SceneObject::distanceTo(const Point3F &pnt) const 1092{ 1093 return mWorldBox.getDistanceToPoint( pnt ); 1094} 1095 1096//----------------------------------------------------------------------------- 1097 1098void SceneObject::processAfter( ProcessObject *obj ) 1099{ 1100 AssertFatal( dynamic_cast<SceneObject*>( obj ), "SceneObject::processAfter - Got non-SceneObject!" ); 1101 1102 mAfterObject = (SceneObject*)obj; 1103 if ( mAfterObject->mAfterObject == this ) 1104 mAfterObject->mAfterObject = NULL; 1105 1106 getProcessList()->markDirty(); 1107} 1108 1109//----------------------------------------------------------------------------- 1110 1111void SceneObject::clearProcessAfter() 1112{ 1113 mAfterObject = NULL; 1114} 1115 1116//----------------------------------------------------------------------------- 1117 1118void SceneObject::setProcessTick( bool t ) 1119{ 1120 if ( t == mProcessTick ) 1121 return; 1122 1123 if ( mProcessTick ) 1124 { 1125 if ( !getMountedObjectCount() ) 1126 plUnlink(); // Only unlink if there is nothing mounted to us 1127 mProcessTick = false; 1128 } 1129 else 1130 { 1131 // Just to be sure... 1132 plUnlink(); 1133 1134 getProcessList()->addObject( this ); 1135 1136 mProcessTick = true; 1137 } 1138} 1139 1140//----------------------------------------------------------------------------- 1141 1142ProcessList* SceneObject::getProcessList() const 1143{ 1144 if ( isClientObject() ) 1145 return ClientProcessList::get(); 1146 else 1147 return ServerProcessList::get(); 1148} 1149 1150//------------------------------------------------------------------------- 1151 1152bool SceneObject::isMounted() 1153{ 1154 resolveMountPID(); 1155 1156 return mMount.object != NULL; 1157} 1158 1159//----------------------------------------------------------------------------- 1160 1161S32 SceneObject::getMountedObjectCount() 1162{ 1163 S32 count = 0; 1164 for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link) 1165 count++; 1166 return count; 1167} 1168 1169//----------------------------------------------------------------------------- 1170 1171SceneObject* SceneObject::getMountedObject(S32 idx) 1172{ 1173 if (idx >= 0) { 1174 S32 count = 0; 1175 for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link) 1176 if (count++ == idx) 1177 return itr; 1178 } 1179 return NULL; 1180} 1181 1182//----------------------------------------------------------------------------- 1183 1184S32 SceneObject::getMountedObjectNode(S32 idx) 1185{ 1186 if (idx >= 0) { 1187 S32 count = 0; 1188 for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link) 1189 if (count++ == idx) 1190 return itr->mMount.node; 1191 } 1192 return -1; 1193} 1194 1195//----------------------------------------------------------------------------- 1196 1197SceneObject* SceneObject::getMountNodeObject(S32 node) 1198{ 1199 for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link) 1200 if (itr->mMount.node == node) 1201 return itr; 1202 return NULL; 1203} 1204 1205//----------------------------------------------------------------------------- 1206 1207bool SceneObject::_setMountPID( void* object, const char* index, const char* data ) 1208{ 1209 SceneObject* so = static_cast<SceneObject*>( object ); 1210 if ( so ) 1211 { 1212 // Unmount old object (PID reference is released even if it had been resolved yet) 1213 if ( so->mMountPID ) 1214 { 1215 so->mMountPID->decRefCount(); 1216 so->mMountPID = NULL; 1217 } 1218 so->unmount(); 1219 1220 // Get the new PID (new object will be mounted on demand) 1221 Con::setData( TypePID, &so->mMountPID, 0, 1, &data ); 1222 if ( so->mMountPID ) 1223 so->mMountPID->incRefCount(); // Prevent PID from being deleted out from under us! 1224 } 1225 return false; 1226} 1227 1228void SceneObject::resolveMountPID() 1229{ 1230 if ( mMountPID && !mMount.object ) 1231 { 1232 SceneObject *obj = dynamic_cast< SceneObject* >( mMountPID->getObject() ); 1233 if ( obj ) 1234 obj->mountObject( this, mMount.node, mMount.xfm ); 1235 } 1236} 1237 1238//----------------------------------------------------------------------------- 1239 1240void SceneObject::mountObject( SceneObject *obj, S32 node, const MatrixF &xfm ) 1241{ 1242 if ( obj->mMount.object == this ) 1243 { 1244 // Already mounted to this 1245 // So update our node and xfm which may have changed. 1246 obj->mMount.node = node; 1247 obj->mMount.xfm = xfm; 1248 } 1249 else 1250 { 1251 if ( obj->mMount.object ) 1252 obj->unmount(); 1253 1254 obj->mMount.object = this; 1255 obj->mMount.node = node; 1256 obj->mMount.link = mMount.list; 1257 obj->mMount.xfm = xfm; 1258 mMount.list = obj; 1259 1260 // Assign PIDs to both objects 1261 if ( isServerObject() ) 1262 { 1263 obj->getOrCreatePersistentId(); 1264 if ( !obj->mMountPID ) 1265 { 1266 obj->mMountPID = getOrCreatePersistentId(); 1267 obj->mMountPID->incRefCount(); 1268 } 1269 } 1270 1271 obj->onMount( this, node ); 1272 } 1273} 1274 1275//----------------------------------------------------------------------------- 1276 1277void SceneObject::unmountObject( SceneObject *obj ) 1278{ 1279 if ( obj->mMount.object == this ) 1280 { 1281 // Find and unlink the object 1282 for ( SceneObject **ptr = &mMount.list; *ptr; ptr = &(*ptr)->mMount.link ) 1283 { 1284 if ( *ptr == obj ) 1285 { 1286 *ptr = obj->mMount.link; 1287 break; 1288 } 1289 } 1290 1291 obj->mMount.object = NULL; 1292 obj->mMount.link = NULL; 1293 1294 if( obj->mMountPID != NULL ) // Only on server. 1295 { 1296 obj->mMountPID->decRefCount(); 1297 obj->mMountPID = NULL; 1298 } 1299 1300 obj->onUnmount( this, obj->mMount.node ); 1301 } 1302} 1303 1304//----------------------------------------------------------------------------- 1305 1306void SceneObject::unmount() 1307{ 1308 if (mMount.object) 1309 mMount.object->unmountObject(this); 1310} 1311 1312//----------------------------------------------------------------------------- 1313 1314void SceneObject::onMount( SceneObject *obj, S32 node ) 1315{ 1316 deleteNotify( obj ); 1317 1318 if ( !isGhost() ) 1319 { 1320 setMaskBits( MountedMask ); 1321 //onMount_callback( node ); 1322 } 1323} 1324 1325//----------------------------------------------------------------------------- 1326 1327void SceneObject::onUnmount( SceneObject *obj, S32 node ) 1328{ 1329 clearNotify(obj); 1330 1331 if ( !isGhost() ) 1332 { 1333 setMaskBits( MountedMask ); 1334 //onUnmount_callback( node ); 1335 } 1336} 1337 1338//----------------------------------------------------------------------------- 1339 1340void SceneObject::getMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat ) 1341{ 1342 MatrixF mountTransform( xfm ); 1343 const Point3F &scale = getScale(); 1344 Point3F position = mountTransform.getPosition(); 1345 position.convolve( scale ); 1346 mountTransform.setPosition( position ); 1347 1348 outMat->mul( mObjToWorld, mountTransform ); 1349} 1350 1351//----------------------------------------------------------------------------- 1352 1353void SceneObject::getRenderMountTransform( F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat ) 1354{ 1355 MatrixF mountTransform( xfm ); 1356 const Point3F &scale = getScale(); 1357 Point3F position = mountTransform.getPosition(); 1358 position.convolve( scale ); 1359 mountTransform.setPosition( position ); 1360 1361 outMat->mul( mRenderObjToWorld, mountTransform ); 1362} 1363 1364//============================================================================= 1365// Console API. 1366//============================================================================= 1367// MARK: ---- Console API ---- 1368 1369//----------------------------------------------------------------------------- 1370 1371DefineEngineMethod( SceneObject, getType, S32, (),, 1372 "Return the type mask for this object.\n" 1373 "@return The numeric type mask for the object." ) 1374{ 1375 return object->getTypeMask(); 1376} 1377 1378//----------------------------------------------------------------------------- 1379 1380DefineEngineMethod( SceneObject, mountObject, bool, 1381 ( SceneObject* objB, S32 slot, TransformF txfm ), ( TransformF::Identity ), 1382 "@brief Mount objB to this object at the desired slot with optional transform.\n\n" 1383 1384 "@param objB Object to mount onto us\n" 1385 "@param slot Mount slot ID\n" 1386 "@param txfm (optional) mount offset transform\n" 1387 "@return true if successful, false if failed (objB is not valid)" ) 1388{ 1389 if ( objB ) 1390 { 1391 object->mountObject( objB, slot, txfm.getMatrix() ); 1392 return true; 1393 } 1394 return false; 1395} 1396 1397//----------------------------------------------------------------------------- 1398 1399DefineEngineMethod( SceneObject, unmountObject, bool, ( SceneObject* target ),, 1400 "@brief Unmount an object from ourselves.\n\n" 1401 1402 "@param target object to unmount\n" 1403 "@return true if successful, false if failed\n" ) 1404{ 1405 if ( target ) 1406 { 1407 object->unmountObject(target); 1408 return true; 1409 } 1410 return false; 1411} 1412 1413//----------------------------------------------------------------------------- 1414 1415DefineEngineMethod( SceneObject, unmount, void, (),, 1416 "Unmount us from the currently mounted object if any.\n" ) 1417{ 1418 object->unmount(); 1419} 1420 1421//----------------------------------------------------------------------------- 1422 1423DefineEngineMethod( SceneObject, isMounted, bool, (),, 1424 "@brief Check if we are mounted to another object.\n\n" 1425 "@return true if mounted to another object, false if not mounted." ) 1426{ 1427 return object->isMounted(); 1428} 1429 1430//----------------------------------------------------------------------------- 1431 1432DefineEngineMethod( SceneObject, getObjectMount, S32, (),, 1433 "@brief Get the object we are mounted to.\n\n" 1434 "@return the SimObjectID of the object we're mounted to, or 0 if not mounted." ) 1435{ 1436 return object->isMounted()? object->getObjectMount()->getId(): 0; 1437} 1438 1439//----------------------------------------------------------------------------- 1440 1441DefineEngineMethod( SceneObject, getMountedObjectCount, S32, (),, 1442 "Get the number of objects mounted to us.\n" 1443 "@return the number of mounted objects." ) 1444{ 1445 return object->getMountedObjectCount(); 1446} 1447 1448//----------------------------------------------------------------------------- 1449 1450DefineEngineMethod( SceneObject, getMountedObject, S32, ( S32 slot ),, 1451 "Get the object mounted at a particular slot.\n" 1452 "@param slot mount slot index to query\n" 1453 "@return ID of the object mounted in the slot, or 0 if no object." ) 1454{ 1455 SceneObject* mobj = object->getMountedObject( slot ); 1456 return mobj? mobj->getId(): 0; 1457} 1458 1459//----------------------------------------------------------------------------- 1460 1461DefineEngineMethod( SceneObject, getMountedObjectNode, S32, ( S32 slot ),, 1462 "@brief Get the mount node index of the object mounted at our given slot.\n\n" 1463 "@param slot mount slot index to query\n" 1464 "@return index of the mount node used by the object mounted in this slot." ) 1465{ 1466 return object->getMountedObjectNode( slot ); 1467} 1468 1469//----------------------------------------------------------------------------- 1470 1471DefineEngineMethod( SceneObject, getMountNodeObject, S32, ( S32 node ),, 1472 "@brief Get the object mounted at our given node index.\n\n" 1473 "@param node mount node index to query\n" 1474 "@return ID of the first object mounted at the node, or 0 if none found." ) 1475{ 1476 SceneObject* mobj = object->getMountNodeObject( node ); 1477 return mobj? mobj->getId(): 0; 1478} 1479 1480//----------------------------------------------------------------------------- 1481 1482DefineEngineMethod( SceneObject, getTransform, TransformF, (),, 1483 "Get the object's transform.\n" 1484 "@return the current transform of the object\n" ) 1485{ 1486 return object->getTransform(); 1487} 1488 1489//----------------------------------------------------------------------------- 1490 1491DefineEngineMethod( SceneObject, getInverseTransform, TransformF, (),, 1492 "Get the object's inverse transform.\n" 1493 "@return the inverse transform of the object\n" ) 1494{ 1495 return object->getWorldTransform(); 1496} 1497 1498//----------------------------------------------------------------------------- 1499 1500DefineEngineMethod( SceneObject, getPosition, Point3F, (),, 1501 "Get the object's world position.\n" 1502 "@return the current world position of the object\n" ) 1503{ 1504 return object->getTransform().getPosition(); 1505} 1506 1507DefineEngineMethod( SceneObject, setPosition, void, (Point3F pos),, 1508 "Set the object's world position.\n" 1509 "@param pos the new world position of the object\n" ) 1510{ 1511 return object->setPosition(pos); 1512} 1513 1514//----------------------------------------------------------------------------- 1515 1516DefineEngineMethod( SceneObject, getEulerRotation, Point3F, (),, 1517 "Get Euler rotation of this object.\n" 1518 "@return the orientation of the object in the form of rotations around the " 1519 "X, Y and Z axes in degrees.\n" ) 1520{ 1521 Point3F euler = object->getTransform().toEuler(); 1522 1523 // Convert to degrees. 1524 euler.x = mRadToDeg( euler.x ); 1525 euler.y = mRadToDeg( euler.y ); 1526 euler.z = mRadToDeg( euler.z ); 1527 1528 return euler; 1529} 1530 1531//----------------------------------------------------------------------------- 1532 1533DefineEngineMethod( SceneObject, getForwardVector, VectorF, (),, 1534 "Get the direction this object is facing.\n" 1535 "@return a vector indicating the direction this object is facing.\n" 1536 "@note This is the object's y axis." ) 1537{ 1538 return object->getTransform().getForwardVector(); 1539} 1540 1541//----------------------------------------------------------------------------- 1542 1543DefineEngineMethod( SceneObject, getRightVector, VectorF, (),, 1544 "Get the right vector of the object.\n" 1545 "@return a vector indicating the right direction of this object." 1546 "@note This is the object's x axis." ) 1547{ 1548 return object->getTransform().getRightVector(); 1549} 1550 1551//----------------------------------------------------------------------------- 1552 1553DefineEngineMethod( SceneObject, getUpVector, VectorF, (),, 1554 "Get the up vector of the object.\n" 1555 "@return a vector indicating the up direction of this object." 1556 "@note This is the object's z axis." ) 1557{ 1558 return object->getTransform().getUpVector(); 1559} 1560 1561//----------------------------------------------------------------------------- 1562 1563DefineEngineMethod( SceneObject, setTransform, void, ( TransformF txfm ),, 1564 "Set the object's transform (orientation and position)." 1565 "@param txfm object transform to set" ) 1566{ 1567// PATHSHAPE 1568 object->PerformUpdatesForChildren(txfm.getMatrix()); 1569// PATHSHAPE END 1570 if ( !txfm.hasRotation() ) 1571 object->setPosition( txfm.getPosition() ); 1572 else 1573 object->setTransform( txfm.getMatrix() ); 1574} 1575 1576//----------------------------------------------------------------------------- 1577 1578DefineEngineMethod( SceneObject, getScale, Point3F, (),, 1579 "Get the object's scale.\n" 1580 "@return object scale as a Point3F" ) 1581{ 1582 return object->getScale(); 1583} 1584 1585//----------------------------------------------------------------------------- 1586 1587DefineEngineMethod( SceneObject, setScale, void, ( Point3F scale ),, 1588 "Set the object's scale.\n" 1589 "@param scale object scale to set\n" ) 1590{ 1591 object->setScale( scale ); 1592} 1593 1594//----------------------------------------------------------------------------- 1595 1596DefineEngineMethod( SceneObject, getWorldBox, Box3F, (),, 1597 "Get the object's world bounding box.\n" 1598 "@return six fields, two Point3Fs, containing the min and max points of the " 1599 "worldbox." ) 1600{ 1601 return object->getWorldBox(); 1602} 1603 1604//----------------------------------------------------------------------------- 1605 1606DefineEngineMethod( SceneObject, getWorldBoxCenter, Point3F, (),, 1607 "Get the center of the object's world bounding box.\n" 1608 "@return the center of the world bounding box for this object." ) 1609{ 1610 Point3F center; 1611 object->getWorldBox().getCenter( ¢er ); 1612 return center; 1613} 1614 1615//----------------------------------------------------------------------------- 1616 1617DefineEngineMethod( SceneObject, getObjectBox, Box3F, (),, 1618 "Get the object's bounding box (relative to the object's origin).\n" 1619 "@return six fields, two Point3Fs, containing the min and max points of the " 1620 "objectbox." ) 1621{ 1622 return object->getObjBox(); 1623} 1624 1625//----------------------------------------------------------------------------- 1626 1627DefineEngineMethod( SceneObject, isGlobalBounds, bool, (),, 1628 "Check if this object has a global bounds set.\n" 1629 "If global bounds are set to be true, then the object is assumed to have an " 1630 "infinitely large bounding box for collision and rendering purposes.\n" 1631 "@return true if the object has a global bounds." ) 1632{ 1633 return object->isGlobalBounds(); 1634} 1635 1636DefineEngineMethod(SceneObject, setForwardVector, void, (VectorF newForward, VectorF upVector), (VectorF(0, 0, 0), VectorF(0, 0, 1)), 1637 "Sets the forward vector of a scene object, making it face Y+ along the new vector.\n" 1638 "@param The new forward vector to set.\n" 1639 "@param (Optional) The up vector to use to help orient the rotation.") 1640{ 1641 object->setForwardVector(newForward, upVector); 1642} 1643 1644// PATHSHAPE 1645// Move RenderTransform by set amount 1646// no longer used 1647 1648void SceneObject::moveRender(const Point3F &delta) 1649{ 1650 Point3F pos; 1651 1652 const MatrixF& tmat = getRenderTransform(); 1653 tmat.getColumn(3,&pos); 1654 AngAxisF aa(tmat); 1655 pos += delta; 1656 1657 MatrixF mat; 1658 aa.setMatrix(&mat); 1659 mat.setColumn(3,pos); 1660 setRenderTransform(mat); 1661} 1662 1663void SceneObject::PerformUpdatesForChildren(MatrixF mat){ 1664 UpdateXformChange(mat); 1665 for (U32 i=0; i < getNumChildren(); i++) { 1666 SceneObject *o = getChild(i); 1667 o->updateChildTransform(); //update the position of the child object 1668 } 1669} 1670 1671 1672 1673 1674 1675// This function will move the players based on how much it's 1676// parent have moved 1677void SceneObject::updateChildTransform(){ 1678 if (getParent() != NULL){ 1679 MatrixF one; 1680 MatrixF two; 1681 MatrixF three; 1682 MatrixF four; 1683 MatrixF mat; 1684 one= getTransform(); 1685 two = getParent()->getTransform(); 1686 one.affineInverse(); 1687 four.mul(two,one); 1688 mat.mul(getParent()->mLastXform,getTransform()); 1689 setTransform(mat); 1690 } 1691} 1692 1693// This function will move the rendered image based on how much it's 1694// parent have moved since the processtick. 1695// For some reason the player object must be updated via it's GetRenderTransform seen below, 1696// Other objects seem to require getTransform() only 1697void SceneObject::updateRenderChangesByParent(){ 1698 if (getParent() != NULL){ 1699 MatrixF renderXform = getParent()->getRenderTransform(); 1700 MatrixF xform = getParent()->getTransform(); 1701 xform.affineInverse(); 1702 1703 MatrixF offset; 1704 offset.mul(renderXform, xform); 1705 1706 MatrixF mat; 1707 1708 //add the "offset" caused by the parents change, and add it to it's own 1709 // This is needed by objects that update their own render transform thru interpolate tick 1710 // Mostly for stationary objects. 1711 1712 if (getClassName() == StringTable->insert("Player")) 1713 mat.mul(offset,getRenderTransform()); 1714 else 1715 mat.mul(offset,getTransform()); 1716 setRenderTransform(mat); 1717 } 1718} 1719 1720 1721 1722 1723 1724//Ramen - Move Transform by set amount 1725//written by Anthony Lovell 1726void SceneObject::move(F32 x, F32 y, F32 z) 1727{ 1728 Point3F delta; 1729 delta.x = x; 1730 delta.y = y; 1731 delta.z = z; 1732 move(delta); 1733} 1734// move by a specified delta in root coordinate space 1735void SceneObject::move(const Point3F &delta) 1736{ 1737 Point3F pos; 1738 1739 const MatrixF& tmat = getTransform(); 1740 tmat.getColumn(3,&pos); 1741 AngAxisF aa(tmat); 1742 1743 pos += delta; 1744 1745 MatrixF mat; 1746 aa.setMatrix(&mat); 1747 mat.setColumn(3,pos); 1748 setTransform(mat); 1749} 1750 1751 1752 1753//written by Anthony Lovell ---------------------------------------------------------- 1754U32 1755SceneObject::getNumChildren() const 1756{ 1757 U32 num = 0; 1758 for (SceneObject *cur = mGraph.firstChild; cur; cur = cur->mGraph.nextSibling) 1759 num++; 1760 return num; 1761} 1762//written by Anthony Lovell ---------------------------------------------------------- 1763SceneObject * 1764SceneObject::getChild(U32 index) const 1765{ 1766 SceneObject *cur = mGraph.firstChild; 1767 for (U32 i = 0; 1768 cur && i < index; 1769 i++) 1770 cur = cur->mGraph.nextSibling; 1771 return cur; 1772} 1773 1774 1775 1776 1777void SceneObject::UpdateXformChange(const MatrixF &mat){ 1778// This function gets the difference between the Transform and current Render transform 1779// Used for Interpolation matching with the child objects who rely on this data. 1780 1781 MatrixF oldxform = getTransform(); 1782 1783 oldxform.affineInverse(); 1784 mLastXform.mul(mat,oldxform); 1785 1786} 1787 1788 1789//---------------------------------------------------------- 1790bool 1791SceneObject::attachChildAt(SceneObject *subObject, MatrixF atThisOffset, S32 node) 1792{ 1793 AssertFatal(subObject, "attaching a null subObject"); 1794 AssertFatal(!isChildOf(subObject), "cyclic attachChild()"); 1795 bool b = subObject->attachToParent(this, &atThisOffset, node); 1796 if (!b) 1797 return false; 1798 1799 return true; 1800} 1801 1802//---------------------------------------------------------- 1803bool 1804SceneObject::attachChildAt(SceneObject *subObject, Point3F atThisPosition) 1805{ 1806 AssertFatal(subObject, "attaching a null subObject"); 1807 AssertFatal(!isChildOf(subObject), "cyclic attachChild()"); 1808 bool b = subObject->attachToParent(this); 1809 if (!b) 1810 return false; 1811 1812 subObject->mGraph.objToParent.setColumn(3, atThisPosition); 1813// calcTransformFromLocalTransform(); 1814 1815 return true; 1816} 1817 1818//---------------------------------------------------------- 1819bool 1820SceneObject::attachChild(SceneObject *child) 1821{ 1822 AssertFatal(child, "attaching a null subObject"); 1823 AssertFatal(!isChildOf(child), "cyclic attachChild()"); 1824 1825 return child->attachToParent(this); 1826} 1827 1828 1829//---------------------------------------------------------- 1830/// returns a count of children plus their children, recursively 1831U32 1832SceneObject::getNumProgeny() const 1833{ 1834 U32 num = 0; 1835 for (SceneObject *cur = mGraph.firstChild; cur; cur = cur->mGraph.nextSibling) { 1836 num += 1 + cur->getNumProgeny(); 1837 } 1838 return num; 1839} 1840 1841DefineEngineMethod(SceneObject, getNumChildren, S32, (),, "returns number of direct child objects") 1842{ 1843 return object->getNumChildren(); 1844} 1845 1846DefineEngineMethod(SceneObject, getNumProgeny, S32, (),, "returns number of recursively-nested child objects") 1847{ 1848 return object->getNumProgeny(); 1849} 1850 1851DefineEngineMethod(SceneObject, getChild, S32, (S32 _index), (0), "getChild(S32 index) -- returns child SceneObject at given index") 1852{ 1853 SceneObject *s = object->getChild(_index); 1854 return s ? s->getId() : 0; 1855} 1856 1857DefineEngineMethod(SceneObject, attachChildAt, bool, (SceneObject* _subObject, MatrixF _offset, S32 _node), (nullAsType<SceneObject*>(), MatrixF::Identity, 0), "(SceneObject subObject, MatrixF offset, S32 offset)" 1858 "Mount object to this one with the specified offset expressed in our coordinate space.") 1859{ 1860 if (_subObject != nullptr) 1861 { 1862 return object->attachChildAt(_subObject, _offset, _node); 1863 } 1864 else 1865 { 1866 Con::errorf("Couldn't addObject()!"); 1867 return false; 1868 } 1869} 1870 1871DefineEngineMethod(SceneObject, attachToParent, bool, (const char*_sceneObject), ,"attachToParent(SceneObject)" 1872 "specify a null or non-null parent") 1873{ 1874 SceneObject * t; 1875 1876 if(Sim::findObject(_sceneObject, t)) 1877 { 1878 return object->attachToParent(t); 1879 } 1880 else 1881 { 1882 if ((!String::compare("0", _sceneObject))|| (!String::compare("", _sceneObject))) 1883 return object->attachToParent(NULL); 1884 else 1885 { 1886 Con::errorf("Couldn't setParent()!"); 1887 return false; 1888 } 1889 } 1890} 1891 1892DefineEngineMethod(SceneObject, getParent, S32, (),, "returns ID of parent SceneObject") 1893{ 1894 SceneObject *p = object->getParent(); 1895 return p ? p->getId() : -1; 1896} 1897 1898DefineEngineMethod(SceneObject, attachChild, bool, (const char*_subObject),, "(SceneObject subObject)" 1899 "attach an object to this one, preserving its present transform.") 1900{ 1901 SceneObject * t; 1902 MatrixF m; 1903 if(Sim::findObject(_subObject, t)) 1904 return object->attachChild(t); 1905 1906 Con::errorf("Couldn't addObject()!"); 1907 return false; 1908} 1909 1910bool SceneObject::isChildOf(SceneObject *so) 1911{ 1912 SceneObject *p = mGraph.parent; 1913 if (p) { 1914 if (p == so) 1915 return true; 1916 else 1917 return p->isChildOf(so); 1918 } else 1919 return false; 1920} 1921 1922 1923 1924bool SceneObject::attachToParent(SceneObject *newParent, MatrixF *atThisOffset/* = NULL */, S32 node ) 1925{ 1926 SceneObject *oldParent = mGraph.parent; 1927 1928 if (oldParent == newParent) 1929 return true; 1930 1931 // cycles in the scene hierarchy are forbidden! 1932 // that is: a SceneObject cannot be a child of its progeny 1933 if (newParent && newParent->isChildOf(this)) 1934 return false; 1935 1936 mGraph.parent = newParent; 1937 1938 if (oldParent) { 1939 1940 clearNotify(oldParent); 1941 1942 // remove this SceneObject from the list of children of oldParent 1943 SceneObject *cur = oldParent->mGraph.firstChild; 1944 if (cur == this) { // if we are the first child, this is easy 1945 oldParent->mGraph.firstChild = mGraph.nextSibling; 1946 } else { 1947 while (cur->mGraph.nextSibling != this) { 1948 cur = cur->mGraph.nextSibling; 1949 // ASSERT cur != NULL; 1950 } 1951 cur->mGraph.nextSibling = mGraph.nextSibling; 1952 } 1953 oldParent->onLostChild(this); 1954 } 1955 1956 if (newParent) { 1957 1958 deleteNotify(newParent); // if we are deleted, inform our parent 1959 1960 // add this SceneObject to the list of children of oldParent 1961 mGraph.nextSibling = newParent->mGraph.firstChild; 1962 newParent->mGraph.firstChild = this; 1963 mGraph.parent = newParent; 1964 1965 newParent->onNewChild(this); 1966 1967 if (atThisOffset) 1968 mGraph.objToParent = *atThisOffset; 1969 } else { 1970 mGraph.parent = NULL; 1971 mGraph.nextSibling = NULL; 1972 mGraph.objToParent = mObjToWorld; 1973 } 1974 1975 onLostParent(oldParent); 1976 onNewParent(newParent); 1977 1978 setMaskBits(MountedMask); 1979 return true; 1980} 1981 1982DefineEngineMethod(SceneObject, detachChild, bool, (const char*_subObject),, "SceneObject subObject") 1983{ 1984 SceneObject * t; 1985 if(Sim::findObject(_subObject, t)) { 1986 return t->attachToParent(NULL); 1987 } else 1988 return false; 1989} 1990 1991// subclasses can do something with these if they care to 1992void SceneObject::onNewParent(SceneObject *newParent) {} 1993void SceneObject::onLostParent(SceneObject *oldParent){} 1994void SceneObject::onNewChild(SceneObject *newKid){} 1995void SceneObject::onLostChild(SceneObject *lostKid){} 1996