guiShapeEdPreview.cpp
Engine/source/gui/editor/guiShapeEdPreview.cpp
Public Variables
Public Functions
ConsoleDocClass(GuiShapeEdPreview , "@brief This <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> provides the 3D view <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the Shape Editor tool, and is " "not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> general purpose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">use.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControls\n</a>" " @internal" )
DefineEngineMethod(GuiShapeEdPreview , addThread , void , () , "Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> thread (initially without any sequence set)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , computeShapeBounds , Box3F , () , "Compute the bounding box of the shape using the current detail and node <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transforms\n\n</a>" "@return the bounding box \"min.x min.y min.z max.x max.y max.z\"" )
DefineEngineMethod(GuiShapeEdPreview , exportToCollada , void , (const char *path) , "Export the current shape and all mounted objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> COLLADA (.dae).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "Note that animation is not exported, and all geometry is combined into <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "single <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mesh.\n\n</a>" " @param path Destination <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">filename\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , fitToShape , void , () , "Adjust the camera position and zoom <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fit the shape within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMeshHidden , bool , (const char *name) , "Return whether the named object is currently <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">hidden\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadDir , F32 , (S32 slot) , "Get the playback direction of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return direction of the sequence (-1=reverse, 0=paused, 1=forward)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadPos , F32 , (S32 slot) , "Get the playback position of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return playback position of the sequence (0-1)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadSequence , const char * , (S32 slot) , "Get the name of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return name of the sequence (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> any)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getThreadCount , S32 , () , "Get the number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n\n</a>" "@return the number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getThreadSequence , const char * , () , "Get the name of the sequence assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the active thread" )
DefineEngineMethod(GuiShapeEdPreview , mountShape , bool , (const char *shapePath, const char *nodeName, const char *type, S32 slot) , "Mount <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape onto the <a href="/coding/file/x86unixmain_8cpp/#x86unixmain_8cpp_1a217dbf8b442f20279ea00b898af96f52">main</a> shape at the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node\n\n</a>" "@param shapePath path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mount\n</a>" "@param nodeName name of the node on the <a href="/coding/file/x86unixmain_8cpp/#x86unixmain_8cpp_1a217dbf8b442f20279ea00b898af96f52">main</a> shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param type type of mounting <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use (<a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a>, Image or Wheel)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param slot mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , refreshShape , void , () , "Refresh the shape (used when the shape meshes or nodes have been added or removed)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , refreshThreadSequences , void , () )
DefineEngineMethod(GuiShapeEdPreview , removeThread , void , (S32 slot) , "Removes the specifed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thread\n\n</a>" "@param slot index of the thread <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">remove\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setAllMeshesHidden , void , (bool hidden) , "Show or hide all objects in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMeshHidden , void , (const char *name, bool hidden) , "Show or hide the named object in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setModel , bool , (const char *shapePath) , "Sets the model <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be displayed in this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control\n\n</a>" "@param shapeName Name of the model <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">display.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the model was loaded successfully, false <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">otherwise.\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountNode , void , (S32 slot, const char *nodeName) , "Set the node <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape is mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param nodename name of the node <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadDir , void , (S32 slot, F32 dir) , "Set the playback direction of the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param dir playback direction (-1=backwards, 0=paused, 1=forwards)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadPos , void , (S32 slot, F32 pos) , "Set the sequence position of the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param pos sequence position (0-1)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadSequence , void , (S32 slot, const char *name) , "Set the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param name name of the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">play\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setOrbitPos , void , (Point3F pos) , "Set the camera orbit <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n\n</a>" "@param pos Position in the form \"x y z\"\n" )
DefineEngineMethod(GuiShapeEdPreview , setThreadSequence , void , (const char *name, F32 duration, F32 pos, bool play) , (0, 0, false) , "Sets the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the active <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thread.\n\n</a>" "@param name name of the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">play\n</a>" "@param duration transition duration (0 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> no transition)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pos position in the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param play <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> true, the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> sequence will play during the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transition\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setTimeScale , void , (F32 scale) , "Set the time scale of all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n\n</a>" "@param scale <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> time scale <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , unmountAll , void , () , "Unmount all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shapes\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , unmountShape , void , (S32 slot) , "Unmount the shape in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , updateNodeTransforms , void , () , "Refresh the shape node transforms (used when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node transform has been modified externally)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
IMPLEMENT_CALLBACK(GuiShapeEdPreview , onThreadPosChanged , void , (F32 pos, bool inTransition) , (pos, inTransition) , "Called when the position of the active thread has changed, such as during " "playback." )
Detailed Description
Public Variables
const F32 sMoveScaler
const S32 sNodeRectSize
const F32 sZoomScaler
Public Functions
ConsoleDocClass(GuiShapeEdPreview , "@brief This <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> provides the 3D view <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the Shape Editor tool, and is " "not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> general purpose <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">use.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiControls\n</a>" " @internal" )
DefineEngineMethod(GuiShapeEdPreview , addThread , void , () , "Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> thread (initially without any sequence set)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , computeShapeBounds , Box3F , () , "Compute the bounding box of the shape using the current detail and node <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transforms\n\n</a>" "@return the bounding box \"min.x min.y min.z max.x max.y max.z\"" )
DefineEngineMethod(GuiShapeEdPreview , exportToCollada , void , (const char *path) , "Export the current shape and all mounted objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> COLLADA (.dae).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "Note that animation is not exported, and all geometry is combined into <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "single <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mesh.\n\n</a>" " @param path Destination <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">filename\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , fitToShape , void , () , "Adjust the camera position and zoom <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fit the shape within the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMeshHidden , bool , (const char *name) , "Return whether the named object is currently <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">hidden\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadDir , F32 , (S32 slot) , "Get the playback direction of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return direction of the sequence (-1=reverse, 0=paused, 1=forward)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadPos , F32 , (S32 slot) , "Get the playback position of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return playback position of the sequence (0-1)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getMountThreadSequence , const char * , (S32 slot) , "Get the name of the sequence playing on this mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@return name of the sequence (<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> any)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getThreadCount , S32 , () , "Get the number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n\n</a>" "@return the number of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , getThreadSequence , const char * , () , "Get the name of the sequence assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the active thread" )
DefineEngineMethod(GuiShapeEdPreview , mountShape , bool , (const char *shapePath, const char *nodeName, const char *type, S32 slot) , "Mount <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape onto the <a href="/coding/file/x86unixmain_8cpp/#x86unixmain_8cpp_1a217dbf8b442f20279ea00b898af96f52">main</a> shape at the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node\n\n</a>" "@param shapePath path <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mount\n</a>" "@param nodeName name of the node on the <a href="/coding/file/x86unixmain_8cpp/#x86unixmain_8cpp_1a217dbf8b442f20279ea00b898af96f52">main</a> shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param type type of mounting <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use (<a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a>, Image or Wheel)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param slot mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , refreshShape , void , () , "Refresh the shape (used when the shape meshes or nodes have been added or removed)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , refreshThreadSequences , void , () )
DefineEngineMethod(GuiShapeEdPreview , removeThread , void , (S32 slot) , "Removes the specifed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thread\n\n</a>" "@param slot index of the thread <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">remove\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setAllMeshesHidden , void , (bool hidden) , "Show or hide all objects in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMeshHidden , void , (const char *name, bool hidden) , "Show or hide the named object in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setModel , bool , (const char *shapePath) , "Sets the model <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be displayed in this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">control\n\n</a>" "@param shapeName Name of the model <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">display.\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the model was loaded successfully, false <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">otherwise.\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountNode , void , (S32 slot, const char *nodeName) , "Set the node <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape is mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param nodename name of the node <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> mount <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadDir , void , (S32 slot, F32 dir) , "Set the playback direction of the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param dir playback direction (-1=backwards, 0=paused, 1=forwards)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadPos , void , (S32 slot, F32 pos) , "Set the sequence position of the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param pos sequence position (0-1)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setMountThreadSequence , void , (S32 slot, const char *name) , "Set the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the shape mounted in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param name name of the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">play\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setOrbitPos , void , (Point3F pos) , "Set the camera orbit <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n\n</a>" "@param pos Position in the form \"x y z\"\n" )
DefineEngineMethod(GuiShapeEdPreview , setThreadSequence , void , (const char *name, F32 duration, F32 pos, bool play) , (0, 0, false) , "Sets the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the active <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">thread.\n\n</a>" "@param name name of the sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">play\n</a>" "@param duration transition duration (0 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> no transition)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pos position in the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param play <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> true, the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> sequence will play during the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">transition\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , setTimeScale , void , (F32 scale) , "Set the time scale of all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">threads\n\n</a>" "@param scale <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> time scale <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , unmountAll , void , () , "Unmount all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shapes\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , unmountShape , void , (S32 slot) , "Unmount the shape in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" "@param slot mounted shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">slot\n</a>" )
DefineEngineMethod(GuiShapeEdPreview , updateNodeTransforms , void , () , "Refresh the shape node transforms (used when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node transform has been modified externally)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" )
IMPLEMENT_CALLBACK(GuiShapeEdPreview , onThreadPosChanged , void , (F32 pos, bool inTransition) , (pos, inTransition) , "Called when the position of the active thread has changed, such as during " "playback." )
IMPLEMENT_CONOBJECT(GuiShapeEdPreview )
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#include "console/consoleTypes.h" 25#include "console/console.h" 26#include "console/engineAPI.h" 27#include "gui/core/guiCanvas.h" 28#include "gui/editor/guiShapeEdPreview.h" 29#include "renderInstance/renderPassManager.h" 30#include "lighting/lightManager.h" 31#include "lighting/lightInfo.h" 32#include "core/resourceManager.h" 33#include "scene/sceneManager.h" 34#include "scene/sceneRenderState.h" 35#include "gfx/primBuilder.h" 36#include "gfx/gfxDrawUtil.h" 37#include "collision/concretePolyList.h" 38 39#ifdef TORQUE_COLLADA 40 #include "collision/optimizedPolyList.h" 41 #include "ts/collada/colladaUtils.h" 42#endif 43 44static const F32 sMoveScaler = 50.0f; 45static const F32 sZoomScaler = 200.0f; 46static const S32 sNodeRectSize = 16; 47 48IMPLEMENT_CONOBJECT( GuiShapeEdPreview ); 49 50ConsoleDocClass( GuiShapeEdPreview, 51 "@brief This control provides the 3D view for the Shape Editor tool, and is " 52 "not intended for general purpose use.\n" 53 54 "@ingroup GuiControls\n" 55 "@internal" 56); 57 58IMPLEMENT_CALLBACK( GuiShapeEdPreview, onThreadPosChanged, void, ( F32 pos, bool inTransition ), ( pos, inTransition), 59 "Called when the position of the active thread has changed, such as during " 60 "playback." ); 61 62 63GuiShapeEdPreview::GuiShapeEdPreview() 64: mOrbitDist( 5.0f ), 65 mMoveSpeed ( 1.0f ), 66 mZoomSpeed ( 1.0f ), 67 mGridDimension( 30, 30 ), 68 mModel( NULL ), 69 mRenderGhost( false ), 70 mRenderNodes( false ), 71 mRenderBounds( false ), 72 mRenderObjBox( false ), 73 mRenderColMeshes( false ), 74 mRenderMounts( true ), 75 mSunDiffuseColor( 255, 255, 255, 255 ), 76 mSelectedNode( -1 ), 77 mSunAmbientColor( 140, 140, 140, 255 ), 78 mHoverNode( -1 ), 79 mSelectedObject( -1 ), 80 mUsingAxisGizmo( false ), 81 mSelectedObjDetail( 0 ), 82 mEditingSun( false ), 83 mGizmoDragID( 0 ), 84 mTimeScale( 1.0f ), 85 mActiveThread( -1 ), 86 mFakeSun( NULL ), 87 mLastRenderTime( 0 ), 88 mCameraRot( 0, 0, 3.9f ), 89 mSunRot( 45.0f, 0, 135.0f ), 90 mRenderCameraAxes( false ), 91 mOrbitPos( 0, 0, 0 ), 92 mFixedDetail( true ), 93 mCurrentDL( 0 ), 94 mDetailSize( 0 ), 95 mDetailPolys( 0 ), 96 mPixelSize( 0 ), 97 mNumMaterials( 0 ), 98 mNumDrawCalls( 0 ), 99 mNumBones( 0 ), 100 mNumWeights( 0 ), 101 mColMeshes( 0 ), 102 mColPolys( 0 ) 103{ 104 mActive = true; 105 106 // By default don't do dynamic reflection 107 // updates for this viewport. 108 mReflectPriority = 0.0f; 109} 110 111GuiShapeEdPreview::~GuiShapeEdPreview() 112{ 113 SAFE_DELETE( mModel ); 114 SAFE_DELETE( mFakeSun ); 115} 116 117void GuiShapeEdPreview::initPersistFields() 118{ 119 addGroup( "Rendering" ); 120 addField( "editSun", TypeBool, Offset( mEditingSun, GuiShapeEdPreview ), 121 "If true, dragging the gizmo will rotate the sun direction" ); 122 addField( "selectedNode", TypeS32, Offset( mSelectedNode, GuiShapeEdPreview ), 123 "Index of the selected node, or -1 if none" ); 124 addField( "selectedObject", TypeS32, Offset( mSelectedObject, GuiShapeEdPreview ), 125 "Index of the selected object, or -1 if none" ); 126 addField( "selectedObjDetail", TypeS32, Offset( mSelectedObjDetail, GuiShapeEdPreview ), 127 "Index of the selected object detail mesh, or 0 if none" ); 128 addField( "gridDimension", TypePoint2I, Offset( mGridDimension, GuiShapeEdPreview ), 129 "Grid dimensions (number of rows and columns) in the form \"rows cols\"" ); 130 addField( "renderGrid", TypeBool, Offset( mRenderGridPlane, EditTSCtrl ), 131 "Flag indicating whether to draw the grid" ); 132 addField( "renderNodes", TypeBool, Offset( mRenderNodes, GuiShapeEdPreview ), 133 "Flag indicating whether to render the shape nodes" ); 134 addField( "renderGhost", TypeBool, Offset( mRenderGhost, GuiShapeEdPreview ), 135 "Flag indicating whether to render the shape in 'ghost' mode (transparent)" ); 136 addField( "renderBounds", TypeBool, Offset( mRenderBounds, GuiShapeEdPreview ), 137 "Flag indicating whether to render the shape bounding box" ); 138 addField( "renderObjBox", TypeBool, Offset( mRenderObjBox, GuiShapeEdPreview ), 139 "Flag indicating whether to render the selected object's bounding box" ); 140 addField( "renderColMeshes", TypeBool, Offset( mRenderColMeshes, GuiShapeEdPreview ), 141 "Flag indicating whether to render the shape's collision geometry" ); 142 addField( "renderMounts", TypeBool, Offset( mRenderMounts, GuiShapeEdPreview ), 143 "Flag indicating whether to render mounted objects" ); 144 endGroup( "Rendering" ); 145 146 addGroup( "Sun" ); 147 addProtectedField( "sunDiffuse", TypeColorI, Offset( mSunDiffuseColor, GuiShapeEdPreview ), &setFieldSunDiffuse, &defaultProtectedGetFn, 148 "Ambient color for the sun" ); 149 addProtectedField( "sunAmbient", TypeColorI, Offset( mSunAmbientColor, GuiShapeEdPreview ), &setFieldSunAmbient, &defaultProtectedGetFn, 150 "Diffuse color for the sun" ); 151 addProtectedField( "sunAngleX", TypeF32, Offset( mSunRot.x, GuiShapeEdPreview ), &setFieldSunAngleX, &defaultProtectedGetFn, 152 "X-axis rotation angle for the sun" ); 153 addProtectedField( "sunAngleZ", TypeF32, Offset( mSunRot.z, GuiShapeEdPreview ), &setFieldSunAngleZ, &defaultProtectedGetFn, 154 "Z-axis rotation angle for the sun" ); 155 endGroup( "Sun" ); 156 157 addGroup( "Animation" ); 158 addField( "activeThread", TypeS32, Offset( mActiveThread, GuiShapeEdPreview ), 159 "Index of the active thread, or -1 if none" ); 160 addProtectedField( "threadPos", TypeF32, NULL, &setFieldThreadPos, &getFieldThreadPos, 161 "Current position of the active thread (0-1)" ); 162 addProtectedField( "threadDirection", TypeS32, NULL, &setFieldThreadDir, &getFieldThreadDir, 163 "Playback direction of the active thread" ); 164 addProtectedField( "threadPingPong", TypeBool, NULL, &setFieldThreadPingPong, &getFieldThreadPingPong, 165 "'PingPong' mode of the active thread" ); 166 endGroup( "Animation" ); 167 168 addGroup( "Detail Stats" ); 169 addField( "fixedDetail", TypeBool, Offset( mFixedDetail, GuiShapeEdPreview ), 170 "If false, the current detail is selected based on camera distance" ); 171 addField( "orbitDist", TypeF32, Offset( mOrbitDist, GuiShapeEdPreview ), 172 "The current distance from the camera to the model" ); 173 addProtectedField( "currentDL", TypeS32, Offset( mCurrentDL, GuiShapeEdPreview ), &setFieldCurrentDL, &defaultProtectedGetFn, 174 "The current detail level" ); 175 addProtectedField( "detailSize", TypeS32, Offset( mDetailSize, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 176 "The size of the current detail" ); 177 addProtectedField( "detailPolys", TypeS32, Offset( mDetailPolys, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 178 "Number of polygons in the current detail" ); 179 addProtectedField( "pixelSize", TypeF32, Offset( mPixelSize, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 180 "The current pixel size of the model" ); 181 addProtectedField( "numMaterials", TypeS32, Offset( mNumMaterials, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 182 "The number of materials in the current detail level" ); 183 addProtectedField( "numDrawCalls", TypeS32, Offset( mNumDrawCalls, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 184 "The number of draw calls in the current detail level" ); 185 addProtectedField( "numBones", TypeS32, Offset( mNumBones, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 186 "The number of bones in the current detail level (skins only)" ); 187 addProtectedField( "numWeights", TypeS32, Offset( mNumWeights, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 188 "The number of vertex weights in the current detail level (skins only)" ); 189 addProtectedField( "colMeshes", TypeS32, Offset( mColMeshes, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 190 "The number of collision meshes in the shape" ); 191 addProtectedField( "colPolys", TypeS32, Offset( mColPolys, GuiShapeEdPreview ), &defaultProtectedSetFn, &defaultProtectedGetFn, 192 "The total number of collision polygons (all meshes) in the shape" ); 193 endGroup( "Detail Stats" ); 194 195 Parent::initPersistFields(); 196} 197 198bool GuiShapeEdPreview::setFieldCurrentDL( void *object, const char *index, const char *data ) 199{ 200 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 201 if ( gui ) 202 gui->setCurrentDetail( mFloor( dAtof( data ) + 0.5f ) ); 203 return false; 204} 205 206bool GuiShapeEdPreview::setFieldSunDiffuse( void *object, const char *index, const char *data ) 207{ 208 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 209 if ( gui ) 210 { 211 Con::setData( TypeColorI, &gui->mSunDiffuseColor, 0, 1, &data ); 212 gui->updateSun(); 213 } 214 return false; 215} 216 217bool GuiShapeEdPreview::setFieldSunAmbient( void *object, const char *index, const char *data ) 218{ 219 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 220 if ( gui ) 221 { 222 Con::setData( TypeColorI, &gui->mSunAmbientColor, 0, 1, &data ); 223 gui->updateSun(); 224 } 225 return false; 226} 227 228bool GuiShapeEdPreview::setFieldSunAngleX( void *object, const char *index, const char *data ) 229{ 230 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 231 if ( gui ) 232 { 233 Con::setData( TypeF32, &gui->mSunRot.x, 0, 1, &data ); 234 gui->updateSun(); 235 } 236 return false; 237} 238 239bool GuiShapeEdPreview::setFieldSunAngleZ( void *object, const char *index, const char *data ) 240{ 241 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 242 if ( gui ) 243 { 244 Con::setData( TypeF32, &gui->mSunRot.z, 0, 1, &data ); 245 gui->updateSun(); 246 } 247 return false; 248} 249 250bool GuiShapeEdPreview::setFieldThreadPos( void *object, const char *index, const char *data ) 251{ 252 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 253 if ( gui && ( gui->mActiveThread >= 0 ) && gui->mThreads[gui->mActiveThread].key ) 254 gui->mModel->setPos( gui->mThreads[gui->mActiveThread].key, dAtof( data ) ); 255 return false; 256} 257 258const char *GuiShapeEdPreview::getFieldThreadPos( void *object, const char *data ) 259{ 260 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 261 if ( gui && ( gui->mActiveThread >= 0 ) && gui->mThreads[gui->mActiveThread].key ) 262 return Con::getFloatArg( gui->mModel->getPos( gui->mThreads[gui->mActiveThread].key ) ); 263 else 264 return "0"; 265} 266 267bool GuiShapeEdPreview::setFieldThreadDir( void *object, const char *index, const char *data ) 268{ 269 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 270 if ( gui && ( gui->mActiveThread >= 0 ) ) 271 { 272 Thread& thread = gui->mThreads[gui->mActiveThread]; 273 Con::setData( TypeS32, &(thread.direction), 0, 1, &data ); 274 if ( thread.key ) 275 gui->mModel->setTimeScale( thread.key, gui->mTimeScale * thread.direction ); 276 } 277 return false; 278} 279 280const char *GuiShapeEdPreview::getFieldThreadDir( void *object, const char *data ) 281{ 282 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 283 if ( gui && ( gui->mActiveThread >= 0 ) ) 284 return Con::getIntArg( gui->mThreads[gui->mActiveThread].direction ); 285 else 286 return "0"; 287} 288 289bool GuiShapeEdPreview::setFieldThreadPingPong( void *object, const char *index, const char *data ) 290{ 291 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 292 if ( gui && ( gui->mActiveThread >= 0 ) ) 293 Con::setData( TypeBool, &(gui->mThreads[gui->mActiveThread].pingpong), 0, 1, &data ); 294 return false; 295} 296 297const char *GuiShapeEdPreview::getFieldThreadPingPong( void *object, const char *data ) 298{ 299 GuiShapeEdPreview* gui = static_cast<GuiShapeEdPreview*>( object ); 300 if ( gui && ( gui->mActiveThread >= 0 ) ) 301 return Con::getIntArg( gui->mThreads[gui->mActiveThread].pingpong ); 302 else 303 return "0"; 304} 305 306 307bool GuiShapeEdPreview::onWake() 308{ 309 if (!Parent::onWake()) 310 return false; 311 312 if (!mFakeSun ) 313 mFakeSun = LIGHTMGR->createLightInfo(); 314 315 mFakeSun->setRange( 2000000.0f ); 316 updateSun(); 317 318 mGizmoProfile->mode = MoveMode; 319 320 return( true ); 321} 322 323void GuiShapeEdPreview::setDisplayType( S32 type ) 324{ 325 Parent::setDisplayType( type ); 326 mOrthoCamTrans.set( 0, 0, 0 ); 327} 328 329//----------------------------------------------------------------------------- 330 331void GuiShapeEdPreview::setCurrentDetail(S32 dl) 332{ 333 if ( mModel ) 334 { 335 TSShape* shape = mModel->getShape(); 336 S32 smallest = shape->mSmallestVisibleDL; 337 shape->mSmallestVisibleDL = shape->details.size() - 1; 338 mModel->setCurrentDetail( dl ); 339 shape->mSmallestVisibleDL = smallest; 340 341 // Match the camera distance to this detail if necessary 342 //@todo if ( !gui->mFixedDetail ) 343 } 344} 345 346bool GuiShapeEdPreview::setObjectModel(const char* modelName) 347{ 348 SAFE_DELETE( mModel ); 349 unmountAll(); 350 mThreads.clear(); 351 mActiveThread = -1; 352 353 if (modelName && modelName[0]) 354 { 355 Resource<TSShape> model = ResourceManager::get().load( modelName ); 356 if (! bool( model )) 357 { 358 Con::warnf( avar("GuiShapeEdPreview: Failed to load model %s. Please check your model name and load a valid model.", modelName )); 359 return false; 360 } 361 362 mModel = new TSShapeInstance( model, true ); 363 AssertFatal( mModel, avar("GuiShapeEdPreview: Failed to load model %s. Please check your model name and load a valid model.", modelName )); 364 365 TSShape* shape = mModel->getShape(); 366 367 // Initialize camera values: 368 mOrbitPos = shape->center; 369 370 // Set camera move and zoom speed according to model size 371 mMoveSpeed = shape->mRadius / sMoveScaler; 372 mZoomSpeed = shape->mRadius / sZoomScaler; 373 374 // Reset node selection 375 mHoverNode = -1; 376 mSelectedNode = -1; 377 mSelectedObject = -1; 378 mSelectedObjDetail = 0; 379 mProjectedNodes.setSize( shape->nodes.size() ); 380 381 // Reset detail stats 382 mCurrentDL = 0; 383 384 // the first time recording 385 mLastRenderTime = Platform::getVirtualMilliseconds(); 386 } 387 388 return true; 389} 390 391void GuiShapeEdPreview::addThread() 392{ 393 if ( mModel ) 394 { 395 mThreads.increment(); 396 if ( mActiveThread == -1 ) 397 mActiveThread = 0; 398 } 399} 400 401void GuiShapeEdPreview::removeThread(S32 slot) 402{ 403 if ( slot < mThreads.size() ) 404 { 405 if ( mThreads[slot].key ) 406 mModel->destroyThread( mThreads[slot].key ); 407 mThreads.erase( slot ); 408 409 if ( mActiveThread >= mThreads.size() ) 410 mActiveThread = mThreads.size() - 1; 411 } 412} 413 414void GuiShapeEdPreview::setTimeScale( F32 scale ) 415{ 416 // Update time scale for all threads 417 mTimeScale = scale; 418 for ( S32 i = 0; i < mThreads.size(); i++ ) 419 { 420 if ( mThreads[i].key ) 421 mModel->setTimeScale( mThreads[i].key, mTimeScale * mThreads[i].direction ); 422 } 423} 424 425void GuiShapeEdPreview::setActiveThreadSequence(const char* seqName, F32 duration, F32 pos, bool play) 426{ 427 if ( mActiveThread == -1 ) 428 return; 429 430 setThreadSequence(mThreads[mActiveThread], mModel, seqName, duration, pos, play); 431} 432 433void GuiShapeEdPreview::setThreadSequence(GuiShapeEdPreview::Thread& thread, TSShapeInstance* shape, const char* seqName, F32 duration, F32 pos, bool play) 434{ 435 thread.seqName = seqName; 436 437 S32 seq = shape->getShape()->findSequence( thread.seqName ); 438 if ( thread.key && ( shape->getSequence(thread.key) == seq ) ) 439 return; 440 441 if ( seq == -1 ) 442 { 443 // This thread is now set to an invalid sequence, so the key must be 444 // removed, but we keep the thread info around in case the user changes 445 // back to a valid sequence 446 if ( thread.key ) 447 { 448 shape->destroyThread( thread.key ); 449 thread.key = NULL; 450 } 451 } 452 else 453 { 454 // Add a TSThread key if one does not already exist 455 if ( !thread.key ) 456 { 457 thread.key = shape->addThread(); 458 shape->setTimeScale( thread.key, mTimeScale * thread.direction ); 459 } 460 461 // Transition to slider or synched position? 462 if ( pos == -1.0f ) 463 pos = shape->getPos( thread.key ); 464 465 if ( duration == 0.0f ) 466 { 467 // No transition => go straight to new sequence 468 shape->setSequence( thread.key, seq, pos ); 469 } 470 else 471 { 472 // Get the current position if transitioning to the sync position 473 shape->setTimeScale( thread.key, thread.direction >= 0 ? 1 : -1 ); 474 shape->transitionToSequence( thread.key, seq, pos, duration, play ); 475 shape->setTimeScale( thread.key, mTimeScale * thread.direction ); 476 } 477 } 478} 479 480const char* GuiShapeEdPreview::getThreadSequence() const 481{ 482 return ( mActiveThread >= 0 ) ? mThreads[mActiveThread].seqName : ""; 483} 484 485void GuiShapeEdPreview::refreshThreadSequences() 486{ 487 S32 oldActive = mActiveThread; 488 489 for ( S32 i = 0; i < mThreads.size(); i++ ) 490 { 491 Thread& thread = mThreads[i]; 492 if ( !thread.key ) 493 continue; 494 495 // Detect changed (or removed) sequence indices 496 if ( mModel->getSequence(thread.key) != mModel->getShape()->findSequence( thread.seqName ) ) 497 { 498 mActiveThread = i; 499 setThreadSequence( thread, mModel, thread.seqName, 0.0f, mModel->getPos( thread.key ), false ); 500 } 501 } 502 503 mActiveThread = oldActive; 504} 505 506//----------------------------------------------------------------------------- 507// MOUNTING 508 509bool GuiShapeEdPreview::mountShape(const char* modelName, const char* nodeName, const char* mountType, S32 slot) 510{ 511 if ( !modelName || !modelName[0] ) 512 return false; 513 514 Resource<TSShape> model = ResourceManager::get().load( modelName ); 515 if ( !bool( model ) ) 516 return false; 517 518 TSShapeInstance* tsi = new TSShapeInstance( model, true ); 519 520 if ( slot == -1 ) 521 { 522 slot = mMounts.size(); 523 mMounts.push_back( new MountedShape ); 524 } 525 else 526 { 527 // Check if we are switching shapes 528 if ( mMounts[slot]->mShape->getShape() != tsi->getShape() ) 529 { 530 delete mMounts[slot]->mShape; 531 mMounts[slot]->mShape = NULL; 532 mMounts[slot]->mThread.init(); 533 } 534 else 535 { 536 // Keep using the existing shape 537 delete tsi; 538 tsi = mMounts[slot]->mShape; 539 } 540 } 541 542 MountedShape* mount = mMounts[slot]; 543 mount->mShape = tsi; 544 545 if ( dStrEqual( mountType, "Wheel" ) ) 546 mount->mType = MountedShape::Wheel; 547 else if ( dStrEqual( mountType, "Image" ) ) 548 mount->mType = MountedShape::Image; 549 else 550 mount->mType = MountedShape::Object; 551 552 setMountNode( slot, nodeName); 553 554 return true; 555} 556 557void GuiShapeEdPreview::setMountNode(S32 mountSlot, const char* nodeName) 558{ 559 if ( mountSlot < mMounts.size() ) 560 { 561 MountedShape* mount = mMounts[mountSlot]; 562 563 mount->mNode = mModel ? mModel->getShape()->findNode( nodeName ) : -1; 564 mount->mTransform.identity(); 565 566 switch ( mount->mType ) 567 { 568 case MountedShape::Image: 569 { 570 // Mount point is either the node called 'mountPoint' or the origin 571 S32 node = mount->mShape->getShape()->findNode( "mountPoint" ); 572 if ( node != -1 ) 573 { 574 mount->mShape->getShape()->getNodeWorldTransform( node, &mount->mTransform ); 575 mount->mTransform.inverse(); 576 } 577 } 578 break; 579 580 case MountedShape::Wheel: 581 // Rotate shape according to node's x position (left or right) 582 { 583 F32 rotAngle = M_PI_F/2; 584 if ( mount->mNode != -1 ) 585 { 586 MatrixF hubMat; 587 mModel->getShape()->getNodeWorldTransform( mount->mNode, &hubMat ); 588 if ( hubMat.getPosition().x < 0 ) 589 rotAngle = -M_PI_F/2; 590 } 591 mount->mTransform.set( EulerF( 0, 0, rotAngle ) ); 592 } 593 break; 594 595 default: 596 // No mount transform (use origin) 597 break; 598 } 599 } 600} 601 602const char* GuiShapeEdPreview::getMountThreadSequence(S32 mountSlot) const 603{ 604 if ( mountSlot < mMounts.size() ) 605 { 606 MountedShape* mount = mMounts[mountSlot]; 607 return mount->mThread.seqName; 608 } 609 else 610 return ""; 611} 612 613void GuiShapeEdPreview::setMountThreadSequence(S32 mountSlot, const char* seqName) 614{ 615 if ( mountSlot < mMounts.size() ) 616 { 617 MountedShape* mount = mMounts[mountSlot]; 618 setThreadSequence( mount->mThread, mount->mShape, seqName ); 619 } 620} 621 622F32 GuiShapeEdPreview::getMountThreadPos(S32 mountSlot) const 623{ 624 if ( mountSlot < mMounts.size() ) 625 { 626 MountedShape* mount = mMounts[mountSlot]; 627 if ( mount->mThread.key ) 628 return mount->mShape->getPos( mount->mThread.key ); 629 } 630 return 0; 631} 632 633void GuiShapeEdPreview::setMountThreadPos(S32 mountSlot, F32 pos) 634{ 635 if ( mountSlot < mMounts.size() ) 636 { 637 MountedShape* mount = mMounts[mountSlot]; 638 if ( mount->mThread.key ) 639 mount->mShape->setPos( mount->mThread.key, pos ); 640 } 641} 642 643F32 GuiShapeEdPreview::getMountThreadDir(S32 mountSlot) const 644{ 645 if ( mountSlot < mMounts.size() ) 646 { 647 MountedShape* mount = mMounts[mountSlot]; 648 return mount->mThread.direction; 649 } 650 return 0; 651} 652 653void GuiShapeEdPreview::setMountThreadDir(S32 mountSlot, F32 dir) 654{ 655 if ( mountSlot < mMounts.size() ) 656 { 657 MountedShape* mount = mMounts[mountSlot]; 658 mount->mThread.direction = dir; 659 if ( mount->mThread.key ) 660 mount->mShape->setTimeScale( mount->mThread.key, mTimeScale * mount->mThread.direction ); 661 } 662} 663 664void GuiShapeEdPreview::unmountShape(S32 mountSlot) 665{ 666 if ( mountSlot < mMounts.size() ) 667 { 668 delete mMounts[mountSlot]; 669 mMounts.erase( mountSlot ); 670 } 671} 672 673void GuiShapeEdPreview::unmountAll() 674{ 675 for ( S32 i = 0; i < mMounts.size(); i++) 676 delete mMounts[i]; 677 mMounts.clear(); 678} 679 680void GuiShapeEdPreview::refreshShape() 681{ 682 if ( mModel ) 683 { 684 // Nodes or details may have changed => refresh the shape instance 685 mModel->setMaterialList( mModel->mMaterialList ); 686 mModel->initNodeTransforms(); 687 mModel->initMeshObjects(); 688 689 TSShape* shape = mModel->getShape(); 690 691 mProjectedNodes.setSize( shape->nodes.size() ); 692 693 if ( mSelectedObject >= shape->objects.size() ) 694 { 695 mSelectedObject = -1; 696 mSelectedObjDetail = 0; 697 } 698 699 // Re-compute the collision mesh stats 700 mColMeshes = 0; 701 mColPolys = 0; 702 for ( S32 i = 0; i < shape->details.size(); i++ ) 703 { 704 const TSShape::Detail& det = shape->details[i]; 705 const String& detName = shape->getName( det.nameIndex ); 706 if ( ( det.subShapeNum < 0 ) || !detName.startsWith( "collision-" ) ) 707 continue; 708 709 mColPolys += det.polyCount; 710 711 S32 od = det.objectDetailNum; 712 S32 start = shape->subShapeFirstObject[det.subShapeNum]; 713 S32 end = start + shape->subShapeNumObjects[det.subShapeNum]; 714 for ( S32 j = start; j < end; j++ ) 715 { 716 const TSShape::Object &obj = shape->objects[j]; 717 const TSMesh* mesh = ( od < obj.numMeshes ) ? shape->meshes[obj.startMeshIndex + od] : NULL; 718 if ( mesh ) 719 mColMeshes++; 720 } 721 } 722 } 723} 724 725void GuiShapeEdPreview::updateSun() 726{ 727 if ( mFakeSun ) 728 { 729 // Update sun colors 730 mFakeSun->setColor( mSunDiffuseColor ); 731 mFakeSun->setAmbient( mSunAmbientColor ); 732 733 // Determine the new sun direction and position 734 Point3F vec; 735 MatrixF xRot, zRot; 736 xRot.set( EulerF( mDegToRad(mSunRot.x), 0.0f, 0.0f )); 737 zRot.set( EulerF( 0.0f, 0.0f, mDegToRad(mSunRot.z) )); 738 739 zRot.mul( xRot ); 740 zRot.getColumn( 1, &vec ); 741 742 mFakeSun->setDirection( vec ); 743 //mFakeSun->setPosition( vec * -10000.0f ); 744 } 745} 746 747void GuiShapeEdPreview::updateNodeTransforms() 748{ 749 if ( mModel ) 750 mModel->mDirtyFlags[0] |= TSShapeInstance::TransformDirty; 751} 752 753bool GuiShapeEdPreview::getMeshHidden( const char* name ) const 754{ 755 if ( mModel ) 756 { 757 S32 objIndex = mModel->getShape()->findObject( name ); 758 if ( objIndex != -1 ) 759 return mModel->mMeshObjects[objIndex].forceHidden; 760 } 761 return false; 762} 763 764void GuiShapeEdPreview::setMeshHidden( const char* name, bool hidden ) 765{ 766 if ( mModel ) 767 { 768 S32 objIndex = mModel->getShape()->findObject( name ); 769 if ( objIndex != -1 ) 770 mModel->setMeshForceHidden( objIndex, hidden ); 771 } 772} 773 774void GuiShapeEdPreview::setAllMeshesHidden( bool hidden ) 775{ 776 if ( mModel ) 777 { 778 for ( S32 i = 0; i < mModel->mMeshObjects.size(); i++ ) 779 mModel->setMeshForceHidden( i, hidden ); 780 } 781} 782 783void GuiShapeEdPreview::get3DCursor( GuiCursor *&cursor, 784 bool &visible, 785 const Gui3DMouseEvent &event_ ) 786{ 787 cursor = NULL; 788 visible = false; 789 790 GuiCanvas *root = getRoot(); 791 if ( !root ) 792 return; 793 794 S32 currCursor = PlatformCursorController::curArrow; 795 796 if ( root->mCursorChanged == currCursor ) 797 return; 798 799 PlatformWindow *window = root->getPlatformWindow(); 800 PlatformCursorController *controller = window->getCursorController(); 801 802 // We've already changed the cursor, 803 // so set it back before we change it again. 804 if ( root->mCursorChanged != -1 ) 805 controller->popCursor(); 806 807 // Now change the cursor shape 808 controller->pushCursor( currCursor ); 809 root->mCursorChanged = currCursor; 810} 811 812void GuiShapeEdPreview::fitToShape() 813{ 814 if ( !mModel ) 815 return; 816 817 // Determine the shape bounding box given the current camera rotation 818 MatrixF camRotMatrix( smCamMatrix ); 819 camRotMatrix.setPosition( Point3F::Zero ); 820 camRotMatrix.inverse(); 821 822 Box3F bounds; 823 computeSceneBounds( bounds ); 824 mOrbitPos = bounds.getCenter(); 825 826 camRotMatrix.mul( bounds ); 827 828 // Estimate the camera distance to fill the view by comparing the radii 829 // of the box and the viewport 830 F32 len_x = bounds.len_x(); 831 F32 len_z = bounds.len_z(); 832 F32 shapeRadius = mSqrt( len_x*len_x + len_z*len_z ) / 2; 833 F32 viewRadius = 0.45f * getMin( getExtent().x, getExtent().y ); 834 835 // Set camera parameters 836 if ( mDisplayType == DisplayTypePerspective ) 837 { 838 mOrbitDist = ( shapeRadius / viewRadius ) * mSaveWorldToScreenScale.y; 839 } 840 else 841 { 842 mOrthoCamTrans.set( 0, 0, 0 ); 843 mOrthoFOV = shapeRadius * viewRadius / 320; 844 } 845} 846 847void GuiShapeEdPreview::setOrbitPos( const Point3F& pos ) 848{ 849 mOrbitPos = pos; 850} 851 852void GuiShapeEdPreview::exportToCollada( const String& path ) 853{ 854#ifdef TORQUE_COLLADA 855 if ( mModel ) 856 { 857 MatrixF orientation( true ); 858 orientation.setPosition( mModel->getShape()->mBounds.getCenter() ); 859 orientation.inverse(); 860 861 OptimizedPolyList polyList; 862 polyList.setBaseTransform( orientation ); 863 864 mModel->buildPolyList( &polyList, mCurrentDL ); 865 for ( S32 i = 0; i < mMounts.size(); i++ ) 866 { 867 MountedShape* mount = mMounts[i]; 868 869 MatrixF mat( true ); 870 if ( mount->mNode != -1 ) 871 { 872 mat = mModel->mNodeTransforms[ mount->mNode ]; 873 mat *= mount->mTransform; 874 } 875 876 polyList.setTransform( &mat, Point3F::One ); 877 mount->mShape->buildPolyList( &polyList, 0 ); 878 } 879 880 // Use a ColladaUtils function to do the actual export to a Collada file 881 ColladaUtils::exportToCollada( path, polyList ); 882 } 883#endif 884} 885 886//----------------------------------------------------------------------------- 887// Camera control and Node editing 888// - moving the mouse over a node will highlight (but not select) it 889// - left clicking on a node will select it, the gizmo will appear 890// - left clicking on no node will unselect the current node 891// - left dragging the gizmo will translate/rotate the node 892// - middle drag translates the view 893// - right drag rotates the view 894// - mouse wheel zooms the view 895// - holding shift while changing the view speeds them up 896 897void GuiShapeEdPreview::handleMouseDown(const GuiEvent& event, GizmoMode mode) 898{ 899 if (!mActive || !mVisible || !mAwake ) 900 return; 901 902 mouseLock(); 903 mLastMousePos = event.mousePoint; 904 905 if ( mRenderNodes && ( mode == NoneMode ) ) 906 { 907 mGizmoDragID++; 908 make3DMouseEvent( mLastEvent, event ); 909 910 // Check gizmo first 911 mUsingAxisGizmo = false; 912 if ( mSelectedNode != -1 ) 913 { 914 mGizmo->on3DMouseDown( mLastEvent ); 915 if ( mGizmo->getSelection() != Gizmo::None ) 916 { 917 mUsingAxisGizmo = true; 918 return; 919 } 920 } 921 922 // Check if we have clicked on a node 923 S32 selected = collideNode( mLastEvent ); 924 if ( selected != mSelectedNode ) 925 { 926 mSelectedNode = selected; 927 Con::executef( this, "onNodeSelected", Con::getIntArg( mSelectedNode )); 928 } 929 } 930 931 //if ( mode == RotateMode ) 932 // mRenderCameraAxes = true; 933} 934 935void GuiShapeEdPreview::handleMouseUp(const GuiEvent& event, GizmoMode mode) 936{ 937 mouseUnlock(); 938 mUsingAxisGizmo = false; 939 940 if ( mRenderNodes && ( mode == NoneMode ) ) 941 { 942 make3DMouseEvent( mLastEvent, event ); 943 mGizmo->on3DMouseUp( mLastEvent ); 944 } 945 946 //if ( mode == RotateMode ) 947 // mRenderCameraAxes = false; 948} 949 950void GuiShapeEdPreview::handleMouseMove(const GuiEvent& event, GizmoMode mode) 951{ 952 if ( mRenderNodes && ( mode == NoneMode ) ) 953 { 954 make3DMouseEvent( mLastEvent, event ); 955 if ( mSelectedNode != -1 ) 956 { 957 // Check if the mouse is hovering over an axis 958 mGizmo->on3DMouseMove( mLastEvent ); 959 if ( mGizmo->getSelection() != Gizmo::None ) 960 return; 961 } 962 963 // Check if we are over another node 964 mHoverNode = collideNode( mLastEvent ); 965 } 966} 967 968void GuiShapeEdPreview::handleMouseDragged(const GuiEvent& event, GizmoMode mode) 969{ 970 // For non-perspective views, ignore rotation, and let EditTSCtrl handle 971 // translation 972 if ( mDisplayType != DisplayTypePerspective ) 973 { 974 if ( mode == MoveMode ) 975 { 976 Parent::onRightMouseDragged( event ); 977 return; 978 } 979 else if ( mode == RotateMode ) 980 return; 981 } 982 983 Point2F delta( event.mousePoint.x - mLastMousePos.x, event.mousePoint.y - mLastMousePos.y ); 984 mLastMousePos = event.mousePoint; 985 986 // Use shift to increase speed 987 delta.x *= ( event.modifier & SI_SHIFT ) ? 0.05f : 0.01f; 988 delta.y *= ( event.modifier & SI_SHIFT ) ? 0.05f : 0.01f; 989 990 if ( mode == NoneMode ) 991 { 992 if ( mEditingSun ) 993 { 994 mSunRot.x += mRadToDeg( delta.y ); 995 mSunRot.z += mRadToDeg( delta.x ); 996 updateSun(); 997 } 998 else if ( mRenderNodes ) 999 { 1000 make3DMouseEvent( mLastEvent, event ); 1001 1002 if ( mUsingAxisGizmo ) 1003 { 1004 // Use gizmo to modify the transform of the selected node 1005 mGizmo->on3DMouseDragged( mLastEvent ); 1006 switch ( mGizmoProfile->mode ) 1007 { 1008 case MoveMode: 1009 // Update node transform 1010 if ( mSelectedNode != -1 ) 1011 { 1012 Point3F pos = mModel->mNodeTransforms[mSelectedNode].getPosition() + mGizmo->getOffset(); 1013 mModel->mNodeTransforms[mSelectedNode].setPosition( pos ); 1014 } 1015 break; 1016 1017 case RotateMode: 1018 // Update node transform 1019 if ( mSelectedNode != -1 ) 1020 { 1021 EulerF rot = mGizmo->getDeltaRot(); 1022 mModel->mNodeTransforms[mSelectedNode].mul( MatrixF( rot ) ); 1023 } 1024 break; 1025 default: 1026 break; 1027 } 1028 1029 // Notify the change in node transform 1030 const char* name = mModel->getShape()->getNodeName(mSelectedNode).c_str(); 1031 const Point3F pos = mModel->mNodeTransforms[mSelectedNode].getPosition(); 1032 AngAxisF aa(mModel->mNodeTransforms[mSelectedNode]); 1033 char buffer[256]; 1034 dSprintf(buffer, sizeof(buffer), "%g %g %g %g %g %g %g", 1035 pos.x, pos.y, pos.z, aa.axis.x, aa.axis.y, aa.axis.z, aa.angle); 1036 1037 Con::executef(this, "onEditNodeTransform", name, buffer, Con::getIntArg(mGizmoDragID)); 1038 } 1039 } 1040 } 1041 else 1042 { 1043 switch ( mode ) 1044 { 1045 case MoveMode: 1046 { 1047 VectorF offset(-delta.x, 0, delta.y ); 1048 smCamMatrix.mulV( offset ); 1049 mOrbitPos += offset * mMoveSpeed; 1050 } 1051 break; 1052 1053 case RotateMode: 1054 mCameraRot.x += delta.y; 1055 mCameraRot.z += delta.x; 1056 break; 1057 1058 default: 1059 break; 1060 } 1061 } 1062} 1063 1064void GuiShapeEdPreview::on3DMouseWheelUp(const Gui3DMouseEvent& event) 1065{ 1066 if ( mDisplayType == DisplayTypePerspective ) 1067 { 1068 // Use shift and ctrl to increase speed 1069 F32 mod = ( event.modifier & SI_SHIFT ) ? ( ( event.modifier & SI_CTRL ) ? 4.0 : 1.0 ) : 0.25f; 1070 mOrbitDist -= mFabs(event.fval) * mZoomSpeed * mod; 1071 } 1072} 1073 1074void GuiShapeEdPreview::on3DMouseWheelDown(const Gui3DMouseEvent& event) 1075{ 1076 if ( mDisplayType == DisplayTypePerspective ) 1077 { 1078 // Use shift and ctrl to increase speed 1079 F32 mod = ( event.modifier & SI_SHIFT ) ? ( ( event.modifier & SI_CTRL ) ? 4.0 : 1.0 ) : 0.25f; 1080 mOrbitDist += mFabs(event.fval) * mZoomSpeed * mod; 1081 } 1082} 1083 1084//----------------------------------------------------------------------------- 1085// NODE PICKING 1086void GuiShapeEdPreview::updateProjectedNodePoints() 1087{ 1088 if ( mModel ) 1089 { 1090 // Project the 3D node position to get the 2D screen coordinates 1091 for ( S32 i = 0; i < mModel->mNodeTransforms.size(); i++) 1092 project( mModel->mNodeTransforms[i].getPosition(), &mProjectedNodes[i] ); 1093 } 1094} 1095 1096S32 GuiShapeEdPreview::collideNode(const Gui3DMouseEvent& event) const 1097{ 1098 // Check if the given position is inside the screen rectangle of 1099 // any shape node 1100 S32 nodeIndex = -1; 1101 F32 minZ = 0; 1102 for ( S32 i = 0; i < mProjectedNodes.size(); i++) 1103 { 1104 const Point3F& pt = mProjectedNodes[i]; 1105 if ( pt.z > 1.0f ) 1106 continue; 1107 1108 RectI rect( pt.x - sNodeRectSize/2, pt.y - sNodeRectSize/2, sNodeRectSize, sNodeRectSize ); 1109 if ( rect.pointInRect( event.mousePoint ) ) 1110 { 1111 if ( ( nodeIndex == -1 ) || ( pt.z < minZ ) ) 1112 { 1113 nodeIndex = i; 1114 minZ = pt.z; 1115 } 1116 } 1117 } 1118 1119 return nodeIndex; 1120} 1121 1122//----------------------------------------------------------------------------- 1123// RENDERING 1124bool GuiShapeEdPreview::getCameraTransform(MatrixF* cameraMatrix) 1125{ 1126 // Adjust the camera so that we are still facing the model 1127 if ( mDisplayType == DisplayTypePerspective ) 1128 { 1129 Point3F vec; 1130 MatrixF xRot, zRot; 1131 xRot.set( EulerF( mCameraRot.x, 0.0f, 0.0f )); 1132 zRot.set( EulerF( 0.0f, 0.0f, mCameraRot.z )); 1133 1134 cameraMatrix->mul( zRot, xRot ); 1135 cameraMatrix->getColumn( 1, &vec ); 1136 cameraMatrix->setColumn( 3, mOrbitPos - vec*mOrbitDist ); 1137 } 1138 else 1139 { 1140 cameraMatrix->identity(); 1141 if ( mModel ) 1142 { 1143 Point3F camPos = mModel->getShape()->mBounds.getCenter(); 1144 F32 offset = mModel->getShape()->mBounds.len(); 1145 1146 switch (mDisplayType) 1147 { 1148 case DisplayTypeTop: camPos.z += offset; break; 1149 case DisplayTypeBottom: camPos.z -= offset; break; 1150 case DisplayTypeFront: camPos.y += offset; break; 1151 case DisplayTypeBack: camPos.y -= offset; break; 1152 case DisplayTypeRight: camPos.x += offset; break; 1153 case DisplayTypeLeft: camPos.x -= offset; break; 1154 default: 1155 break; 1156 } 1157 1158 cameraMatrix->setColumn( 3, camPos ); 1159 } 1160 } 1161 1162 return true; 1163} 1164 1165void GuiShapeEdPreview::computeSceneBounds(Box3F& bounds) 1166{ 1167 if ( mModel ) 1168 mModel->computeBounds( mCurrentDL, bounds ); 1169 1170 if (bounds.getExtents().x < POINT_EPSILON || bounds.getExtents().y < POINT_EPSILON || bounds.getExtents().z < POINT_EPSILON) 1171 { 1172 bounds.set(Point3F::Zero); 1173 1174 //We probably don't have any actual meshes in this model, so compute using the bones if we have them 1175 for (S32 i = 0; i < mModel->getShape()->nodes.size(); i++) 1176 { 1177 Point3F nodePos = mModel->mNodeTransforms[i].getPosition(); 1178 1179 bounds.extend(nodePos); 1180 } 1181 } 1182} 1183 1184void GuiShapeEdPreview::updateDetailLevel(const SceneRenderState* state) 1185{ 1186 // Make sure current detail is valid 1187 if ( !mModel->getShape()->details.size() ) 1188 return; 1189 1190 if ( mModel->getCurrentDetail() >= mModel->getShape()->details.size() ) 1191 setCurrentDetail( mModel->getShape()->details.size() - 1 ); 1192 1193 // Convert between FOV and distance so zoom is consistent between Perspective 1194 // and Orthographic views (conversion factor found by trial and error) 1195 const F32 fov2dist = 1.3f; 1196 if ( mDisplayType == DisplayTypePerspective ) 1197 mOrthoFOV = mOrbitDist / fov2dist; 1198 else 1199 mOrbitDist = mOrthoFOV * fov2dist; 1200 1201 // Use fixed distance in orthographic view (value found by trial + error) 1202 F32 dist = ( mDisplayType == DisplayTypePerspective ) ? mOrbitDist : 0.1f; 1203 1204 // Select the appropriate detail level, and update the detail stats 1205 S32 currentDetail = mModel->getCurrentDetail(); 1206 mModel->setDetailFromDistance( state, dist ); // need to call this to update smLastPixelSize 1207 if ( mFixedDetail ) 1208 setCurrentDetail( currentDetail ); 1209 1210 if ( mModel->getCurrentDetail() < 0 ) 1211 setCurrentDetail( 0 ); 1212 1213 currentDetail = mModel->getCurrentDetail(); 1214 const TSShape::Detail& det = mModel->getShape()->details[ currentDetail ]; 1215 1216 mDetailPolys = det.polyCount; 1217 mDetailSize = det.size; 1218 mPixelSize = TSShapeInstance::smLastPixelSize; 1219 1220 mNumMaterials = 0; 1221 mNumDrawCalls = 0; 1222 mNumBones = 0; 1223 mNumWeights = 0; 1224 1225 if ( det.subShapeNum < 0 ) 1226 { 1227 mNumMaterials = 1; 1228 mNumDrawCalls = 1; 1229 } 1230 else 1231 { 1232 Vector<U32> usedMaterials; 1233 1234 S32 start = mModel->getShape()->subShapeFirstObject[det.subShapeNum]; 1235 S32 end = start + mModel->getShape()->subShapeNumObjects[det.subShapeNum]; 1236 1237 for ( S32 iObj = start; iObj < end; iObj++ ) 1238 { 1239 const TSShape::Object& obj = mModel->getShape()->objects[iObj]; 1240 1241 if ( obj.numMeshes <= currentDetail ) 1242 continue; 1243 1244 const TSMesh* mesh = mModel->getShape()->meshes[ obj.startMeshIndex + currentDetail ]; 1245 if ( !mesh ) 1246 continue; 1247 1248 // Count the number of draw calls and materials 1249 mNumDrawCalls += mesh->mPrimitives.size(); 1250 for ( S32 iPrim = 0; iPrim < mesh->mPrimitives.size(); iPrim++ ) 1251 usedMaterials.push_back_unique( mesh->mPrimitives[iPrim].matIndex & TSDrawPrimitive::MaterialMask ); 1252 1253 // For skinned meshes, count the number of bones and weights 1254 if ( mesh->getMeshType() == TSMesh::SkinMeshType ) 1255 { 1256 const TSSkinMesh* skin = dynamic_cast<const TSSkinMesh*>(mesh); 1257 mNumBones += skin->batchData.initialTransforms.size(); 1258 mNumWeights += skin->weight.size(); 1259 } 1260 } 1261 1262 mNumMaterials = usedMaterials.size(); 1263 } 1264 1265 // Detect changes in detail level 1266 if ( mCurrentDL != currentDetail ) 1267 { 1268 mCurrentDL = currentDetail; 1269 Con::executef( this, "onDetailChanged"); 1270 } 1271} 1272 1273void GuiShapeEdPreview::updateThreads(F32 delta) 1274{ 1275 // Advance time on all threads 1276 for ( S32 i = 0; i < mThreads.size(); i++ ) 1277 { 1278 Thread& thread = mThreads[i]; 1279 if ( !thread.key || !thread.direction ) 1280 continue; 1281 1282 // Make sure thread priority matches sequence priority (which may have changed) 1283 mModel->setPriority( thread.key, mModel->getShape()->sequences[mModel->getSequence( thread.key )].priority ); 1284 1285 // Handle ping-pong 1286 if ( thread.pingpong && !mModel->isInTransition( thread.key ) ) 1287 { 1288 // Determine next position, then adjust if needed 1289 F32 threadPos = mModel->getPos( thread.key ); 1290 F32 nextPos = threadPos + ( mModel->getTimeScale( thread.key ) * delta / mModel->getDuration( thread.key ) ); 1291 1292 if ( nextPos < 0 ) 1293 { 1294 // Reflect position and swap playback direction 1295 nextPos = -nextPos; 1296 mModel->setTimeScale( thread.key, -mModel->getTimeScale( thread.key ) ); 1297 mModel->setPos( thread.key, nextPos ); 1298 } 1299 else if ( nextPos > 1.0f ) 1300 { 1301 // Reflect position and swap playback direction 1302 nextPos = 2.0f - nextPos; 1303 mModel->setTimeScale( thread.key, -mModel->getTimeScale( thread.key ) ); 1304 mModel->setPos( thread.key, nextPos ); 1305 } 1306 else 1307 { 1308 // Advance time normally 1309 mModel->advanceTime( delta, thread.key ); 1310 } 1311 } 1312 else 1313 { 1314 // Advance time normally 1315 mModel->advanceTime( delta, thread.key ); 1316 } 1317 1318 // Invoke script callback if active thread position has changed 1319 if ( i == mActiveThread ) 1320 { 1321 F32 threadPos = mModel->getPos( thread.key ); 1322 bool inTransition = mModel->isInTransition( thread.key ); 1323 onThreadPosChanged_callback( threadPos, inTransition ); 1324 } 1325 } 1326 1327 // Mark threads as dirty so they will be re-sorted, in case the user changed 1328 // sequence priority or blend flags 1329 mModel->setDirty( TSShapeInstance::ThreadDirty ); 1330 1331 // Advance time on all mounted shape threads 1332 for ( S32 i = 0; i < mMounts.size(); i++ ) 1333 { 1334 MountedShape* mount = mMounts[i]; 1335 if ( mount->mThread.key ) 1336 mount->mShape->advanceTime( delta, mount->mThread.key ); 1337 } 1338} 1339 1340void GuiShapeEdPreview::renderWorld(const RectI &updateRect) 1341{ 1342 if ( !mModel ) 1343 return; 1344 1345 mSaveFrustum = GFX->getFrustum(); 1346 mSaveFrustum.setFarDist( 100000.0f ); 1347 GFX->setFrustum( mSaveFrustum ); 1348 mSaveFrustum.setTransform( smCamMatrix ); 1349 1350 mSaveProjection = GFX->getProjectionMatrix(); 1351 mSaveWorldToScreenScale = GFX->getWorldToScreenScale(); 1352 1353 FogData savedFogData = gClientSceneGraph->getFogData(); 1354 gClientSceneGraph->setFogData( FogData() ); // no fog in preview window 1355 1356 SceneRenderState state 1357 ( 1358 gClientSceneGraph, 1359 SPT_Diffuse, 1360 SceneCameraState( GFX->getViewport(), mSaveFrustum, 1361 GFX->getWorldMatrix(), GFX->getProjectionMatrix() ) 1362 ); 1363 1364 // Set up pass transforms 1365 RenderPassManager *renderPass = state.getRenderPass(); 1366 renderPass->assignSharedXform( RenderPassManager::View, GFX->getWorldMatrix() ); 1367 renderPass->assignSharedXform( RenderPassManager::Projection, GFX->getProjectionMatrix() ); 1368 1369 // Set up our TS render state here. 1370 TSRenderState rdata; 1371 rdata.setSceneState(&state); 1372 1373 LIGHTMGR->unregisterAllLights(); 1374 LIGHTMGR->setSpecialLight( LightManager::slSunLightType, mFakeSun ); 1375 1376 // We might have some forward lit materials 1377 // so pass down a query to gather lights. 1378 LightQuery query; 1379 query.init( SphereF( Point3F::Zero, 1 ) ); 1380 rdata.setLightQuery( &query ); 1381 1382 // Update projected node points (for mouse picking) 1383 updateProjectedNodePoints(); 1384 1385 // Determine time elapsed since last render (for animation playback) 1386 S32 time = Platform::getVirtualMilliseconds(); 1387 S32 dt = time - mLastRenderTime; 1388 mLastRenderTime = time; 1389 1390 if ( mModel ) 1391 { 1392 updateDetailLevel( &state ); 1393 1394 // Render the grid 1395 renderGrid(); 1396 1397 // Animate the model 1398 updateThreads( (F32)dt / 1000.f ); 1399 mModel->animate(); 1400 1401 // Render the shape 1402 GFX->setStateBlock( mDefaultGuiSB ); 1403 1404 if ( mRenderGhost ) 1405 rdata.setFadeOverride( 0.5f ); 1406 1407 GFX->pushWorldMatrix(); 1408 GFX->setWorldMatrix( MatrixF::Identity ); 1409 1410 mModel->render( rdata ); 1411 1412 // Render mounted objects 1413 if ( mRenderMounts ) 1414 { 1415 for ( S32 i = 0; i < mMounts.size(); i++ ) 1416 { 1417 MountedShape* mount = mMounts[i]; 1418 1419 GFX->pushWorldMatrix(); 1420 1421 if ( mount->mNode != -1 ) 1422 { 1423 GFX->multWorld( mModel->mNodeTransforms[ mount->mNode ] ); 1424 GFX->multWorld( mount->mTransform ); 1425 } 1426 1427 mount->mShape->animate(); 1428 mount->mShape->render( rdata ); 1429 1430 GFX->popWorldMatrix(); 1431 } 1432 } 1433 1434 GFX->popWorldMatrix(); 1435 1436 renderPass->renderPass( &state ); 1437 1438 // @todo: Model and other elements (bounds, grid etc) use different 1439 // zBuffers, so at the moment, draw order determines what is on top 1440 1441 // Render collision volumes 1442 renderCollisionMeshes(); 1443 1444 // Render the shape bounding box 1445 if ( mRenderBounds ) 1446 { 1447 Point3F boxSize = mModel->getShape()->mBounds.maxExtents - mModel->getShape()->mBounds.minExtents; 1448 1449 GFXStateBlockDesc desc; 1450 desc.fillMode = GFXFillWireframe; 1451 GFX->getDrawUtil()->drawCube( desc, boxSize, mModel->getShape()->center, ColorI::WHITE ); 1452 } 1453 1454 // Render the selected object bounding box 1455 if ( mRenderObjBox && ( mSelectedObject != -1 ) ) 1456 { 1457 const TSShape::Object& obj = mModel->getShape()->objects[mSelectedObject]; 1458 const TSMesh* mesh = ( mCurrentDL < obj.numMeshes ) ? mModel->getShape()->meshes[obj.startMeshIndex + mSelectedObjDetail] : NULL; 1459 if ( mesh ) 1460 { 1461 GFX->pushWorldMatrix(); 1462 if ( obj.nodeIndex != -1 ) 1463 GFX->multWorld( mModel->mNodeTransforms[ obj.nodeIndex ] ); 1464 1465 const Box3F& bounds = mesh->getBounds(); 1466 GFXStateBlockDesc desc; 1467 desc.fillMode = GFXFillWireframe; 1468 GFX->getDrawUtil()->drawCube( desc, bounds.getExtents(), bounds.getCenter(), ColorI::RED ); 1469 1470 GFX->popWorldMatrix(); 1471 } 1472 } 1473 1474 // Render the sun direction if currently editing it 1475 renderSunDirection(); 1476 1477 // render the nodes in the model 1478 renderNodes(); 1479 1480 // use the gizmo to render the camera axes 1481 if ( mRenderCameraAxes ) 1482 { 1483 GizmoMode savedMode = mGizmoProfile->mode; 1484 mGizmoProfile->mode = MoveMode; 1485 1486 Point3F pos; 1487 Point2I screenCenter( updateRect.point + updateRect.extent/2 ); 1488 unproject( Point3F( screenCenter.x, screenCenter.y, 0.5 ), &pos ); 1489 1490 mGizmo->set( MatrixF::Identity, pos, Point3F::One); 1491 mGizmo->renderGizmo( smCamMatrix ); 1492 1493 mGizmoProfile->mode = savedMode; 1494 } 1495 } 1496 1497 gClientSceneGraph->setFogData( savedFogData ); // restore fog setting 1498} 1499 1500void GuiShapeEdPreview::renderGui(Point2I offset, const RectI& updateRect) 1501{ 1502 // Render the 2D stuff here 1503 1504 // Render the names of the hovered and selected nodes 1505 if ( mModel ) 1506 { 1507 if ( mRenderNodes && mHoverNode != -1 ) 1508 renderNodeName( mHoverNode, LinearColorF::WHITE ); 1509 if ( mSelectedNode != -1 ) 1510 renderNodeName( mSelectedNode, LinearColorF::WHITE ); 1511 } 1512} 1513 1514void GuiShapeEdPreview::renderGrid() 1515{ 1516 if ( mRenderGridPlane ) 1517 { 1518 // Use EditTSCtrl to render the grid in non-perspective views 1519 if ( mDisplayType != DisplayTypePerspective ) 1520 { 1521 Parent::renderGrid(); 1522 return; 1523 } 1524 1525 // Round grid dimension up to a multiple of the minor ticks 1526 Point2I dim(mGridDimension.x + mGridPlaneMinorTicks, mGridDimension.y + mGridPlaneMinorTicks); 1527 dim /= ( mGridPlaneMinorTicks + 1 ); 1528 dim *= ( mGridPlaneMinorTicks + 1 ); 1529 1530 Point2F minorStep( mGridPlaneSize, mGridPlaneSize ); 1531 Point2F size( minorStep.x * dim.x, minorStep.y * dim.y ); 1532 Point2F majorStep( minorStep * ( mGridPlaneMinorTicks + 1 ) ); 1533 1534 GFXStateBlockDesc desc; 1535 desc.setBlend( true ); 1536 desc.setZReadWrite( true, false ); 1537 1538 GFX->getDrawUtil()->drawPlaneGrid( desc, Point3F::Zero, size, minorStep, mGridPlaneMinorTickColor ); 1539 GFX->getDrawUtil()->drawPlaneGrid( desc, Point3F::Zero, size, majorStep, mGridPlaneColor ); 1540 } 1541} 1542 1543void GuiShapeEdPreview::renderSunDirection() const 1544{ 1545 if ( mEditingSun ) 1546 { 1547 // Render four arrows aiming in the direction of the sun's light 1548 ColorI color = LinearColorF( mFakeSun->getColor()).toColorI(); 1549 F32 length = mModel->getShape()->mBounds.len() * 0.8f; 1550 1551 // Get the sun's vectors 1552 Point3F fwd = mFakeSun->getTransform().getForwardVector(); 1553 Point3F up = mFakeSun->getTransform().getUpVector() * length / 8; 1554 Point3F right = mFakeSun->getTransform().getRightVector() * length / 8; 1555 1556 // Calculate the start and end points of the first arrow (bottom left) 1557 Point3F start = mModel->getShape()->center - fwd * length - up/2 - right/2; 1558 Point3F end = mModel->getShape()->center - fwd * length / 3 - up/2 - right/2; 1559 1560 GFXStateBlockDesc desc; 1561 desc.setZReadWrite( true, true ); 1562 1563 GFXDrawUtil* drawUtil = GFX->getDrawUtil(); 1564 1565 drawUtil->drawArrow( desc, start, end, color ); 1566 drawUtil->drawArrow( desc, start + up, end + up, color ); 1567 drawUtil->drawArrow( desc, start + right, end + right, color ); 1568 drawUtil->drawArrow( desc, start + up + right, end + up + right, color ); 1569 } 1570} 1571 1572void GuiShapeEdPreview::renderNodes() const 1573{ 1574 if ( mRenderNodes ) 1575 { 1576 // Render links between nodes 1577 GFXStateBlockDesc desc; 1578 desc.setZReadWrite( false, true ); 1579 desc.setCullMode( GFXCullNone ); 1580 GFX->setStateBlockByDesc( desc ); 1581 1582 PrimBuild::color( ColorI::WHITE ); 1583 PrimBuild::begin( GFXLineList, mModel->getShape()->nodes.size() * 2 ); 1584 for ( S32 i = 0; i < mModel->getShape()->nodes.size(); i++) 1585 { 1586 const TSShape::Node& node = mModel->getShape()->nodes[i]; 1587 if (node.parentIndex >= 0) 1588 { 1589 Point3F start(mModel->mNodeTransforms[i].getPosition()); 1590 Point3F end(mModel->mNodeTransforms[node.parentIndex].getPosition()); 1591 1592 PrimBuild::vertex3f( start.x, start.y, start.z ); 1593 PrimBuild::vertex3f( end.x, end.y, end.z ); 1594 } 1595 } 1596 PrimBuild::end(); 1597 1598 // Render the node axes 1599 for ( S32 i = 0; i < mModel->getShape()->nodes.size(); i++) 1600 { 1601 // Render the selected and hover nodes last (so they are on top) 1602 if ( ( i == mSelectedNode ) || ( i == mHoverNode ) ) 1603 continue; 1604 1605 renderNodeAxes( i, LinearColorF::WHITE ); 1606 } 1607 1608 // Render the hovered node 1609 if ( mHoverNode != -1 ) 1610 renderNodeAxes( mHoverNode, LinearColorF::GREEN ); 1611 } 1612 1613 // Render the selected node (even if mRenderNodes is false) 1614 if ( mSelectedNode != -1 ) 1615 { 1616 renderNodeAxes( mSelectedNode, LinearColorF::GREEN ); 1617 1618 const MatrixF& nodeMat = mModel->mNodeTransforms[mSelectedNode]; 1619 mGizmo->set( nodeMat, nodeMat.getPosition(), Point3F::One); 1620 mGizmo->renderGizmo( smCamMatrix ); 1621 } 1622} 1623 1624void GuiShapeEdPreview::renderNodeAxes(S32 index, const LinearColorF& nodeColor) const 1625{ 1626 if(mModel->mNodeTransforms.size() <= index || index < 0) 1627 return; 1628 const Point3F xAxis( 1.0f, 0.15f, 0.15f ); 1629 const Point3F yAxis( 0.15f, 1.0f, 0.15f ); 1630 const Point3F zAxis( 0.15f, 0.15f, 1.0f ); 1631 1632 GFXStateBlockDesc desc; 1633 desc.setZReadWrite( false, true ); 1634 desc.setCullMode( GFXCullNone ); 1635 1636 // Render nodes the same size regardless of zoom 1637 F32 scale = mOrbitDist / 60; 1638 1639 GFX->pushWorldMatrix(); 1640 GFX->multWorld( mModel->mNodeTransforms[index] ); 1641 const ColorI color = LinearColorF(nodeColor).toColorI(); 1642 GFX->getDrawUtil()->drawCube( desc, xAxis * scale, Point3F::Zero, color ); 1643 GFX->getDrawUtil()->drawCube( desc, yAxis * scale, Point3F::Zero, color ); 1644 GFX->getDrawUtil()->drawCube( desc, zAxis * scale, Point3F::Zero, color ); 1645 1646 GFX->popWorldMatrix(); 1647} 1648 1649void GuiShapeEdPreview::renderNodeName(S32 index, const LinearColorF& textColor) const 1650{ 1651 if(index < 0 || index >= mModel->getShape()->nodes.size() || index >= mProjectedNodes.size()) 1652 return; 1653 const TSShape::Node& node = mModel->getShape()->nodes[index]; 1654 const String& nodeName = mModel->getShape()->getName( node.nameIndex ); 1655 1656 Point2I pos( mProjectedNodes[index].x, mProjectedNodes[index].y + sNodeRectSize + 6 ); 1657 1658 GFX->getDrawUtil()->setBitmapModulation( LinearColorF(textColor).toColorI()); 1659 GFX->getDrawUtil()->drawText( mProfile->mFont, pos, nodeName.c_str() ); 1660} 1661 1662void GuiShapeEdPreview::renderCollisionMeshes() const 1663{ 1664 if ( mRenderColMeshes ) 1665 { 1666 ConcretePolyList polylist; 1667 polylist.setTransform( &MatrixF::Identity, Point3F::One ); 1668 for ( S32 iDet = 0; iDet < mModel->getShape()->details.size(); iDet++ ) 1669 { 1670 const TSShape::Detail& det = mModel->getShape()->details[iDet]; 1671 const String& detName = mModel->getShape()->getName( det.nameIndex ); 1672 1673 // Ignore non-collision details 1674 if ( detName.startsWith( "Collision-" ) ) 1675 mModel->buildPolyList( &polylist, iDet ); 1676 } 1677 1678 polylist.render(); 1679 } 1680} 1681 1682//----------------------------------------------------------------------------- 1683// Console methods (GuiShapeEdPreview) 1684//----------------------------------------------------------------------------- 1685 1686DefineEngineMethod( GuiShapeEdPreview, setOrbitPos, void, ( Point3F pos ),, 1687 "Set the camera orbit position\n\n" 1688 "@param pos Position in the form \"x y z\"\n" ) 1689{ 1690 object->setOrbitPos( pos ); 1691} 1692 1693DefineEngineMethod( GuiShapeEdPreview, setModel, bool, ( const char* shapePath ),, 1694 "Sets the model to be displayed in this control\n\n" 1695 "@param shapeName Name of the model to display.\n" 1696 "@return True if the model was loaded successfully, false otherwise.\n" ) 1697{ 1698 return object->setObjectModel( shapePath ); 1699} 1700 1701DefineEngineMethod( GuiShapeEdPreview, fitToShape, void, (),, 1702 "Adjust the camera position and zoom to fit the shape within the view.\n\n" ) 1703{ 1704 object->fitToShape(); 1705} 1706 1707DefineEngineMethod( GuiShapeEdPreview, refreshShape, void, (),, 1708 "Refresh the shape (used when the shape meshes or nodes have been added or removed)\n\n" ) 1709{ 1710 object->refreshShape(); 1711} 1712 1713DefineEngineMethod( GuiShapeEdPreview, updateNodeTransforms, void, (),, 1714 "Refresh the shape node transforms (used when a node transform has been modified externally)\n\n" ) 1715{ 1716 object->updateNodeTransforms(); 1717} 1718 1719DefineEngineMethod( GuiShapeEdPreview, computeShapeBounds, Box3F, (),, 1720 "Compute the bounding box of the shape using the current detail and node transforms\n\n" 1721 "@return the bounding box \"min.x min.y min.z max.x max.y max.z\"" ) 1722{ 1723 Box3F bounds; 1724 object->computeSceneBounds(bounds); 1725 return bounds; 1726} 1727 1728DefineEngineMethod( GuiShapeEdPreview, getMeshHidden, bool, ( const char* name ),, 1729 "Return whether the named object is currently hidden\n\n" ) 1730{ 1731 return object->getMeshHidden( name ); 1732} 1733 1734DefineEngineMethod( GuiShapeEdPreview, setMeshHidden, void, ( const char* name, bool hidden ),, 1735 "Show or hide the named object in the shape\n\n" ) 1736{ 1737 object->setMeshHidden( name, hidden ); 1738} 1739 1740DefineEngineMethod( GuiShapeEdPreview, setAllMeshesHidden, void, ( bool hidden ),, 1741 "Show or hide all objects in the shape\n\n" ) 1742{ 1743 object->setAllMeshesHidden( hidden ); 1744} 1745 1746DefineEngineMethod( GuiShapeEdPreview, exportToCollada, void, ( const char* path ),, 1747 "Export the current shape and all mounted objects to COLLADA (.dae).\n" 1748 "Note that animation is not exported, and all geometry is combined into a " 1749 "single mesh.\n\n" 1750 "@param path Destination filename\n" ) 1751{ 1752 object->exportToCollada( path ); 1753} 1754 1755//----------------------------------------------------------------------------- 1756// THREADS 1757DefineEngineMethod( GuiShapeEdPreview, addThread, void, (),, 1758 "Add a new thread (initially without any sequence set)\n\n" ) 1759{ 1760 object->addThread(); 1761} 1762 1763DefineEngineMethod( GuiShapeEdPreview, removeThread, void, ( S32 slot ),, 1764 "Removes the specifed thread\n\n" 1765 "@param slot index of the thread to remove\n" ) 1766{ 1767 object->removeThread( slot ); 1768} 1769 1770DefineEngineMethod( GuiShapeEdPreview, getThreadCount, S32, (),, 1771 "Get the number of threads\n\n" 1772 "@return the number of threads\n" ) 1773{ 1774 return object->getThreadCount(); 1775} 1776 1777DefineEngineMethod( GuiShapeEdPreview, setTimeScale, void, ( F32 scale ),, 1778 "Set the time scale of all threads\n\n" 1779 "@param scale new time scale value\n" ) 1780{ 1781 object->setTimeScale( scale ); 1782} 1783 1784DefineEngineMethod( GuiShapeEdPreview, setThreadSequence, void, ( const char* name, F32 duration, F32 pos, bool play ), ( 0, 0, false ), 1785 "Sets the sequence to play for the active thread.\n\n" 1786 "@param name name of the sequence to play\n" 1787 "@param duration transition duration (0 for no transition)\n" 1788 "@param pos position in the new sequence to transition to\n" 1789 "@param play if true, the new sequence will play during the transition\n" ) 1790{ 1791 object->setActiveThreadSequence( name, duration, pos, play ); 1792} 1793 1794DefineEngineMethod( GuiShapeEdPreview, getThreadSequence, const char*, (),, 1795 "Get the name of the sequence assigned to the active thread" ) 1796{ 1797 return object->getThreadSequence(); 1798} 1799 1800DefineEngineMethod( GuiShapeEdPreview, refreshThreadSequences, void, (),, 1801 "Refreshes thread sequences (in case of removed/renamed sequences" ) 1802{ 1803 object->refreshThreadSequences(); 1804} 1805 1806//----------------------------------------------------------------------------- 1807// Mounting 1808DefineEngineMethod( GuiShapeEdPreview, mountShape, bool, ( const char* shapePath, const char* nodeName, const char* type, S32 slot ),, 1809 "Mount a shape onto the main shape at the specified node\n\n" 1810 "@param shapePath path to the shape to mount\n" 1811 "@param nodeName name of the node on the main shape to mount to\n" 1812 "@param type type of mounting to use (Object, Image or Wheel)\n" 1813 "@param slot mount slot\n" ) 1814{ 1815 return object->mountShape( shapePath, nodeName, type, slot ); 1816} 1817 1818DefineEngineMethod( GuiShapeEdPreview, setMountNode, void, ( S32 slot, const char* nodeName ),, 1819 "Set the node a shape is mounted to.\n\n" 1820 "@param slot mounted shape slot\n" 1821 "@param nodename name of the node to mount to\n" ) 1822{ 1823 object->setMountNode( slot, nodeName ); 1824} 1825 1826DefineEngineMethod( GuiShapeEdPreview, getMountThreadSequence, const char*, ( S32 slot ),, 1827 "Get the name of the sequence playing on this mounted shape\n" 1828 "@param slot mounted shape slot\n" 1829 "@return name of the sequence (if any)\n" ) 1830{ 1831 return object->getMountThreadSequence( slot ); 1832} 1833 1834DefineEngineMethod( GuiShapeEdPreview, setMountThreadSequence, void, ( S32 slot, const char* name ),, 1835 "Set the sequence to play for the shape mounted in the specified slot\n" 1836 "@param slot mounted shape slot\n" 1837 "@param name name of the sequence to play\n" ) 1838{ 1839 object->setMountThreadSequence( slot, name ); 1840} 1841 1842DefineEngineMethod( GuiShapeEdPreview, getMountThreadPos, F32, ( S32 slot ),, 1843 "Get the playback position of the sequence playing on this mounted shape\n" 1844 "@param slot mounted shape slot\n" 1845 "@return playback position of the sequence (0-1)\n" ) 1846{ 1847 return object->getMountThreadPos( slot ); 1848} 1849 1850DefineEngineMethod( GuiShapeEdPreview, setMountThreadPos, void, ( S32 slot, F32 pos ),, 1851 "Set the sequence position of the shape mounted in the specified slot\n" 1852 "@param slot mounted shape slot\n" 1853 "@param pos sequence position (0-1)\n" ) 1854{ 1855 object->setMountThreadPos( slot, pos ); 1856} 1857 1858DefineEngineMethod( GuiShapeEdPreview, getMountThreadDir, F32, ( S32 slot ),, 1859 "Get the playback direction of the sequence playing on this mounted shape\n" 1860 "@param slot mounted shape slot\n" 1861 "@return direction of the sequence (-1=reverse, 0=paused, 1=forward)\n" ) 1862{ 1863 return object->getMountThreadDir( slot ); 1864} 1865 1866DefineEngineMethod( GuiShapeEdPreview, setMountThreadDir, void, ( S32 slot, F32 dir ),, 1867 "Set the playback direction of the shape mounted in the specified slot\n" 1868 "@param slot mounted shape slot\n" 1869 "@param dir playback direction (-1=backwards, 0=paused, 1=forwards)\n" ) 1870{ 1871 object->setMountThreadDir( slot, dir ); 1872} 1873 1874DefineEngineMethod( GuiShapeEdPreview, unmountShape, void, ( S32 slot ),, 1875 "Unmount the shape in the specified slot\n" 1876 "@param slot mounted shape slot\n" ) 1877{ 1878 return object->unmountShape( slot ); 1879} 1880 1881DefineEngineMethod( GuiShapeEdPreview, unmountAll, void, (),, 1882 "Unmount all shapes\n" ) 1883{ 1884 return object->unmountAll(); 1885} 1886