Torque3D Documentation / _generateds / guiConvexShapeEditorCtrl.cpp

guiConvexShapeEditorCtrl.cpp

Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp

More...

Public Functions

ConsoleDocClass(GuiConvexEditorCtrl , "@brief The base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the sketch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tool\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiConvexEditorCtrl , dropSelectionAtScreenCenter , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , getGridSnapSize , float , () , "@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(GuiConvexEditorCtrl , getSelectedFaceHorzFlip , bool , () , "@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(GuiConvexEditorCtrl , getSelectedFaceMaterial , const char * , () , "@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(GuiConvexEditorCtrl , getSelectedFaceUVOffset , Point2F , () , "@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(GuiConvexEditorCtrl , getSelectedFaceUVScale , Point2F , () , "@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(GuiConvexEditorCtrl , getSelectedFaceVertFlip , bool , () , "@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(GuiConvexEditorCtrl , getSelectedFaceZRot , float , () , "@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(GuiConvexEditorCtrl , handleDelete , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , handleDeselect , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , hasSelection , S32 , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , hollowSelection , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , recenterSelection , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , selectConvex , void , (ConvexShape *convex) , "( ConvexShape )" )
DefineEngineMethod(GuiConvexEditorCtrl , setGridSnapSize , void , (float gridSize) , (1.0) , "@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(GuiConvexEditorCtrl , setSelectedFaceHorzFlip , void , (bool flipped) , (false) , "@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(GuiConvexEditorCtrl , setSelectedFaceMaterial , void , (const char *materialName) , ("") , "@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(GuiConvexEditorCtrl , setSelectedFaceUVOffset , void , (Point2F offset) , (Point2F(0, 0)) , "@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(GuiConvexEditorCtrl , setSelectedFaceUVScale , void , (Point2F scale) , (Point2F(0, 0)) , "@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(GuiConvexEditorCtrl , setSelectedFaceVertFlip , void , (bool flipped) , (false) , "@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(GuiConvexEditorCtrl , setSelectedFaceZRot , void , (float degrees) , (0.0) , "@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(GuiConvexEditorCtrl , splitSelectedFace , void , () , "" )
DefineEngineMethod(GuiConvexEditorCtrl , toggleGridSnapping , void , () , "@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(GuiConvexEditorCtrl , updateShape , void , () , "@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)" )

Detailed Description

Public Functions

ConsoleDocClass(GuiConvexEditorCtrl , "@brief The base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the sketch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tool\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(GuiConvexEditorCtrl , dropSelectionAtScreenCenter , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , getGridSnapSize , float , () , "@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(GuiConvexEditorCtrl , getSelectedFaceHorzFlip , bool , () , "@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(GuiConvexEditorCtrl , getSelectedFaceMaterial , const char * , () , "@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(GuiConvexEditorCtrl , getSelectedFaceUVOffset , Point2F , () , "@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(GuiConvexEditorCtrl , getSelectedFaceUVScale , Point2F , () , "@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(GuiConvexEditorCtrl , getSelectedFaceVertFlip , bool , () , "@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(GuiConvexEditorCtrl , getSelectedFaceZRot , float , () , "@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(GuiConvexEditorCtrl , handleDelete , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , handleDeselect , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , hasSelection , S32 , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , hollowSelection , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , recenterSelection , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , selectConvex , void , (ConvexShape *convex) , "( ConvexShape )" )

DefineEngineMethod(GuiConvexEditorCtrl , setGridSnapSize , void , (float gridSize) , (1.0) , "@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(GuiConvexEditorCtrl , setSelectedFaceHorzFlip , void , (bool flipped) , (false) , "@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(GuiConvexEditorCtrl , setSelectedFaceMaterial , void , (const char *materialName) , ("") , "@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(GuiConvexEditorCtrl , setSelectedFaceUVOffset , void , (Point2F offset) , (Point2F(0, 0)) , "@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(GuiConvexEditorCtrl , setSelectedFaceUVScale , void , (Point2F scale) , (Point2F(0, 0)) , "@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(GuiConvexEditorCtrl , setSelectedFaceVertFlip , void , (bool flipped) , (false) , "@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(GuiConvexEditorCtrl , setSelectedFaceZRot , void , (float degrees) , (0.0) , "@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(GuiConvexEditorCtrl , splitSelectedFace , void , () , "" )

DefineEngineMethod(GuiConvexEditorCtrl , toggleGridSnapping , void , () , "@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(GuiConvexEditorCtrl , updateShape , void , () , "@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)" )

IMPLEMENT_CONOBJECT(GuiConvexEditorCtrl )

   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 "platform/platform.h"
  25#include "gui/worldEditor/guiConvexShapeEditorCtrl.h"
  26
  27#include "console/consoleTypes.h"
  28#include "console/engineAPI.h"
  29#include "T3D/convexShape.h"
  30#include "renderInstance/renderPassManager.h"
  31#include "collision/collision.h"
  32#include "math/util/frustum.h"
  33#include "math/mathUtils.h"
  34#include "gfx/gfxPrimitiveBuffer.h"
  35#include "gfx/gfxTextureHandle.h"
  36#include "gfx/gfxTransformSaver.h"
  37#include "gfx/primBuilder.h"
  38#include "gfx/gfxDrawUtil.h"
  39#include "scene/sceneRenderState.h"
  40#include "scene/sceneManager.h"
  41#include "gui/core/guiCanvas.h"
  42#include "gui/buttons/guiButtonCtrl.h"
  43#include "gui/worldEditor/undoActions.h"
  44#include "T3D/gameBase/gameConnection.h"
  45#include "gfx/sim/debugDraw.h"
  46#include "collision/optimizedPolyList.h"
  47#include "core/volume.h"
  48#include "gui/worldEditor/worldEditor.h"
  49#include "T3D/prefab.h"
  50#include "T3D/trigger.h"
  51#include "T3D/zone.h"
  52#include "T3D/portal.h"
  53#include "math/mPolyhedron.impl.h"
  54
  55#include "T3D/Scene.h"
  56
  57IMPLEMENT_CONOBJECT( GuiConvexEditorCtrl );
  58
  59ConsoleDocClass( GuiConvexEditorCtrl,
  60   "@brief The base class for the sketch tool\n\n"
  61   "Editor use only.\n\n"
  62   "@internal"
  63);
  64
  65
  66GuiConvexEditorCtrl::GuiConvexEditorCtrl()
  67 : mIsDirty( false ),
  68   mFaceSEL( -1 ),
  69   mFaceHL( -1 ),
  70   mFaceSavedXfm( true ),
  71   mSavedUndo( false ),
  72   mHasGeometry(false),
  73   mDragging( false ),
  74   mGizmoMatOffset( Point3F::Zero ),
  75   mPivotPos( Point3F::Zero ),
  76   mUsingPivot( false ),
  77   mSettingPivot( false ),
  78   mActiveTool( NULL ),
  79   mMouseDown( false ),
  80   mCreateTool( NULL ),
  81   mSavedGizmoFlags( -1 ),
  82   mHasCopied( false ),
  83   mLastUndo( NULL ),
  84   mUndoManager( NULL ),
  85   mCtrlDown( false ),
  86   mGridSnap(false)
  87{   
  88   mMaterialName = StringTable->insert("Grid512_OrangeLines_Mat");
  89}
  90
  91GuiConvexEditorCtrl::~GuiConvexEditorCtrl()
  92{
  93}
  94
  95bool GuiConvexEditorCtrl::onAdd()
  96{
  97   if ( !Parent::onAdd() )
  98      return false;   
  99
 100   SceneManager::getPreRenderSignal().notify( this, &GuiConvexEditorCtrl::_prepRenderImage );
 101
 102   mCreateTool = new ConvexEditorCreateTool( this );
 103
 104   return true;
 105}
 106
 107void GuiConvexEditorCtrl::onRemove()
 108{
 109   SceneManager::getPreRenderSignal().remove( this, &GuiConvexEditorCtrl::_prepRenderImage );
 110
 111   SAFE_DELETE( mCreateTool );
 112
 113   Parent::onRemove();
 114}
 115
 116void GuiConvexEditorCtrl::initPersistFields()
 117{   
 118   addField( "isDirty", TypeBool, Offset( mIsDirty, GuiConvexEditorCtrl ) );
 119   addField( "materialName", TypeString, Offset(mMaterialName, GuiConvexEditorCtrl) );
 120
 121   Parent::initPersistFields();
 122}
 123
 124bool GuiConvexEditorCtrl::onWake()
 125{
 126   if ( !Parent::onWake() )
 127      return false;
 128
 129   Scene* scene = Scene::getRootScene();
 130   if ( !scene )
 131      return true;
 132
 133   SimGroup::iterator itr = scene->begin();
 134   for ( ; itr != scene->end(); itr++ )
 135   {
 136      if ( String::compare( (*itr)->getClassName(), "ConvexShape" ) == 0 )
 137      {
 138         mConvexSEL = static_cast<ConvexShape*>( *itr );
 139         mGizmo->set( mConvexSEL->getTransform(), mConvexSEL->getPosition(), mConvexSEL->getScale() );
 140         return true;
 141      }
 142   }
 143
 144   return true;   
 145}
 146
 147void GuiConvexEditorCtrl::onSleep()
 148{
 149   Parent::onSleep();
 150
 151   mConvexSEL = NULL;
 152   mConvexHL = NULL;   
 153}
 154
 155void GuiConvexEditorCtrl::setVisible( bool val )
 156{
 157   //ConvexShape::smRenderEdges = value;
 158
 159   if ( isProperlyAdded() )
 160   {
 161      if ( !val )
 162      {         
 163         mFaceHL = -1;
 164         mConvexHL = NULL;       
 165
 166         setSelection( NULL, -1 );
 167
 168         if ( mSavedGizmoFlags != -1 )
 169         {
 170            mGizmoProfile->flags = mSavedGizmoFlags;
 171            mSavedGizmoFlags = -1;
 172         }
 173
 174         Scene* scene = Scene::getRootScene();
 175         if (scene != nullptr)
 176         {
 177            //Make our proxy objects "real" again
 178            for (U32 i = 0; i < mProxyObjects.size(); ++i)
 179            {
 180               if (!mProxyObjects[i].shapeProxy || !mProxyObjects[i].targetObject)
 181                  continue;
 182
 183               AbstractClassRep* classRep = AbstractClassRep::findClassRep(mProxyObjects[i].targetObjectClass);
 184               if (!classRep)
 185               {
 186                  Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", mProxyObjects[i].targetObjectClass.c_str());
 187                  continue;
 188               }
 189
 190               SceneObject* polyObj = createPolyhedralObject(mProxyObjects[i].targetObjectClass.c_str(), mProxyObjects[i].shapeProxy);
 191
 192               scene->addObject(polyObj);
 193
 194               //Now, remove the convex proxy
 195               mProxyObjects[i].shapeProxy->deleteObject();
 196               mProxyObjects[i].targetObject->deleteObject();
 197               mProxyObjects.erase(i);
 198               --i;
 199            }
 200
 201         }
 202      }
 203      else
 204      {
 205         mConvexHL = NULL;       
 206         mFaceHL = -1;
 207
 208         setSelection( NULL, -1 );
 209
 210         WorldEditor *wedit;
 211         if ( Sim::findObject( "EWorldEditor", wedit ) )
 212         {
 213            S32 count = wedit->getSelectionSize();
 214            for ( S32 i = 0; i < count; i++ )
 215            {
 216               S32 objId = wedit->getSelectObject(i);
 217               ConvexShape *pShape;
 218               if ( Sim::findObject( objId, pShape ) )
 219               {
 220                  mConvexSEL = pShape;                
 221                  wedit->clearSelection();
 222                  wedit->selectObject( String::ToString("%i",objId) );
 223                  break;
 224               }
 225            }
 226         }
 227         updateGizmoPos();
 228         mSavedGizmoFlags = mGizmoProfile->flags;
 229
 230         Scene* scene = Scene::getRootScene();
 231         if (scene != nullptr)
 232         {
 233            for (U32 c = 0; c < scene->size(); ++c)
 234            {
 235               bool isTrigger = (scene->at(c)->getClassName() == StringTable->insert("Trigger"));
 236               bool isZone = (scene->at(c)->getClassName() == StringTable->insert("Zone"));
 237               bool isPortal = (scene->at(c)->getClassName() == StringTable->insert("Portal"));
 238               bool isOccluder = (scene->at(c)->getClassName() == StringTable->insert("OcclusionVolume"));
 239
 240               if (isZone || isPortal || isOccluder)
 241               {
 242                  SceneObject* sceneObj = static_cast<SceneObject*>(scene->at(c));
 243                  if (!sceneObj)
 244                  {
 245                     Con::errorf("WorldEditor::createConvexShapeFrom - Invalid object");
 246                     continue;
 247                  }
 248
 249                  ConvexShape* proxyShape = createConvexShapeFrom(sceneObj);
 250
 251                  //Set the texture to a representatory one so we know what's what
 252                  if (isTrigger)
 253                     proxyShape->mMaterialName = "TriggerProxyMaterial";
 254                  else if (isPortal)
 255                     proxyShape->mMaterialName = "PortalProxyMaterial";
 256                  else if (isZone)
 257                     proxyShape->mMaterialName = "ZoneProxyMaterial";
 258                  else if (isOccluder)
 259                     proxyShape->mMaterialName = "OccluderProxyMaterial";
 260
 261                  proxyShape->_updateMaterial();
 262
 263                  sceneObj->setHidden(true);
 264
 265                  //set up the proxy object
 266                  ConvexShapeProxy newProxy;
 267                  newProxy.shapeProxy = proxyShape;
 268                  newProxy.targetObject = sceneObj;
 269
 270                  if (isTrigger)
 271                     newProxy.targetObjectClass = "Trigger";
 272                  else if (isPortal)
 273                     newProxy.targetObjectClass = "Portal";
 274                  else if (isZone)
 275                     newProxy.targetObjectClass = "Zone";
 276                  else
 277                     newProxy.targetObjectClass = "OcclusionVolume";
 278
 279                  mProxyObjects.push_back(newProxy);
 280               }
 281            }
 282         }
 283      }
 284   }
 285
 286   Parent::setVisible( val );
 287}
 288
 289void GuiConvexEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
 290{
 291   mouseLock();   
 292
 293   mMouseDown = true;
 294
 295   if ( event.modifier & SI_ALT )
 296   {
 297      setActiveTool( mCreateTool );
 298      mActiveTool->on3DMouseDown( event );
 299      return;
 300   }
 301
 302   if ( mConvexSEL && isShapeValid( mConvexSEL ) )      
 303      mLastValidShape = mConvexSEL->mSurfaces;  
 304
 305   if ( mConvexSEL &&
 306        mFaceSEL != -1 &&
 307        mGizmo->getMode() == RotateMode &&
 308        mGizmo->getSelection() == Gizmo::Centroid )
 309   {      
 310      mSettingPivot = true;      
 311      mSavedPivotPos = mGizmo->getPosition();
 312      setPivotPos( mConvexSEL, mFaceSEL, event );
 313      updateGizmoPos();
 314      return;
 315   }
 316
 317   mGizmo->on3DMouseDown( event );   
 318}
 319
 320void GuiConvexEditorCtrl::on3DRightMouseDown(const Gui3DMouseEvent & event)
 321{
 322   return;
 323
 324   /*
 325   if ( mConvexSEL && mFaceSEL != -1 && mFaceSEL == mFaceHL )
 326   {
 327      _submitUndo( "Split ConvexShape face." );
 328
 329      const MatrixF &surf = mConvexSEL->mSurfaces[mFaceSEL];
 330
 331      MatrixF newSurf( surf );
 332
 333      MatrixF rotMat( EulerF( 0.0f, mDegToRad( 2.0f ), 0.0f ) );
 334
 335      newSurf *= rotMat;           
 336
 337      mConvexSEL->mSurfaces.insert( mFaceSEL+1, newSurf );
 338   }
 339   */
 340}
 341
 342void GuiConvexEditorCtrl::on3DRightMouseUp(const Gui3DMouseEvent & event)
 343{
 344   //ConvexShape *hitShape;
 345   //S32 hitFace;
 346   //bool hit = _cursorCast( event, &hitShape, &hitFace );
 347   //Con::printf( hit ? "HIT" : "MISS" );
 348}
 349
 350void GuiConvexEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
 351{
 352   mouseUnlock();
 353
 354   mMouseDown = false;
 355
 356   mHasCopied = false;
 357   mHasGeometry = false;   
 358
 359   if ( mActiveTool )
 360   {
 361      ConvexEditorTool::EventResult result = mActiveTool->on3DMouseUp( event );
 362
 363      if ( result == ConvexEditorTool::Done )      
 364         setActiveTool( NULL );         
 365      
 366      return;
 367   }
 368
 369   if ( !mSettingPivot && !mDragging && ( mGizmo->getSelection() == Gizmo::None || !mConvexSEL ) )
 370   {
 371      if ( mConvexSEL != mConvexHL )
 372      {         
 373         setSelection( mConvexHL, -1 );
 374      }
 375      else
 376      {
 377         if ( mFaceSEL != mFaceHL )         
 378            setSelection( mConvexSEL, mFaceHL );         
 379         else
 380            setSelection( mConvexSEL, -1 );
 381      }
 382
 383      mUsingPivot = false;
 384   }
 385
 386   mSettingPivot = false;
 387   mSavedPivotPos = mGizmo->getPosition();
 388   mSavedUndo = false;   
 389
 390   mGizmo->on3DMouseUp( event );
 391
 392   if ( mDragging )
 393   {
 394      mDragging = false;
 395
 396      if ( mConvexSEL )
 397      {         
 398         Vector< U32> removedPlanes;
 399         mConvexSEL->cullEmptyPlanes( &removedPlanes );
 400
 401         // If a face has been removed we need to validate / remap
 402         // our selected and highlighted faces.
 403         if ( !removedPlanes.empty() )
 404         {
 405            S32 prevFaceHL = mFaceHL;
 406            S32 prevFaceSEL = mFaceSEL;
 407
 408            if ( removedPlanes.contains( mFaceHL ) )
 409               prevFaceHL = mFaceHL = -1;
 410            if ( removedPlanes.contains( mFaceSEL ) )
 411               prevFaceSEL = mFaceSEL = -1;
 412            
 413            for ( S32 i = 0; i < removedPlanes.size(); i++ )
 414            {
 415               if ( (S32)removedPlanes[i] < prevFaceSEL )
 416                  mFaceSEL--;               
 417               if ( (S32)removedPlanes[i] < prevFaceHL )
 418                  mFaceHL--;     
 419            }        
 420
 421            setSelection( mConvexSEL, mFaceSEL );
 422
 423            // We need to reindex faces.
 424            updateShape( mConvexSEL );
 425         }
 426      }
 427   }
 428
 429   updateGizmoPos();   
 430}
 431
 432void GuiConvexEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
 433{
 434   if ( mActiveTool )
 435   {
 436      // If we have an active tool pass this event to it.
 437      // If it handled it, consume the event.
 438      if ( mActiveTool->on3DMouseMove( event ) )
 439         return;
 440   }
 441
 442   ConvexShape *hitShape = NULL;
 443   S32 hitFace = -1;
 444   
 445   _cursorCast( event, &hitShape, &hitFace );
 446
 447   if ( !mConvexSEL )
 448   {
 449      mConvexHL = hitShape;
 450      mFaceHL = -1;
 451   }
 452   else
 453   {
 454      if ( mConvexSEL == hitShape )
 455      {
 456         mConvexHL = hitShape;        
 457         mFaceHL = hitFace;
 458      }
 459      else
 460      {
 461         // Mousing over a shape that is not the one currently selected.
 462
 463         if ( mFaceSEL != -1 )
 464         {
 465            mFaceHL = -1;
 466         }
 467         else
 468         {
 469            mConvexHL = hitShape;
 470            mFaceHL = -1;
 471         } 
 472      }
 473   }
 474
 475   if ( mConvexSEL )
 476      mGizmo->on3DMouseMove( event );
 477}
 478
 479void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
 480{      
 481   if ( mActiveTool )
 482   {
 483      // If we have an active tool pass this event to it.
 484      // If it handled it, consume the event.
 485      if ( mActiveTool->on3DMouseDragged( event ) )
 486         return;
 487   }
 488
 489   //mGizmoProfile->rotateScalar = 0.55f;
 490   //mGizmoProfile->scaleScalar = 0.55f;
 491
 492   if ( !mConvexSEL )
 493      return;
 494
 495   if ( mGizmo->getMode() == RotateMode &&
 496        mGizmo->getSelection() == Gizmo::Centroid )
 497   {            
 498      setPivotPos( mConvexSEL, mFaceSEL, event );      
 499      mDragging = true;
 500      return;
 501   }
 502
 503   mGizmo->on3DMouseDragged( event );
 504      
 505   if ( event.modifier & SI_SHIFT && 
 506       ( mGizmo->getMode() == MoveMode || mGizmo->getMode() == RotateMode ) &&
 507        !mHasCopied )
 508   {
 509      if ( mFaceSEL != -1 )
 510      {
 511         ConvexShape *newShape = mCreateTool->extrudeShapeFromFace( mConvexSEL, mFaceSEL );
 512         //newShape->_updateGeometry();
 513
 514         submitUndo( CreateShape, newShape );
 515         setSelection( newShape, 0 );         
 516         updateGizmoPos();
 517
 518         mGizmo->on3DMouseDown( event );
 519
 520         mHasCopied = true;
 521         mSavedUndo = true;
 522      }
 523      else
 524      {
 525         ConvexShape *newShape = new ConvexShape();
 526         newShape->setTransform( mConvexSEL->getTransform() );
 527         newShape->setScale( mConvexSEL->getScale() );
 528         newShape->mSurfaces.clear();
 529         newShape->mSurfaces.merge( mConvexSEL->mSurfaces );
 530         
 531         setupShape( newShape );
 532
 533         newShape->setField("material", mConvexSEL->getMaterialName());
 534
 535         submitUndo( CreateShape, newShape );
 536
 537         setSelection( newShape, -1 );
 538
 539         updateGizmoPos();
 540
 541         mHasCopied = true;
 542         mSavedUndo = true;
 543      }
 544
 545      return;
 546   }
 547
 548   if ( mGizmo->getMode() == RotateMode &&
 549        event.modifier & SI_CTRL &&
 550        !mHasCopied &&
 551        mFaceSEL != -1 )
 552   {
 553      // Can must verify that splitting the face at the current angle 
 554      // ( of the gizmo ) will generate a valid shape.  If not enough rotation
 555      // has occurred we will have two faces that are coplanar and must wait
 556      // until later in the drag to perform the split.
 557
 558      //AssertFatal( isShapeValid( mConvexSEL ), "Shape was already invalid at beginning of split operation." );
 559
 560      if ( !isShapeValid( mConvexSEL ) )
 561         return;
 562
 563      mLastValidShape = mConvexSEL->mSurfaces;
 564
 565      Point3F rot = mGizmo->getDeltaTotalRot();
 566      rot.normalize();
 567      rot *= mDegToRad( 10.0f );
 568
 569      MatrixF rotMat( (EulerF)rot );
 570
 571      MatrixF worldToObj( mConvexSEL->getTransform() );
 572      worldToObj.scale( mConvexSEL->getScale() );
 573      worldToObj.inverse();      
 574
 575      mConvexSEL->mSurfaces.increment();
 576      MatrixF &newSurf = mConvexSEL->mSurfaces.last();
 577      newSurf = mConvexSEL->mSurfaces[mFaceSEL] * rotMat;
 578      
 579      //worldToObj.mul( mGizmo->getTransform() );
 580      //Point3F pos( mPivotPos );
 581      //worldToObj.mulP( pos );
 582      //newSurf.setPosition( pos );
 583
 584      updateShape( mConvexSEL );
 585
 586      if ( !isShapeValid( mConvexSEL ) )
 587      {
 588         mConvexSEL->mSurfaces = mLastValidShape;
 589         updateShape( mConvexSEL );
 590      }
 591      else
 592      {
 593         mHasCopied = true;
 594         mSavedUndo = true;
 595
 596         mLastValidShape = mConvexSEL->mSurfaces;
 597
 598         submitUndo( ModifyShape, mConvexSEL );           
 599
 600         setSelection( mConvexSEL, mConvexSEL->mSurfaces.size() - 1 );
 601
 602         updateGizmoPos();
 603      }      
 604      
 605      return;
 606   }
 607
 608   // If we are dragging, but no gizmo selection...
 609   // Then treat this like a regular mouse move, update the highlighted
 610   // convex/face under the cursor and handle onMouseUp as we normally would
 611   // to change the selection.
 612   if ( mGizmo->getSelection() == Gizmo::None )
 613   {
 614      ConvexShape *hitShape = NULL;
 615      S32 hitFace = -1;
 616
 617      _cursorCast( event, &hitShape, &hitFace );
 618      mFaceHL = hitFace;
 619      mConvexHL = hitShape;      
 620
 621      return;
 622   }
 623
 624   mDragging = true;
 625
 626   // Manipulating a face.
 627
 628   if ( mFaceSEL != -1 )
 629   {
 630      if ( !mSavedUndo )
 631      {
 632         mSavedUndo = true;
 633         submitUndo( ModifyShape, mConvexSEL );
 634      }      
 635
 636      if ( mGizmo->getMode() == ScaleMode &&  !(event.modifier & SI_CTRL))
 637      {
 638         scaleFace( mConvexSEL, mFaceSEL, mGizmo->getScale() );
 639      }
 640
 641     else if ( mGizmo->getMode() == ScaleMode &&  (event.modifier & SI_CTRL) )
 642      {
 643          Point3F scale = mGizmo->getDeltaScale();
 644
 645        F32 scalar = 1;
 646        mConvexSEL->mSurfaceUVs[mFaceSEL].scale += (Point2F(scale.x, scale.y) * scalar);
 647
 648        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x < 0.01)
 649           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 0.01;
 650
 651        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y < 0.01)
 652           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 0.01;
 653
 654        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x > 100)
 655           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 100;
 656
 657        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y > 100)
 658           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 100;
 659
 660        Point2F test = mConvexSEL->mSurfaceUVs[mFaceSEL].scale;
 661        mConvexSEL->setMaskBits( ConvexShape::UpdateMask );
 662
 663        updateShape( mConvexSEL, mFaceSEL );
 664     }
 665     /*else if ( mGizmo->getMode() == MoveMode && event.modifier & SI_CTRL ) {
 666        Point3F scale = mGizmo->getOffset();
 667
 668          F32 scalar = 0.8;
 669        mConvexSEL->mSurfaceTextures[mFaceSEL].offset += (Point2F(-scale.x, scale.z) * scalar);
 670        mConvexSEL->setMaskBits( ConvexShape::UpdateMask );
 671
 672        updateShape( mConvexSEL, mFaceSEL );
 673     }*/
 674      else
 675      {
 676         // Why does this have to be so ugly.
 677         if ( mGizmo->getMode() == RotateMode || 
 678              ( mGizmo->getMode() == MoveMode  && 
 679                ( event.modifier & SI_CTRL  ||
 680                  ( mGizmo->getSelection() == Gizmo::Axis_Z && mHasCopied ) 
 681                )
 682              )
 683            )
 684         {
 685            const MatrixF &gMat = mGizmo->getTransform();      
 686            MatrixF surfMat;
 687            surfMat.mul( mConvexSEL->mWorldToObj, gMat );
 688
 689            MatrixF worldToObj ( mConvexSEL->getTransform() );
 690            worldToObj.scale( mConvexSEL->getScale() );
 691            worldToObj.inverse();
 692
 693            Point3F newPos;            
 694            newPos = gMat.getPosition();      
 695
 696            worldToObj.mulP( newPos );
 697            surfMat.setPosition( newPos );
 698            
 699            // Clear out floating point errors.
 700            cleanMatrix( surfMat );
 701
 702            if (mGizmo->getSelection() == Gizmo::Axis_Z)
 703            {
 704               MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL];
 705               EulerF curSufRot = curSurfMat.toEuler();
 706
 707               EulerF newSufRot = surfMat.toEuler();
 708
 709               float zRot = mRadToDeg(newSufRot.z - curSufRot.z);
 710
 711               float curZRot = mConvexSEL->mSurfaceUVs[mFaceSEL].zRot;
 712
 713               mConvexSEL->mSurfaceUVs[mFaceSEL].zRot += zRot;
 714            }
 715
 716            mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
 717
 718            updateShape( mConvexSEL, mFaceSEL );         
 719         }
 720         else
 721         {
 722            // Translating a face in x/y/z
 723
 724            translateFace( mConvexSEL, mFaceSEL, mGizmo->getTotalOffset() );
 725         }
 726      }
 727
 728      if ( isShapeValid( mConvexSEL ) )          
 729      {
 730         AssertFatal( mConvexSEL->mSurfaces.size() > mFaceSEL, "mFaceSEL out of range." );
 731         mLastValidShape = mConvexSEL->mSurfaces; 
 732      }
 733      else
 734      {
 735         AssertFatal( mLastValidShape.size() > mFaceSEL, "mFaceSEL out of range." );
 736         mConvexSEL->mSurfaces = mLastValidShape;
 737         updateShape( mConvexSEL );
 738      }
 739
 740      return;
 741   }
 742
 743   // Manipulating a whole Convex.
 744
 745   if ( !mSavedUndo )
 746   {
 747      mSavedUndo = true;
 748      submitUndo( ModifyShape, mConvexSEL );
 749   }
 750
 751   if ( mGizmo->getMode() == MoveMode )
 752   {
 753      //mConvexSEL->setPosition( mGizmo->getPosition() );
 754
 755      //MatrixF mat = mGizmo->getTransform();
 756      Point3F wPos = mGizmo->getPosition();
 757      //mat.getColumn(3, &wPos);
 758
 759      // adjust
 760      //wPos += offset;
 761
 762      if (mGridSnap && mGridPlaneSize != 0.f)
 763      {
 764         if (mGizmo->getSelection() == Gizmo::Selection::Axis_X || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ)
 765            wPos.x -= mFmod(wPos.x, mGridPlaneSize);
 766
 767         if (mGizmo->getSelection() == Gizmo::Selection::Axis_Y || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ)
 768            wPos.y -= mFmod(wPos.y, mGridPlaneSize);
 769
 770         if (mGizmo->getSelection() == Gizmo::Selection::Axis_Z || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ)
 771            wPos.z -= mFmod(wPos.z, mGridPlaneSize);
 772      }
 773
 774      mConvexSEL->setPosition(wPos);
 775   }
 776   else if ( mGizmo->getMode() == RotateMode )
 777   {   
 778      mConvexSEL->setTransform( mGizmo->getTransform() );      
 779   }
 780   else
 781   {
 782      mConvexSEL->setScale( mGizmo->getScale() );
 783   }   
 784
 785   if ( mConvexSEL->getClientObject() )
 786   {
 787      ConvexShape *clientObj = static_cast< ConvexShape* >( mConvexSEL->getClientObject() );
 788      clientObj->setTransform( mConvexSEL->getTransform() );
 789      clientObj->setScale( mConvexSEL->getScale() );
 790   }      
 791}
 792
 793void GuiConvexEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event)
 794{
 795
 796}
 797
 798void GuiConvexEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
 799{
 800
 801}
 802
 803bool GuiConvexEditorCtrl::onKeyDown( const GuiEvent &evt )
 804{
 805   bool handled = false;
 806
 807   switch ( evt.keyCode )
 808   {
 809   case KEY_ESCAPE:
 810      handled = handleEscape();      
 811      break;   
 812   case KEY_A:
 813      if ( evt.modifier & SI_ALT )
 814      {
 815         GizmoAlignment align = mGizmo->getProfile()->alignment;
 816         if ( align == World )
 817            mGizmo->getProfile()->alignment = Object;
 818         else
 819            mGizmo->getProfile()->alignment = World;
 820         handled = true;
 821      }
 822      break;
 823   case KEY_LCONTROL:
 824      //mCtrlDown = true;
 825      break;  
 826   default:
 827      break;
 828   }
 829   
 830   return handled;
 831}
 832
 833bool GuiConvexEditorCtrl::onKeyUp( const GuiEvent &evt )
 834{
 835   bool handled = false;
 836
 837   switch ( evt.keyCode )
 838   {      
 839   case KEY_LCONTROL:
 840      //mCtrlDown = false;
 841      break;   
 842   default:
 843      break;
 844   }
 845
 846   return handled;
 847}
 848
 849void GuiConvexEditorCtrl::get3DCursor( GuiCursor *&cursor, 
 850                                       bool &visible, 
 851                                       const Gui3DMouseEvent &event_ )
 852{
 853   //cursor = mAddNodeCursor;
 854   //visible = false;
 855
 856   cursor = NULL;
 857   visible = false;
 858
 859   GuiCanvas *root = getRoot();
 860   if ( !root )
 861      return;
 862
 863   S32 currCursor = PlatformCursorController::curArrow;
 864
 865   if ( root->mCursorChanged == currCursor )
 866      return;
 867
 868   PlatformWindow *window = root->getPlatformWindow();
 869   PlatformCursorController *controller = window->getCursorController();
 870
 871   // We've already changed the cursor, 
 872   // so set it back before we change it again.
 873   if( root->mCursorChanged != -1)
 874      controller->popCursor();
 875
 876   // Now change the cursor shape
 877   controller->pushCursor(currCursor);
 878   root->mCursorChanged = currCursor;   
 879}
 880
 881void GuiConvexEditorCtrl::updateGizmo()
 882{
 883   mGizmoProfile->restoreDefaultState();
 884   
 885   const GizmoMode &mode = mGizmoProfile->mode;
 886   S32 &flags = mGizmoProfile->flags;
 887   GizmoAlignment &align = mGizmoProfile->alignment;
 888
 889   U8 keys = Input::getModifierKeys();
 890
 891   mCtrlDown = keys & ( SI_LCTRL | SI_LSHIFT );
 892
 893   bool altDown = keys & ( SI_LALT );
 894
 895   if ( altDown )
 896   {
 897      flags = 0;
 898      return;
 899   }
 900
 901   if ( mFaceSEL != -1 )
 902   {
 903      align = Object;    
 904      flags |= GizmoProfile::CanRotateUniform;
 905      flags &= ~<a href="/coding/class/classgizmoprofile/">GizmoProfile</a>::CanRotateScreen;
 906   }
 907   else
 908   {
 909      flags &= ~<a href="/coding/class/classgizmoprofile/">GizmoProfile</a>::CanRotateUniform;
 910      flags |= GizmoProfile::CanRotateScreen;
 911   }
 912
 913   if ( mFaceSEL != -1 && mode == ScaleMode )
 914      flags &= ~<a href="/coding/class/classgizmoprofile/">GizmoProfile</a>::CanScaleZ;
 915   else
 916      flags |= GizmoProfile::CanScaleZ;         
 917
 918   if ( mFaceSEL != -1 && mode == MoveMode )
 919   {
 920      if ( mCtrlDown )  
 921         //hijacking the CTRL modifier for texture offsetting control
 922         //flags &= ~( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn ); 
 923         flags &= ~<a href="/coding/class/classgizmoprofile/">GizmoProfile</a>::CanScaleZ;
 924      else      
 925         flags |= ( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );      
 926   }
 927}
 928
 929void GuiConvexEditorCtrl::renderScene(const RectI & updateRect)
 930{      
 931   // Synch selected ConvexShape with the WorldEditor.
 932
 933   WorldEditor *wedit;
 934   if ( Sim::findObject( "EWorldEditor", wedit) )
 935   {
 936      S32 count = wedit->getSelectionSize();
 937
 938      if ( !mConvexSEL && count != 0 )
 939         wedit->clearSelection();
 940      else if ( mConvexSEL && count != 1 )
 941      {
 942         wedit->clearSelection();
 943         wedit->selectObject( mConvexSEL->getIdString() );
 944      }
 945      else if ( mConvexSEL && count == 1 )
 946      {
 947         if ( wedit->getSelectObject(0) != mConvexSEL->getId() )
 948         {
 949            wedit->clearSelection();
 950            wedit->selectObject( mConvexSEL->getIdString() );
 951         }
 952      }
 953   }   
 954
 955   // Update status bar text.
 956
 957   SimObject *statusbar;
 958   if ( Sim::findObject( "EditorGuiStatusBar", statusbar ) )
 959   {
 960      String text( "Sketch Tool." );      
 961      GizmoMode mode = mGizmo->getMode();
 962
 963      if ( mMouseDown && mGizmo->getSelection() != Gizmo::None && mConvexSEL )
 964      {
 965         Point3F delta;
 966         String qualifier;
 967
 968         if ( mode == RotateMode )   
 969         {
 970            if ( mSettingPivot )            
 971               delta = mGizmo->getPosition() - mSavedPivotPos;
 972            else
 973               delta = mGizmo->getDeltaTotalRot();         
 974         }
 975         else if ( mode == MoveMode )         
 976            delta = mGizmo->getTotalOffset();         
 977         else if ( mode == ScaleMode )
 978            delta = mGizmo->getDeltaTotalScale();            
 979         
 980         if ( mGizmo->getAlignment() == Object && 
 981              mode != ScaleMode )
 982         {            
 983            mConvexSEL->mWorldToObj.mulV( delta );            
 984            if ( mFaceSEL != -1 && mode != RotateMode )
 985            {
 986               MatrixF objToSurf( mConvexSEL->mSurfaces[ mFaceSEL ] );
 987               objToSurf.scale( mConvexSEL->getScale() );
 988               objToSurf.inverse();
 989               objToSurf.mulV( delta );
 990            }
 991         }
 992
 993         if ( mIsZero( delta.x, 0.0001f ) )
 994            delta.x = 0.0f;
 995         if ( mIsZero( delta.y, 0.0001f ) )
 996            delta.y = 0.0f;
 997         if ( mIsZero( delta.z, 0.0001f ) )
 998            delta.z = 0.0f;
 999         
1000         if ( mode == RotateMode )         
1001         {
1002            if ( mSettingPivot )            
1003               text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
1004            else
1005            {
1006               delta.x = mRadToDeg( delta.x );
1007               delta.y = mRadToDeg( delta.y );
1008               delta.z = mRadToDeg( delta.z );
1009               text = String::ToString( "Delta angle ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
1010            }
1011         }
1012         else if ( mode == MoveMode )     
1013            text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
1014         else if ( mode == ScaleMode )
1015            text = String::ToString( "Delta scale ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z ); 
1016      }
1017      else 
1018      {     
1019         if ( !mConvexSEL )
1020            text = "Sketch Tool.  ALT + Click-Drag to create a new ConvexShape.";
1021         else if ( mFaceSEL == -1 )
1022         {
1023            if ( mode == MoveMode )            
1024               text = "Move selection.  SHIFT while dragging duplicates objects.";
1025            else if ( mode == RotateMode )            
1026               text = "Rotate selection.";
1027            else if ( mode == ScaleMode )            
1028               text = "Scale selection.";        
1029         }
1030         else 
1031         {
1032            if ( mode == MoveMode )            
1033               text = "Move face.  SHIFT while beginning a drag EXTRUDES a new convex. Press CTRL for alternate translation mode.";
1034            else if ( mode == RotateMode )            
1035               text = "Rotate face.  Gizmo/Pivot is draggable. CTRL while dragging splits/folds a new face. SHIFT while dragging extrudes a new convex.";
1036            else if ( mode == ScaleMode )            
1037            text = "Scale face.";
1038         }
1039      }
1040   
1041      // Issue a warning in the status bar
1042      // if this convex has an excessive number of surfaces...
1043      if ( mConvexSEL && mConvexSEL->getSurfaces().size() > ConvexShape::smMaxSurfaces )
1044      {
1045          text = "WARNING: Reduce the number of surfaces on the selected ConvexShape, only the first 100 will be saved!";
1046      }
1047
1048      Con::executef( statusbar, "setInfo", text.c_str() );
1049
1050   Con::executef( statusbar, "setSelectionObjectsByCount", Con::getIntArg( mConvexSEL == NULL ? 0 : 1 ) );
1051   }   
1052
1053   if ( mActiveTool )
1054      mActiveTool->renderScene( updateRect );
1055
1056   ColorI colorHL( 255, 50, 255, 255 );
1057   ColorI colorSEL( 255, 50, 255, 255 );
1058   ColorI colorNA( 255, 255, 255, 100 );
1059
1060   GFXDrawUtil *drawer = GFX->getDrawUtil();
1061
1062   if ( mConvexSEL && !mDragging )
1063   {
1064      if ( mFaceSEL == -1 )
1065      {
1066         GFXStateBlockDesc desc;
1067         desc.setBlend( true );
1068         desc.setZReadWrite( true, true );
1069
1070         Box3F objBox = mConvexSEL->getObjBox();
1071         objBox.scale( mConvexSEL->getScale() );
1072
1073         const MatrixF &objMat = mConvexSEL->getTransform();
1074
1075         Point3F boxPos = objBox.getCenter();
1076         objMat.mulP( boxPos );
1077         
1078         drawer->drawObjectBox( desc, objBox.getExtents(), boxPos, objMat, ColorI::WHITE );
1079      }
1080      else
1081      {
1082         mConvexSEL->renderFaceEdges( -1, colorNA );     
1083
1084         drawFacePlane( mConvexSEL, mFaceSEL );         
1085      }
1086
1087      if ( mConvexHL == mConvexSEL &&
1088           mFaceHL != -1 && 
1089           mFaceHL != mFaceSEL && 
1090           mGizmo->getSelection() == Gizmo::None )
1091      {
1092         mConvexSEL->renderFaceEdges( mFaceHL, colorHL );
1093      }
1094   }
1095
1096   if ( mConvexHL && mConvexHL != mConvexSEL )
1097   {
1098      mConvexHL->renderFaceEdges( -1 );      
1099   }
1100
1101   if ( mGizmo->getMode() != RotateMode && mUsingPivot )
1102   {
1103      mUsingPivot = false;
1104      updateGizmoPos();
1105   }
1106
1107   F32 gizmoAlpha = 1.0f;
1108   if ( !mConvexSEL )
1109      gizmoAlpha = 0.0f;
1110
1111   if ( mMouseDown && mGizmo->getSelection() != Gizmo::None && mConvexSEL )
1112   {
1113      if ( mSettingPivot )
1114         gizmoAlpha = 1.0f;
1115      else
1116         gizmoAlpha = 0.0f;
1117   }
1118
1119   DebugDrawer::get()->render();
1120
1121   {
1122      GFXTransformSaver saver;
1123      // Now draw all the 2d stuff!
1124      GFX->setClipRect(updateRect); 
1125
1126      if ( mConvexSEL && mFaceSEL != -1 )
1127      {      
1128         Vector< Point3F> lineList;
1129         mConvexSEL->getSurfaceLineList( mFaceSEL, lineList );
1130
1131         MatrixF objToWorld( mConvexSEL->getTransform() );
1132         objToWorld.scale( mConvexSEL->getScale() );      
1133
1134         for ( S32 i = 0; i < lineList.size(); i++ )     
1135            objToWorld.mulP( lineList[i] );        
1136
1137         for ( S32 i = 0; i < lineList.size() - 1; i++ )
1138         {
1139            Point3F p0( lineList[i] );
1140            Point3F p1( lineList[i+1] );
1141
1142            drawLine( p0, p1, colorSEL, 3.0f );
1143         }
1144      }
1145
1146      if ( gizmoAlpha == 1.0f )
1147      {
1148         if ( mGizmoProfile->mode != NoneMode )
1149            mGizmo->renderText( mSaveViewport, mSaveModelview, mSaveProjection );      
1150      }
1151
1152      if ( mActiveTool )
1153         mActiveTool->render2D();
1154   }
1155
1156   if ( gizmoAlpha == 1.0f )   
1157      mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix, mLastCameraQuery.fov );
1158} 
1159
1160void GuiConvexEditorCtrl::drawFacePlane( ConvexShape *shape, S32 faceId )
1161{
1162   // Build a vb of the face points ( in world space ) scaled outward in
1163   // the surface space in x/y with uv coords.
1164
1165   /*
1166   Vector< Point3F > points;
1167   Vector< Point2F > coords;
1168
1169   shape->getSurfaceTriangles( faceId, &points, &coords, false );
1170
1171   if ( points.empty() )
1172      return;
1173
1174   GFXVertexBufferHandle< GFXVertexPCT > vb;
1175   vb.set( GFX, points.size(), GFXBufferTypeVolatile );
1176   GFXVertexPCT *vert = vb.lock();
1177
1178   for ( S32 i = 0; i < points.size(); i++ )
1179   {
1180      vert->point = points[i];
1181      vert->color.set( 255, 255, 255, 200 );
1182      vert->texCoord = coords[i];
1183      vert++;
1184   }
1185
1186   vb.unlock();
1187
1188   GFXTransformSaver saver;
1189   MatrixF renderMat( shape->getTransform() );
1190   renderMat.scale( shape->getScale() );
1191   GFX->multWorld( renderMat );
1192
1193   GFXStateBlockDesc desc;
1194   desc.setBlend( true );
1195   desc.setCullMode( GFXCullNone );
1196   desc.setZReadWrite( true, false );
1197   desc.samplersDefined = true;
1198   desc.samplers[0] = GFXSamplerStateDesc::getWrapLinear();
1199   GFX->setStateBlockByDesc( desc );
1200
1201   GFX->setVertexBuffer( vb );
1202
1203   GFXTexHandle tex( "core/art/grids/512_transp", &GFXStaticTextureSRGBProfile, "ConvexEditor_grid" );
1204   GFX->setTexture( 0, tex );
1205   GFX->setupGenericShaders();
1206   GFX->drawPrimitive( GFXTriangleList, 0, points.size() / 3 );
1207   */
1208}
1209
1210
1211void GuiConvexEditorCtrl::scaleFace( ConvexShape *shape, S32 faceId, Point3F scale )
1212{
1213   if ( !mHasGeometry )
1214   {
1215      mHasGeometry = true;
1216      
1217      mSavedGeometry = shape->mGeometry;
1218      mSavedSurfaces = shape->mSurfaces;      
1219   }
1220   else
1221   {
1222      shape->mGeometry = mSavedGeometry;
1223      shape->mSurfaces = mSavedSurfaces;
1224   }
1225
1226   if ( shape->mGeometry.faces.size() <= faceId )
1227      return;
1228   
1229   ConvexShape::Face &face = shape->mGeometry.faces[faceId];
1230
1231   Vector< Point3F> &pointList = shape->mGeometry.points;
1232
1233   AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
1234      
1235   Point3F projScale;
1236   scale.z = 1.0f;
1237
1238   const MatrixF &surfToObj = shape->mSurfaces[ face.id ];
1239   MatrixF objToSurf( surfToObj );
1240   objToSurf.inverse();
1241
1242   for ( S32 i = 0; i < face.points.size(); i++ )
1243   {                  
1244      Point3F &pnt = pointList[ face.points[i] ];   
1245
1246      objToSurf.mulP( pnt );
1247      pnt *= scale;
1248      surfToObj.mulP( pnt );
1249   }
1250
1251   updateModifiedFace( shape, faceId );
1252}
1253
1254void GuiConvexEditorCtrl::translateFace( ConvexShape *shape, S32 faceId, const Point3F &displace )
1255{
1256   if ( !mHasGeometry )
1257   {
1258      mHasGeometry = true;
1259
1260      mSavedGeometry = shape->mGeometry;
1261      mSavedSurfaces = shape->mSurfaces;      
1262   }
1263   else
1264   {
1265      shape->mGeometry = mSavedGeometry;
1266      shape->mSurfaces = mSavedSurfaces;
1267   }
1268
1269   if ( shape->mGeometry.faces.size() <= faceId )
1270      return;
1271
1272   ConvexShape::Face &face = shape->mGeometry.faces[faceId];
1273
1274   Vector< Point3F> &pointList = shape->mGeometry.points;
1275
1276   AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
1277
1278   Point3F modDisplace = Point3F(displace.x, displace.y, displace.z);
1279
1280   //snapping
1281   if (mGridSnap && mGridPlaneSize != 0)
1282   {
1283      Point3F faceCenter = Point3F::Zero;
1284
1285      for (S32 i = 0; i < face.points.size(); i++)
1286      {
1287         Point3F &pnt = pointList[face.points[i]];
1288         faceCenter += pnt;
1289      }
1290
1291      faceCenter /= face.points.size();
1292
1293      // Transform displacement into object space.    
1294      MatrixF objToWorld(shape->getWorldTransform());
1295      objToWorld.scale(shape->getScale());
1296      objToWorld.inverse();
1297
1298      objToWorld.mulP(faceCenter);
1299
1300      modDisplace = faceCenter + displace;
1301      Point3F fMod = Point3F::Zero;
1302
1303      if (!mIsZero(displace.x))
1304         fMod.x = mFmod(modDisplace.x - (displace.x > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
1305
1306      if (!mIsZero(displace.y))
1307         fMod.y = mFmod(modDisplace.y - (displace.y > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
1308
1309      if (!mIsZero(displace.z))
1310         fMod.z = mFmod(modDisplace.z - (displace.z > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
1311
1312      modDisplace -= fMod;
1313      modDisplace -= faceCenter;
1314   }
1315
1316   // Transform displacement into object space.    
1317   MatrixF worldToObj( shape->getTransform() );
1318   worldToObj.scale( shape->getScale() );
1319   worldToObj.inverse();
1320
1321   Point3F displaceOS;
1322   worldToObj.mulV(modDisplace, &displaceOS);
1323
1324   for ( S32 i = 0; i < face.points.size(); i++ )
1325   {                  
1326      Point3F &pnt = pointList[ face.points[i] ];   
1327      pnt += displaceOS;      
1328   }
1329
1330   updateModifiedFace( shape, faceId );
1331}
1332
1333void GuiConvexEditorCtrl::updateModifiedFace( ConvexShape *shape, S32 faceId )
1334{
1335   if ( shape->mGeometry.faces.size() <= faceId )
1336      return;
1337
1338   ConvexShape::Face &face = shape->mGeometry.faces[faceId];
1339
1340   Vector< Point3F> &pointList = shape->mGeometry.points;
1341
1342   Vector< ConvexShape::Face> &faceList = shape->mGeometry.faces;
1343
1344   for ( S32 i = 0; i < faceList.size(); i++ )
1345   {
1346      ConvexShape::Face &curFace = faceList[i];      
1347      MatrixF &curSurface = shape->mSurfaces[ curFace.id ];
1348
1349      U32 curPntCount = curFace.points.size();
1350
1351      if ( curPntCount < 3 )
1352         continue;
1353
1354      // Does this face use any of the points which we have modified?
1355      // Collect them in correct winding order.
1356
1357      S32 pId0 = -1;
1358
1359      for ( S32 j = 0; j < curFace.winding.size(); j++ )
1360      {
1361         if ( face.points.contains( curFace.points[ curFace.winding[ j ] ] ) )
1362         {
1363            pId0 = j;
1364            break;
1365         }
1366      }         
1367
1368      if ( pId0 == -1 )
1369         continue;
1370
1371      S32 pId1 = -1, pId2 = -1;
1372
1373      pId1 = ( pId0 + 1 ) % curFace.winding.size();
1374      pId2 = ( pId0 + 2 ) % curFace.winding.size();
1375
1376      const Point3F &p0 = pointList[ curFace.points[ curFace.winding[ pId0 ] ] ];
1377      const Point3F &p1 = pointList[ curFace.points[ curFace.winding[ pId1 ] ] ];
1378      const Point3F &p2 = pointList[ curFace.points[ curFace.winding[ pId2 ] ] ];
1379
1380      PlaneF newPlane( p0, p1, p2 );
1381      Point3F uvec = newPlane.getNormal();
1382      Point3F fvec = curSurface.getForwardVector();
1383      Point3F rvec = curSurface.getRightVector();
1384
1385      F32 dt0 = mDot( uvec, fvec );
1386      F32 dt1 = mDot( uvec, rvec );
1387
1388      if ( mFabs( dt0 ) < mFabs( dt1 ) )
1389      {
1390         rvec = mCross( fvec, uvec );
1391         rvec.normalizeSafe();
1392         fvec = mCross( uvec, rvec );
1393         fvec.normalizeSafe();
1394      }
1395      else
1396      {
1397         fvec = mCross( uvec, rvec );
1398         fvec.normalizeSafe();
1399         rvec = mCross( fvec, uvec );
1400         rvec.normalizeSafe();
1401      }
1402
1403      curSurface.setColumn( 0, rvec );
1404      curSurface.setColumn( 1, fvec );
1405      curSurface.setColumn( 2, uvec );   
1406      curSurface.setPosition( newPlane.getPosition() );
1407   }
1408
1409   updateShape( shape );
1410}
1411
1412bool GuiConvexEditorCtrl::isShapeValid( ConvexShape *shape )
1413{
1414   // Test for no-geometry.
1415   if ( shape->mGeometry.points.empty() )
1416      return false;
1417
1418   const Vector<Point3F> &pointList = shape->mGeometry.points;
1419   const Vector<ConvexShape::Face> &faceList = shape->mGeometry.faces;
1420
1421   // Test that all points are shared by at least 3 faces.
1422
1423   for ( S32 i = 0; i < pointList.size(); i++ )
1424   {
1425      U32 counter = 0;
1426
1427      for ( S32 j = 0; j < faceList.size(); j++ )
1428      {
1429         if ( faceList[j].points.contains( i ) )
1430            counter++;
1431      }
1432
1433      if ( counter < 3 )
1434         return false;
1435   }
1436
1437   // Test for co-planar faces.
1438   for ( S32 i = 0; i < shape->mPlanes.size(); i++ )
1439   {
1440      for ( S32 j = i + 1; j < shape->mPlanes.size(); j++ )
1441      {
1442         F32 d = mDot( shape->mPlanes[i], shape->mPlanes[j] );
1443         if ( d > 0.999f )         
1444            return false;         
1445      }
1446   }
1447
1448   // Test for faces with zero or negative area.
1449   for ( S32 i = 0; i < shape->mGeometry.faces.size(); i++ )
1450   {
1451      if ( shape->mGeometry.faces[i].area < 0.0f )
1452         return false;
1453
1454      if ( shape->mGeometry.faces[i].triangles.empty() )
1455         return false;
1456   }
1457
1458   return true;
1459}
1460
1461void GuiConvexEditorCtrl::setupShape( ConvexShape *shape )
1462{
1463   shape->setField( "material", mMaterialName );
1464   shape->registerObject();
1465   updateShape( shape );
1466
1467   Scene* scene = Scene::getRootScene();
1468   if ( scene )
1469      scene->addObject( shape );
1470}
1471
1472void GuiConvexEditorCtrl::updateShape( ConvexShape *shape, S32 offsetFace )
1473{
1474   shape->_updateGeometry( true );
1475
1476   /*
1477   if ( offsetFace != -1 )
1478   {
1479      shape->mSurfaces[ offsetFace ].setPosition( mPivotPos );
1480   }*/
1481
1482   synchClientObject( shape );
1483}
1484
1485void GuiConvexEditorCtrl::synchClientObject( const ConvexShape *serverConvex )
1486{
1487   if ( serverConvex->getClientObject() )
1488   {
1489      ConvexShape *clientConvex = static_cast< ConvexShape* >( serverConvex->getClientObject() );
1490      clientConvex->setScale( serverConvex->getScale() );
1491      clientConvex->setTransform( serverConvex->getTransform() );
1492      clientConvex->mSurfaces.clear();
1493      clientConvex->mSurfaces.merge( serverConvex->mSurfaces );
1494      clientConvex->_updateGeometry(true);
1495   }
1496}
1497
1498void GuiConvexEditorCtrl::updateGizmoPos()
1499{
1500   if ( mConvexSEL )
1501   {
1502      if ( mFaceSEL != -1 )
1503      {
1504         MatrixF surfMat = mConvexSEL->getSurfaceWorldMat( mFaceSEL );  
1505
1506         MatrixF objToWorld( mConvexSEL->getTransform() );
1507         objToWorld.scale( mConvexSEL->getScale() );
1508
1509         Point3F gizmoPos(0,0,0);
1510
1511         if ( mUsingPivot )
1512         {
1513            gizmoPos = mPivotPos;
1514         }
1515         else
1516         {
1517            Point3F faceCenterPnt = mConvexSEL->mSurfaces[ mFaceSEL ].getPosition();
1518            objToWorld.mulP( faceCenterPnt );
1519
1520            mGizmoMatOffset = surfMat.getPosition() - faceCenterPnt;
1521
1522            gizmoPos = faceCenterPnt;
1523         }
1524
1525         mGizmo->set( surfMat, gizmoPos, Point3F::One );        
1526      }
1527      else
1528      {
1529         mGizmoMatOffset = Point3F::Zero;
1530         mGizmo->set( mConvexSEL->getTransform(), mConvexSEL->getPosition(), mConvexSEL->getScale() ); 
1531      }
1532   }   
1533}
1534
1535bool GuiConvexEditorCtrl::setActiveTool( ConvexEditorTool *tool )
1536{   
1537   if ( mActiveTool == tool )
1538      return false;
1539
1540   ConvexEditorTool *prevTool = mActiveTool;
1541   ConvexEditorTool *newTool = tool;
1542
1543   if ( prevTool )
1544      prevTool->onDeactivated( newTool );
1545
1546   mActiveTool = newTool;
1547
1548   if ( newTool )
1549      newTool->onActivated( prevTool );
1550
1551   return true;
1552}
1553
1554bool GuiConvexEditorCtrl::handleEscape()
1555{
1556   if ( mActiveTool )
1557   {
1558      mActiveTool->onDeactivated( NULL );
1559      mActiveTool = NULL;
1560
1561      return true;
1562   }
1563
1564   if ( mFaceSEL != -1 )
1565   {
1566      setSelection( mConvexSEL, -1 );
1567      return true;
1568   }
1569
1570   if ( mConvexSEL )
1571   {         
1572      setSelection( NULL, -1 );
1573      return true;
1574   }
1575
1576   return false;
1577}
1578
1579bool GuiConvexEditorCtrl::handleDelete()
1580{
1581   if ( mActiveTool )
1582   {
1583      mActiveTool->onDeactivated( NULL );
1584      mActiveTool = NULL;
1585   }
1586
1587   if ( mConvexSEL )
1588   {
1589      if ( mFaceSEL != -1 )
1590      {
1591         submitUndo( ModifyShape, mConvexSEL );
1592
1593         mConvexSEL->mSurfaces.erase_fast( mFaceSEL );
1594         updateShape( mConvexSEL );
1595
1596         if ( !isShapeValid( mConvexSEL ) )
1597         {
1598            S32 selFace = mFaceSEL;
1599            mLastUndo->undo();
1600            mFaceSEL = selFace;
1601            updateShape( mConvexSEL );
1602            updateGizmoPos();
1603         }
1604         else
1605         {
1606            setSelection( mConvexSEL, -1 );
1607         }
1608      }
1609      else
1610      {
1611         // Grab the mission editor undo manager.
1612         UndoManager *undoMan = NULL;
1613         if ( !Sim::findObject( "EUndoManager", undoMan ) )
1614         {            
1615            Con::errorf( "GuiConvexEditorCtrl::on3DMouseDown() - EUndoManager not found!" );    
1616         }
1617         else
1618         {
1619            // Create the UndoAction.
1620            MEDeleteUndoAction *action = new MEDeleteUndoAction("Deleted ConvexShape");
1621            action->deleteObject( mConvexSEL );
1622            mIsDirty = true;
1623            
1624            mFaceHL = -1; 
1625
1626            setSelection( NULL, -1 );
1627
1628            // Submit it.               
1629            undoMan->addAction( action );
1630         }
1631      }
1632   }
1633
1634   return true;
1635}
1636
1637bool GuiConvexEditorCtrl::hasSelection() const
1638{
1639   return mConvexSEL != NULL;   
1640}
1641
1642void GuiConvexEditorCtrl::clearSelection()
1643{
1644   mFaceHL = -1;
1645   mConvexHL = NULL;
1646   setSelection( NULL, -1 );
1647}
1648
1649void GuiConvexEditorCtrl::handleDeselect()
1650{
1651   if ( mActiveTool )
1652   {
1653      mActiveTool->onDeactivated( NULL );
1654      mActiveTool = NULL;
1655   }
1656
1657   mFaceHL = -1;
1658   mConvexHL = NULL;
1659   setSelection( NULL, -1 );
1660}
1661
1662void GuiConvexEditorCtrl::setSelection( ConvexShape *shape, S32 faceId )
1663{
1664   mFaceSEL = faceId;
1665   mConvexSEL = shape;
1666   updateGizmoPos();
1667
1668   Con::executef( this, "onSelectionChanged", shape ? shape->getIdString() : "", Con::getIntArg(faceId) );
1669}
1670
1671void GuiConvexEditorCtrl::_prepRenderImage( SceneManager* sceneGraph, const SceneRenderState* state )
1672{   
1673   if ( !isAwake() )
1674      return;
1675
1676   /*
1677   ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
1678   ri->type = RenderPassManager::RIT_Editor;
1679   ri->renderDelegate.bind( this, &GuiConvexEditorCtrl::_renderObject );
1680   ri->defaultKey = 100;
1681   state->getRenderPass()->addInst( ri );   
1682   */
1683}
1684
1685void GuiConvexEditorCtrl::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst )
1686{  
1687}
1688
1689void GuiConvexEditorCtrl::submitUndo( UndoType type, ConvexShape *shape )
1690{
1691   Vector< ConvexShape*> shapes;
1692   shapes.push_back( shape );
1693   submitUndo( type, shapes );
1694}
1695
1696void GuiConvexEditorCtrl::submitUndo( UndoType type, const Vector<ConvexShape*> &shapes )
1697{   
1698   // Grab the mission editor undo manager.
1699   Sim::findObject( "EUndoManager", mUndoManager );   
1700   
1701   if ( !mUndoManager )   
1702   {
1703      Con::errorf( "GuiConvexEditorCtrl::submitUndo() - EUndoManager not found!" );
1704      return;           
1705   }
1706
1707   if ( type == ModifyShape )
1708   {
1709      // Setup the action.
1710      GuiConvexEditorUndoAction *action = new GuiConvexEditorUndoAction( "Modified a ConvexShape" );
1711
1712      ConvexShape *shape = shapes.first();
1713
1714      action->mObjId = shape->getId();   
1715      action->mEditor = this;   
1716      action->mSavedObjToWorld = shape->getTransform();
1717      action->mSavedScale = shape->getScale();
1718      action->mSavedSurfaces.merge( shape->mSurfaces );             
1719      action->mUndoManager = mUndoManager;
1720
1721      mUndoManager->addAction( action );
1722
1723      mLastUndo = action;
1724   }
1725   else if ( type == CreateShape )
1726   {
1727      MECreateUndoAction *action = new MECreateUndoAction( "Create ConvexShape" );
1728
1729      for ( S32 i = 0; i < shapes.size(); i++ )
1730         action->addObject( shapes[i] );
1731         
1732      mUndoManager->addAction( action );
1733      
1734      mLastUndo = action;
1735   }
1736   else if ( type == DeleteShape )
1737   {
1738      MEDeleteUndoAction *action = new MEDeleteUndoAction( "Deleted ConvexShape" );
1739
1740      for ( S32 i = 0; i < shapes.size(); i++ )
1741         action->deleteObject( shapes[i] );         
1742
1743      mUndoManager->addAction( action );
1744
1745      mLastUndo = action;
1746   }
1747   else if ( type == HollowShape )
1748   {
1749      CompoundUndoAction *action = new CompoundUndoAction( "Hollow ConvexShape" );
1750
1751      MECreateUndoAction *createAction = new MECreateUndoAction();
1752      MEDeleteUndoAction *deleteAction = new MEDeleteUndoAction();
1753
1754      deleteAction->deleteObject( shapes.first() );
1755      
1756      for ( S32 i = 1; i < shapes.size(); i++ )      
1757         createAction->addObject( shapes[i] );
1758      
1759      action->addAction( deleteAction );
1760      action->addAction( createAction );
1761
1762      mUndoManager->addAction( action );
1763
1764      mLastUndo = action;
1765   }
1766
1767   mIsDirty = true;
1768}
1769
1770bool GuiConvexEditorCtrl::_cursorCastCallback( RayInfo* ri )
1771{
1772   // Reject anything that's not a ConvexShape.
1773   return dynamic_cast< ConvexShape* >( ri->object );
1774}
1775
1776bool GuiConvexEditorCtrl::_cursorCast( const Gui3DMouseEvent &event, ConvexShape **hitShape, S32 *hitFace )
1777{
1778   RayInfo ri;
1779   
1780   if ( gServerContainer.castRay( event.pos, event.pos + event.vec * 10000.0f, StaticShapeObjectType, &ri, &GuiConvexEditorCtrl::_cursorCastCallback ) &&
1781        dynamic_cast< ConvexShape* >( ri.object ) )
1782   {
1783      // Do not select or edit ConvexShapes that are within a Prefab.
1784      if ( Prefab::getPrefabByChild( ri.object ) )
1785         return false;
1786
1787      *hitShape = static_cast< ConvexShape* >( ri.object );
1788      *hitFace = ri.face;
1789      mLastRayInfo = ri;
1790
1791      return true;
1792   }
1793
1794   return false;
1795}
1796
1797void GuiConvexEditorCtrl::setPivotPos( ConvexShape *shape, S32 faceId, const Gui3DMouseEvent &event )
1798{
1799   PlaneF plane;
1800   mTransformPlane( shape->getTransform(), shape->getScale(), shape->mPlanes[ faceId ], &plane );
1801
1802   Point3F start( event.pos );
1803   Point3F end( start + event.vec * 10000.0f );
1804
1805   F32 t = plane.intersect( start, end );
1806
1807   if ( t >= 0.0f && t <= 1.0f )
1808   {
1809      Point3F hitPos;
1810      hitPos.interpolate( start, end, t );
1811
1812      mPivotPos = hitPos;
1813      mUsingPivot = true;
1814
1815      MatrixF worldToObj( shape->getTransform() );
1816      worldToObj.scale( shape->getScale() );
1817      worldToObj.inverse();
1818
1819      Point3F objPivotPos( mPivotPos );
1820      worldToObj.mulP( objPivotPos );
1821
1822      updateGizmoPos();
1823   }
1824}
1825
1826void GuiConvexEditorCtrl::cleanMatrix( MatrixF &mat )
1827{
1828   if ( mat.isAffine() )
1829      return;
1830
1831   VectorF col0 = mat.getColumn3F(0);
1832   VectorF col1 = mat.getColumn3F(1);
1833   VectorF col2 = mat.getColumn3F(2);
1834
1835   col0.normalize();
1836   col1.normalize();
1837   col2.normalize();
1838
1839   col2 = mCross( col0, col1 );
1840   col2.normalize();
1841   col1 = mCross( col2, col0 );
1842   col1.normalize();
1843   col0 = mCross( col1, col2 );
1844   col0.normalize();
1845
1846   mat.setColumn(0,col0);
1847   mat.setColumn(1,col1);
1848   mat.setColumn(2,col2);
1849
1850   AssertFatal( mat.isAffine(), "GuiConvexEditorCtrl::cleanMatrix, non-affine matrix" );
1851}
1852
1853S32 GuiConvexEditorCtrl::getEdgeByPoints( ConvexShape *shape, S32 faceId, S32 p0, S32 p1 )
1854{
1855   const ConvexShape::Face &face = shape->mGeometry.faces[faceId];
1856
1857   for ( S32 i = 0; i < face.edges.size(); i++ )
1858   {
1859      const ConvexShape::Edge &edge = face.edges[i];
1860
1861      if ( edge.p0 != p0 && edge.p0 != p1 )
1862         continue;
1863      if ( edge.p1 != p0 && edge.p1 != p1 )
1864         continue;
1865
1866      return i;      
1867   }
1868
1869   return -1;
1870}
1871
1872bool GuiConvexEditorCtrl::getEdgesTouchingPoint( ConvexShape *shape, S32 faceId, S32 pId, Vector< U32> &edgeIdxList, S32 excludeEdge )
1873{
1874   const ConvexShape::Face &face = shape->mGeometry.faces[faceId];   
1875   const Vector< ConvexShape::Edge> &edgeList = face.edges;
1876
1877   for ( S32 i = 0; i < edgeList.size(); i++ )
1878   {
1879      if ( i == excludeEdge )
1880         continue;
1881
1882      const ConvexShape::Edge &curEdge = edgeList[i];
1883
1884      if ( curEdge.p0 == pId || curEdge.p1 == pId )      
1885         edgeIdxList.push_back(i);
1886   }
1887
1888   return !edgeIdxList.empty();
1889}
1890
1891Point2F GuiConvexEditorCtrl::getSelectedFaceUVOffset()
1892{
1893   if (mFaceSEL == -1 || mConvexSEL == NULL)
1894      return Point2F(0, 0);
1895
1896   return mConvexSEL->mSurfaceUVs[mFaceSEL].offset;
1897}
1898
1899Point2F GuiConvexEditorCtrl::getSelectedFaceUVScale()
1900{
1901   if (mFaceSEL == -1 || mConvexSEL == NULL)
1902      return Point2F(0, 0);
1903
1904   return mConvexSEL->mSurfaceUVs[mFaceSEL].scale;
1905}
1906
1907const char* GuiConvexEditorCtrl::getSelectedFaceMaterial()
1908{
1909   if (mFaceSEL == -1 || mConvexSEL == NULL)
1910      return "";
1911
1912   if (mConvexSEL->mSurfaceUVs[mFaceSEL].matID == 0)
1913   {
1914      return mConvexSEL->mMaterialName;
1915   }
1916   else
1917   {
1918      return mConvexSEL->mSurfaceTextures[mConvexSEL->mSurfaceUVs[mFaceSEL].matID - 1].materialName;
1919   }
1920}
1921
1922bool GuiConvexEditorCtrl::getSelectedFaceHorzFlip()
1923{
1924   if (mFaceSEL == -1 || mConvexSEL == NULL)
1925      return false;
1926
1927   return mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip;
1928}
1929
1930bool GuiConvexEditorCtrl::getSelectedFaceVertFlip()
1931{
1932   if (mFaceSEL == -1 || mConvexSEL == NULL)
1933      return false;
1934
1935   return mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip;
1936}
1937
1938float GuiConvexEditorCtrl::getSelectedFaceZRot()
1939{
1940   if (mFaceSEL == -1 || mConvexSEL == NULL)
1941      return false;
1942
1943   return mConvexSEL->mSurfaceUVs[mFaceSEL].zRot;
1944}
1945
1946void GuiConvexEditorCtrl::setSelectedFaceUVOffset(Point2F offset)
1947{
1948   if (mFaceSEL == -1 || mConvexSEL == NULL)
1949      return;
1950
1951   mConvexSEL->mSurfaceUVs[mFaceSEL].offset = offset;
1952
1953   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
1954}
1955
1956void GuiConvexEditorCtrl::setSelectedFaceUVScale(Point2F scale)
1957{
1958   if (mFaceSEL == -1 || mConvexSEL == NULL)
1959      return;
1960
1961   mConvexSEL->mSurfaceUVs[mFaceSEL].scale = scale;
1962
1963   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
1964}
1965
1966void GuiConvexEditorCtrl::setSelectedFaceMaterial(const char* materialName)
1967{
1968   if (mFaceSEL == -1 || mConvexSEL == NULL)
1969      return;
1970
1971   if (mConvexSEL->mSurfaceUVs.size() < mFaceSEL)
1972      return;
1973
1974   //first, see if the mat already exists in our list
1975   bool found = false;
1976   U32 oldmatID = mConvexSEL->mSurfaceUVs[mFaceSEL].matID;
1977
1978   if (String::compare(materialName, mConvexSEL->getMaterialName().c_str()))
1979   {
1980      for (U32 i = 0; i < mConvexSEL->mSurfaceTextures.size(); i++)
1981      {
1982         if (!String::compare(mConvexSEL->mSurfaceTextures[i].materialName, materialName))
1983         {
1984            //found a match
1985            mConvexSEL->mSurfaceUVs[mFaceSEL].matID = i + 1;
1986            found = true;
1987         }
1988      }
1989
1990      if (!found)
1991      {
1992         //add a new one
1993         ConvexShape::surfaceMaterial newMat;
1994         newMat.materialName = materialName;
1995
1996         mConvexSEL->mSurfaceTextures.push_back(newMat);
1997
1998         mConvexSEL->mSurfaceUVs[mFaceSEL].matID = mConvexSEL->mSurfaceTextures.size();
1999      }
2000   }
2001   else
2002   {
2003      mConvexSEL->mSurfaceUVs[mFaceSEL].matID = 0;
2004   }
2005
2006   //run through and find out if there are any other faces still using the old mat texture
2007   if (oldmatID != 0)
2008   {
2009      S32 curMatCount = mConvexSEL->mSurfaceTextures.size();
2010
2011      bool used = false;
2012      for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++)
2013      {
2014         if (mConvexSEL->mSurfaceUVs[i].matID == oldmatID)
2015         {
2016            used = true;
2017            break;
2018         }
2019      }
2020
2021      if (!used)
2022      {
2023         //that was the last reference, so let's update the listings on the shape
2024         if (mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst)
2025            SAFE_DELETE(mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst);
2026
2027         mConvexSEL->mSurfaceTextures.erase(oldmatID-1);
2028
2029         for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++)
2030         {
2031            if (mConvexSEL->mSurfaceUVs[i].matID > oldmatID)
2032               mConvexSEL->mSurfaceUVs[i].matID--;
2033         }
2034      }
2035   }
2036
2037   //mConvexSEL->mSurfaceUVs[mFaceSEL].materialName = materialName;
2038
2039   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
2040}
2041
2042void GuiConvexEditorCtrl::setSelectedFaceHorzFlip(bool flipped)
2043{
2044   if (mFaceSEL == -1 || mConvexSEL == NULL)
2045      return;
2046
2047   mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip = flipped;
2048
2049   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
2050}
2051
2052void GuiConvexEditorCtrl::setSelectedFaceVertFlip(bool flipped)
2053{
2054   if (mFaceSEL == -1 || mConvexSEL == NULL)
2055      return;
2056
2057   mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip = flipped;
2058
2059   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
2060}
2061
2062void GuiConvexEditorCtrl::setSelectedFaceZRot(float degrees)
2063{
2064   if (mFaceSEL == -1 || mConvexSEL == NULL)
2065      return;
2066
2067   F32 oldRot = mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot);
2068   mConvexSEL->mSurfaceUVs[mFaceSEL].zRot = degrees;
2069
2070   EulerF curEul = mConvexSEL->mSurfaces[mFaceSEL].toEuler();
2071
2072   MatrixF oldRotMat = MatrixF(EulerF(0, 0, -oldRot));
2073
2074   mConvexSEL->mSurfaces[mFaceSEL].mul(oldRotMat);
2075
2076   MatrixF newRotMat = MatrixF(EulerF(0, 0, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)));
2077
2078   mConvexSEL->mSurfaces[mFaceSEL].mul(newRotMat);
2079
2080   //Point3F curPos = mConvexSEL->mSurfaces[mFaceSEL].getPosition();
2081
2082   //we roll back our existing modified rotation before setting the new one, just to keep it consistent
2083   //const MatrixF &gMat = MatrixF(EulerF(curEul.x, curEul.y, curEul.z - oldRot + mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos);
2084
2085   //mConvexSEL->mSurfaces[mFaceSEL] = MatrixF(EulerF(curEul.x, curEul.y, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos);
2086
2087   /*MatrixF surfMat;
2088   surfMat.mul(mConvexSEL->mWorldToObj, gMat);
2089
2090   MatrixF worldToObj(mConvexSEL->getTransform());
2091   worldToObj.scale(mConvexSEL->getScale());
2092   worldToObj.inverse();
2093
2094   Point3F newPos;
2095   newPos = gMat.getPosition();
2096
2097   worldToObj.mulP(newPos);
2098   surfMat.setPosition(newPos);
2099
2100   // Clear out floating point errors.
2101   cleanMatrix(surfMat);
2102
2103   mConvexSEL->mSurfaces[mFaceSEL] = surfMat;*/
2104
2105   updateShape(mConvexSEL, mFaceSEL);
2106
2107   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
2108
2109   /*
2110   const MatrixF &gMat = mGizmo->getTransform();
2111   MatrixF surfMat;
2112   surfMat.mul( mConvexSEL->mWorldToObj, gMat );
2113
2114   MatrixF worldToObj ( mConvexSEL->getTransform() );
2115   worldToObj.scale( mConvexSEL->getScale() );
2116   worldToObj.inverse();
2117
2118   Point3F newPos;
2119   newPos = gMat.getPosition();
2120
2121   worldToObj.mulP( newPos );
2122   surfMat.setPosition( newPos );
2123
2124   // Clear out floating point errors.
2125   cleanMatrix( surfMat );
2126
2127   if (mGizmo->getSelection() == Gizmo::Axis_Z)
2128   {
2129   MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL];
2130   EulerF curSufRot = curSurfMat.toEuler();
2131
2132   EulerF newSufRot = surfMat.toEuler();
2133
2134   float zRot = mRadToDeg(newSufRot.z - curSufRot.z);
2135
2136   float curZRot = mConvexSEL->mSurfaceTextures[mFaceSEL].zRot;
2137
2138   mConvexSEL->mSurfaceTextures[mFaceSEL].zRot += zRot;
2139   }
2140
2141   mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
2142
2143   updateShape( mConvexSEL, mFaceSEL );
2144   */
2145}
2146
2147void GuiConvexEditorCtrl::toggleGridSnapping()
2148{
2149   if (mGridSnap)
2150      mGridSnap = false;
2151   else
2152      mGridSnap = true;
2153}
2154
2155void GuiConvexEditorCtrl::updateShape()
2156{
2157   if (mConvexSEL)
2158      mConvexSEL->inspectPostApply();
2159}
2160
2161void GuiConvexEditorCtrl::setGridSnapSize(float gridSize)
2162{
2163   mGridPlaneSize = gridSize;
2164}
2165
2166void GuiConvexEditorUndoAction::undo()
2167{
2168   ConvexShape *object = NULL;
2169   if ( !Sim::findObject( mObjId, object ) )
2170      return;
2171
2172   // Temporarily save the ConvexShape current data.   
2173   Vector< MatrixF> tempSurfaces;   
2174   tempSurfaces.merge( object->mSurfaces );
2175   MatrixF tempObjToWorld( object->getTransform() );
2176   Point3F tempScale( object->getScale() );
2177
2178   // Restore the Object to the UndoAction state.
2179   object->mSurfaces.clear();
2180   object->mSurfaces.merge( mSavedSurfaces );   
2181   object->setScale( mSavedScale );
2182   object->setTransform( mSavedObjToWorld );
2183
2184   // Regenerate the ConvexShape and synch the client object.
2185   object->_updateGeometry();
2186   GuiConvexEditorCtrl::synchClientObject( object );
2187
2188   // If applicable set the selected ConvexShape and face
2189   // on the editor.   
2190   mEditor->setSelection( object, -1 );
2191   mEditor->updateGizmoPos();
2192
2193   // Now save the previous ConvexShape data in this UndoAction
2194   // since an undo action must become a redo action and vice-versa
2195   
2196   mSavedObjToWorld = tempObjToWorld;
2197   mSavedScale = tempScale;
2198   mSavedSurfaces.clear();
2199   mSavedSurfaces.merge( tempSurfaces );   
2200}
2201
2202ConvexEditorCreateTool::ConvexEditorCreateTool( GuiConvexEditorCtrl *editor )
2203 : Parent( editor ),
2204   mStage( -1 ),
2205   mNewConvex( NULL )
2206{
2207}
2208
2209void ConvexEditorCreateTool::onActivated( ConvexEditorTool *prevTool )
2210{
2211   mEditor->clearSelection();
2212   mStage = -1;
2213   mNewConvex = NULL;
2214}
2215
2216void ConvexEditorCreateTool::onDeactivated( ConvexEditorTool *newTool )
2217{
2218   if ( mNewConvex )
2219      mNewConvex->deleteObject();
2220
2221   mStage = -1;
2222   mNewConvex = NULL;
2223   mEditor->mouseUnlock();
2224}
2225
2226ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseDown( const Gui3DMouseEvent &event )
2227{
2228   if ( mStage == -1 )
2229   {
2230      mEditor->setFirstResponder();
2231      mEditor->mouseLock();
2232
2233      Point3F start( event.pos );
2234      Point3F end( event.pos + event.vec * 10000.0f );      
2235      RayInfo ri;
2236      
2237      bool hit = gServerContainer.castRay( event.pos, end, STATIC_COLLISION_TYPEMASK, &ri );
2238
2239      MatrixF objMat( true );
2240
2241      // Calculate the orientation matrix of the new ConvexShape
2242      // based on what has been clicked.
2243
2244      if ( !hit )
2245      {
2246         objMat.setPosition( event.pos + event.vec * 100.0f );      
2247      }
2248      else
2249      {
2250         if ( dynamic_cast< ConvexShape* >( ri.object ) )
2251         {
2252            ConvexShape *hitShape = static_cast< ConvexShape* >( ri.object );
2253            objMat = hitShape->getSurfaceWorldMat( ri.face );
2254            objMat.setPosition( ri.point );
2255         }
2256         else
2257         {
2258            Point3F rvec;
2259            Point3F fvec( mEditor->getCameraMat().getForwardVector() );
2260            Point3F uvec( ri.normal );
2261
2262            rvec = mCross( fvec, uvec );
2263
2264            if ( rvec.isZero() )
2265            {
2266               fvec = mEditor->getCameraMat().getRightVector();
2267               rvec = mCross( fvec, uvec );
2268            }
2269
2270            rvec.normalizeSafe();
2271            fvec = mCross( uvec, rvec );
2272            fvec.normalizeSafe();
2273            uvec = mCross( rvec, fvec );
2274            uvec.normalizeSafe();
2275
2276            objMat.setColumn( 0, rvec );
2277            objMat.setColumn( 1, fvec );
2278            objMat.setColumn( 2, uvec );
2279
2280            objMat.setPosition( ri.point );
2281         }
2282      }
2283
2284      mNewConvex = new ConvexShape();                       
2285
2286      mNewConvex->setTransform( objMat );   
2287      
2288      mNewConvex->setField( "material", Parent::mEditor->mMaterialName );
2289      
2290      mNewConvex->registerObject();
2291      mPlaneSizes.set( 0.1f, 0.1f, 0.1f );
2292      mNewConvex->resizePlanes( mPlaneSizes );
2293      mEditor->updateShape( mNewConvex );
2294      
2295      mTransform = objMat;     
2296
2297      mCreatePlane.set( objMat.getPosition(), objMat.getUpVector() );
2298   }
2299   else if ( mStage == 0 )
2300   {
2301      // Handle this on mouseUp
2302   }
2303   
2304   return Handled;
2305}
2306
2307ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseUp( const Gui3DMouseEvent &event )
2308{
2309   if ( mNewConvex && mStage == -1 )
2310   {
2311      mStage = 0;      
2312
2313      mCreatePlane = PlaneF( mNewConvex->getPosition(), mNewConvex->getTransform().getForwardVector() );
2314
2315      mTransform.setPosition( mNewConvex->getPosition() );      
2316
2317      return Handled;
2318   }
2319   else if ( mStage == 0 )
2320   {
2321      SimGroup *scene = Scene::getRootScene();
2322      scene->addObject( mNewConvex );
2323
2324      mStage = -1;
2325
2326      // Grab the mission editor undo manager.
2327      UndoManager *undoMan = NULL;
2328      if ( !Sim::findObject( "EUndoManager", undoMan ) )
2329      {
2330         Con::errorf( "ConvexEditorCreateTool::on3DMouseDown() - EUndoManager not found!" );
2331         mNewConvex = NULL;
2332         return Failed;           
2333      }
2334
2335      // Create the UndoAction.
2336      MECreateUndoAction *action = new MECreateUndoAction("Create ConvexShape");
2337      action->addObject( mNewConvex );
2338
2339      // Submit it.               
2340      undoMan->addAction( action );
2341
2342      mEditor->setField( "isDirty", "1" );
2343
2344      mEditor->setSelection( mNewConvex, -1 );      
2345
2346      mNewConvex = NULL;
2347
2348      mEditor->mouseUnlock();
2349
2350      return Done;
2351   }
2352
2353   return Done;
2354}
2355
2356ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseMove( const Gui3DMouseEvent &event )
2357{
2358   if ( mStage == 0 )
2359   {
2360      Point3F start( event.pos );
2361      Point3F end( start + event.vec * 10000.0f );
2362      
2363      F32 t = mCreatePlane.intersect( start, end );
2364
2365      Point3F hitPos;
2366
2367      if ( t < 0.0f || t > 1.0f )
2368         return Handled;
2369
2370      hitPos.interpolate( start, end, t );      
2371
2372      MatrixF worldToObj( mTransform );
2373      worldToObj.inverse();
2374      worldToObj.mulP( hitPos );
2375
2376      F32 delta = ( hitPos.z );
2377
2378      mPlaneSizes.z = getMax( 0.1f, delta );
2379
2380      mNewConvex->resizePlanes( mPlaneSizes );
2381
2382      mEditor->updateShape( mNewConvex );
2383
2384      Point3F pos( mTransform.getPosition() );
2385      pos += mPlaneSizes.z * 0.5f * mTransform.getUpVector();
2386      mNewConvex->setPosition( pos );
2387   }
2388
2389   return Handled;
2390}
2391
2392ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseDragged( const Gui3DMouseEvent &event )
2393{
2394   if ( !mNewConvex || mStage != -1 )
2395      return Handled;
2396
2397   Point3F start( event.pos );
2398   Point3F end( event.pos + event.vec * 10000.0f );
2399
2400   F32 t = mCreatePlane.intersect( start, end );
2401
2402   if ( t < 0.0f || t > 1.0f )
2403      return Handled;
2404
2405   Point3F hitPos;
2406   hitPos.interpolate( start, end, t );
2407   
2408   MatrixF xfm( mTransform );
2409   xfm.inverse();      
2410   xfm.mulP( hitPos);      
2411   
2412   Point3F scale;
2413   scale.x = getMax( mFabs( hitPos.x ), 0.1f );
2414   scale.y = getMax( mFabs( hitPos.y ), 0.1f );
2415   scale.z = 0.1f;
2416
2417   mNewConvex->resizePlanes( scale );
2418   mPlaneSizes = scale;
2419   mEditor->updateShape( mNewConvex );   
2420
2421   Point3F pos( mTransform.getPosition() );
2422   pos += mTransform.getRightVector() * hitPos.x * 0.5f;
2423   pos += mTransform.getForwardVector() * hitPos.y * 0.5f;
2424
2425   mNewConvex->setPosition( pos );
2426
2427   return Handled;
2428}
2429
2430void ConvexEditorCreateTool::renderScene( const RectI &updateRect )
2431{
2432  
2433}
2434
2435ConvexShape* ConvexEditorCreateTool::extrudeShapeFromFace( ConvexShape *inShape, S32 inFaceId )
2436{
2437   ConvexShape::Geometry &inShapeGeometry = inShape->getGeometry();
2438   ConvexShape::Face &inFace = inShapeGeometry.faces[inFaceId];
2439   Vector< Point3F> &inShapePointList = inShapeGeometry.points;
2440   Vector< MatrixF> &inShapeSurfaces = inShape->getSurfaces();
2441   
2442   S32 shapeFaceCount = inFace.edges.size() + 2;   
2443   
2444   MatrixF inShapeToWorld( inShape->getTransform() );
2445   inShapeToWorld.scale( inShape->getScale() );
2446   //MatrixF inWorldToShape( inShapeToWorld );
2447   //inWorldToShape.inverse();
2448
2449   MatrixF shapeToWorld;
2450   shapeToWorld.mul( inShape->getTransform(), inShapeSurfaces[inFaceId] );
2451   Point3F tmp( inShapeSurfaces[inFaceId].getPosition() );
2452   inShapeToWorld.mulP( tmp );
2453   shapeToWorld.setPosition( tmp );
2454   MatrixF worldToShape( shapeToWorld );
2455   worldToShape.inverse();
2456
2457   MatrixF inShapeToNewShape;
2458   inShapeToNewShape.mul( inShapeToWorld, worldToShape );   
2459
2460   ConvexShape *newShape = new ConvexShape;   
2461   newShape->setTransform( shapeToWorld );   
2462
2463   Vector< MatrixF> &shapeSurfaces = newShape->getSurfaces();
2464   shapeSurfaces.setSize( shapeFaceCount );
2465   //shapeSurfaces.setSize( 2 );
2466
2467   const Point3F &shapePos = shapeToWorld.getPosition();
2468   
2469   shapeSurfaces[0].identity();
2470   shapeSurfaces[1].identity();   
2471   shapeSurfaces[1].setColumn( 0, -shapeSurfaces[1].getColumn3F(0) );
2472   shapeSurfaces[1].setColumn( 2, -shapeSurfaces[1].getColumn3F(2) );
2473
2474   for ( S32 i = 0; i < inFace.winding.size(); i++ )
2475   {      
2476      Point3F p0 = inShapePointList[ inFace.points[ inFace.winding[ i ] ] ];
2477      Point3F p1;
2478      
2479      if ( i+1 < inFace.winding.size() )
2480         p1 = inShapePointList[ inFace.points[ inFace.winding[ i+1 ] ] ];
2481      else
2482         p1 = inShapePointList[ inFace.points[ inFace.winding[ 0 ] ] ];
2483
2484      inShapeToWorld.mulP( p0 );
2485      inShapeToWorld.mulP( p1 );
2486
2487      Point3F newPos = MathUtils::mClosestPointOnSegment( p0, p1, shapePos );      
2488
2489      Point3F rvec = p0 - p1;
2490      rvec.normalizeSafe();
2491
2492      Point3F fvec = shapeToWorld.getUpVector();
2493
2494      Point3F uvec = mCross( rvec, fvec );      
2495
2496      if ( i + 2 >= shapeSurfaces.size() )
2497         continue;
2498      
2499      //F32 dt = mDot( shapeToWorld.getUpVector(), rvec );
2500      //AssertFatal( mIsZero( dt ), "bad" );
2501      
2502      MatrixF &surf = shapeSurfaces[i+2];
2503      surf.identity();
2504      surf.setColumn( 0, rvec );
2505      surf.setColumn( 1, fvec );
2506      surf.setColumn( 2, uvec );
2507      surf.setPosition( newPos );
2508
2509      surf.mulL( worldToShape );      
2510   }
2511
2512   //newShape->setField( "material", Parent::mEditor->mMaterialName );
2513   newShape->setField("material", inShape->getMaterialName());
2514
2515   newShape->registerObject();
2516   mEditor->updateShape( newShape );
2517
2518   Scene* scene = Scene::getRootScene();
2519   if ( scene )
2520      scene->addObject( newShape );
2521
2522   return newShape;
2523}
2524
2525void GuiConvexEditorCtrl::hollowShape( ConvexShape *shape, F32 thickness )
2526{
2527   // Create a new Convex for each face of the original shape.
2528   // This is the same as an extrude from face operation going inward by the thickness
2529   // for every face.
2530
2531   Vector< ConvexShape*> convexList;
2532
2533   for ( S32 i = 0; i < shape->mGeometry.faces.size(); i++ )
2534   {
2535      ConvexShape *faceShape = mCreateTool->extrudeShapeFromFace( shape, i );
2536      MatrixF &inwardFace = faceShape->mSurfaces[1];
2537      //MatrixF &outwardFace = faceShape->mSurfaces[0];      
2538
2539      Point3F invec = inwardFace.getUpVector();
2540
2541      inwardFace.setPosition( inwardFace.getPosition() + invec * thickness );
2542
2543      updateShape( faceShape );
2544
2545      convexList.push_back( faceShape );
2546   }
2547
2548   convexList.push_front( shape );
2549   submitUndo( HollowShape, convexList );   
2550}
2551
2552void GuiConvexEditorCtrl::hollowSelection()
2553{
2554   if ( mConvexSEL )
2555   {
2556      hollowShape( mConvexSEL, 0.15f );
2557      setSelection( NULL, -1 );      
2558   }
2559}
2560
2561void GuiConvexEditorCtrl::recenterSelection()
2562{
2563   if ( mConvexSEL )    
2564   {
2565      recenterShape( mConvexSEL );   
2566      updateGizmoPos();
2567   }
2568}
2569
2570void GuiConvexEditorCtrl::recenterShape( ConvexShape *shape )
2571{
2572   submitUndo( ModifyShape, shape );
2573   shape->recenter();
2574   synchClientObject( shape );
2575}
2576
2577void GuiConvexEditorCtrl::dropSelectionAtScreenCenter()
2578{
2579   // This code copied from WorldEditor.
2580   // All the dropping code would be moved to somewhere common, but its not.
2581
2582   if ( !mConvexSEL )
2583      return;
2584
2585   // Calculate the center of the screen (in global screen coordinates)
2586   Point2I offset = localToGlobalCoord(Point2I(0,0));
2587   Point3F sp(F32(offset.x + F32(getExtent().x / 2)), F32(offset.y + (getExtent().y / 2)), 1.0f);
2588
2589   // Calculate the view distance to fit the selection
2590   // within the camera's view.
2591   const Box3F bounds = mConvexSEL->getWorldBox();
2592   F32 radius = bounds.len()*0.5f;
2593   F32 viewdist = calculateViewDistance(radius);
2594
2595   // Be careful of infinite sized objects, or just large ones in general.
2596   if(viewdist > 100.0f )
2597      viewdist = 100.0f;
2598
2599   // Position the selection   
2600   mConvexSEL->setPosition( smCamPos + smCamMatrix.getForwardVector() * viewdist );
2601
2602   synchClientObject( mConvexSEL );
2603
2604   updateGizmoPos();
2605}
2606
2607void GuiConvexEditorCtrl::splitSelectedFace()
2608{
2609   if ( !mConvexSEL || mFaceSEL == -1 )
2610      return;
2611
2612   if ( !isShapeValid( mConvexSEL ) )
2613      return;
2614
2615   mLastValidShape = mConvexSEL->mSurfaces;
2616
2617   const F32 radians = mDegToRad( 15.0f );
2618   Point3F rot( 0, 0, 0 );
2619   MatrixF rotMat( true );
2620
2621   mConvexSEL->mSurfaces.increment();
2622   MatrixF &dstMat = mConvexSEL->mSurfaces.last();   
2623   const MatrixF &srcMat = mConvexSEL->mSurfaces[mFaceSEL];
2624
2625   for ( S32 i = 0; i < 6; i++ )
2626   {
2627      F32 sign = i > 2 ? -1.0f : 1.0f;
2628      U32 idx = i % 3;
2629
2630      rot.zero();
2631      rot[idx] = sign * radians;
2632      rotMat.set( (EulerF)rot );
2633
2634      dstMat = srcMat * rotMat;
2635
2636      updateShape( mConvexSEL );
2637
2638      if ( isShapeValid( mConvexSEL ) )
2639      {
2640         mSavedSurfaces = mConvexSEL->mSurfaces;
2641         mConvexSEL->mSurfaces = mLastValidShape;
2642
2643         submitUndo( ModifyShape, mConvexSEL );  
2644
2645         mConvexSEL->mSurfaces = mSavedSurfaces;
2646         mLastValidShape = mSavedSurfaces;
2647
2648         setSelection( mConvexSEL, mConvexSEL->mSurfaces.size() - 1 );
2649
2650         return;
2651      }      
2652   }
2653
2654   mConvexSEL->mSurfaces = mLastValidShape;
2655   updateShape( mConvexSEL );
2656   updateGizmoPos();
2657}
2658
2659SceneObject* GuiConvexEditorCtrl::createPolyhedralObject(const char* className, SceneObject* geometryProvider)
2660{
2661   if (!geometryProvider)
2662   {
2663      Con::errorf("WorldEditor::createPolyhedralObject - Invalid geometry provider!");
2664      return NULL;
2665   }
2666
2667   if (!className || !className[0])
2668   {
2669      Con::errorf("WorldEditor::createPolyhedralObject - Invalid class name");
2670      return NULL;
2671   }
2672
2673   AbstractClassRep* classRep = AbstractClassRep::findClassRep(className);
2674   if (!classRep)
2675   {
2676      Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", className);
2677      return NULL;
2678   }
2679
2680   // We don't want the extracted poly list to be affected by the object's
2681   // current transform and scale so temporarily reset them.
2682
2683   MatrixF savedTransform = geometryProvider->getTransform();
2684   Point3F savedScale = geometryProvider->getScale();
2685
2686   geometryProvider->setTransform(MatrixF::Identity);
2687   geometryProvider->setScale(Point3F(1.f, 1.f, 1.f));
2688
2689   // Extract the geometry.  Use the object-space bounding volumes
2690   // as we have moved the object to the origin for the moment.
2691
2692   OptimizedPolyList polyList;
2693   if (!geometryProvider->buildPolyList(PLC_Export, &polyList, geometryProvider->getObjBox(), geometryProvider->getObjBox().getBoundingSphere()))
2694   {
2695      Con::errorf("WorldEditor::createPolyhedralObject - Failed to extract geometry!");
2696      return NULL;
2697   }
2698
2699   // Restore the object's original transform.
2700
2701   geometryProvider->setTransform(savedTransform);
2702   geometryProvider->setScale(savedScale);
2703
2704   // Create the object.
2705
2706   SceneObject* object = dynamic_cast< SceneObject* >(classRep->create());
2707   if (!Object)
2708   {
2709      Con::errorf("WorldEditor::createPolyhedralObject - Could not create SceneObject with class '%s'", className);
2710      return NULL;
2711   }
2712
2713   // Convert the polylist to a polyhedron.
2714
2715   Polyhedron polyhedron = polyList.toPolyhedron();
2716
2717   // Add the vertex data.
2718
2719   const U32 numPoints = polyhedron.getNumPoints();
2720   const Point3F* points = polyhedron.getPoints();
2721
2722   for (U32 i = 0; i < numPoints; ++i)
2723   {
2724      static StringTableEntry sPoint = StringTable->insert("point");
2725      object->setDataField(sPoint, NULL, EngineMarshallData(points[i]));
2726   }
2727
2728   // Add the plane data.
2729
2730   const U32 numPlanes = polyhedron.getNumPlanes();
2731   const PlaneF* planes = polyhedron.getPlanes();
2732
2733   for (U32 i = 0; i < numPlanes; ++i)
2734   {
2735      static StringTableEntry sPlane = StringTable->insert("plane");
2736      const PlaneF& plane = planes[i];
2737
2738      char buffer[1024];
2739      dSprintf(buffer, sizeof(buffer), "%g %g %g %g", plane.x, plane.y, plane.z, plane.d);
2740
2741      object->setDataField(sPlane, NULL, buffer);
2742   }
2743
2744   // Add the edge data.
2745
2746   const U32 numEdges = polyhedron.getNumEdges();
2747   const Polyhedron::Edge* edges = polyhedron.getEdges();
2748
2749   for (U32 i = 0; i < numEdges; ++i)
2750   {
2751      static StringTableEntry sEdge = StringTable->insert("edge");
2752      const Polyhedron::Edge& edge = edges[i];
2753
2754      char buffer[1024];
2755      dSprintf(buffer, sizeof(buffer), "%i %i %i %i ",
2756         edge.face[0], edge.face[1],
2757         edge.vertex[0], edge.vertex[1]
2758      );
2759
2760      object->setDataField(sEdge, NULL, buffer);
2761   }
2762
2763   // Set the transform.
2764
2765   object->setTransform(savedTransform);
2766   object->setScale(savedScale);
2767
2768   // Register and return the object.
2769
2770   if (!object->registerObject())
2771   {
2772      Con::errorf("WorldEditor::createPolyhedralObject - Failed to register object!");
2773      delete object;
2774      return NULL;
2775   }
2776
2777   return object;
2778}
2779
2780ConvexShape* GuiConvexEditorCtrl::createConvexShapeFrom(SceneObject* polyObject)
2781{
2782   if (!polyObject)
2783   {
2784      Con::errorf("WorldEditor::createConvexShapeFrom - Invalid object");
2785      return NULL;
2786   }
2787
2788   IScenePolyhedralObject* iPoly = dynamic_cast< IScenePolyhedralObject* >(polyObject);
2789   if (!iPoly)
2790   {
2791      Con::errorf("WorldEditor::createConvexShapeFrom - Not a polyhedral object!");
2792      return NULL;
2793   }
2794
2795   // Get polyhedron.
2796
2797   AnyPolyhedron polyhedron = iPoly->ToAnyPolyhedron();
2798   const U32 numPlanes = polyhedron.getNumPlanes();
2799   if (!numPlanes)
2800   {
2801      Con::errorf("WorldEditor::createConvexShapeFrom - Object returned no valid polyhedron");
2802      return NULL;
2803   }
2804
2805   // Create a ConvexShape.
2806
2807   ConvexShape* shape = new ConvexShape();
2808
2809   // Add all planes.
2810
2811   for (U32 i = 0; i < numPlanes; ++i)
2812   {
2813      const PlaneF& plane = polyhedron.getPlanes()[i];
2814
2815      // Polyhedron planes are facing inwards so we need to
2816      // invert the normal here.
2817
2818      Point3F normal = plane.getNormal();
2819      normal.neg();
2820
2821      // Turn the orientation of the plane into a quaternion.
2822      // The normal is our up vector (that's what's expected
2823      // by ConvexShape for the surface orientation).
2824
2825      MatrixF orientation(true);
2826      MathUtils::getMatrixFromUpVector(normal, &orientation);
2827      const QuatF quat(orientation);
2828
2829      // Get the plane position.
2830
2831      const Point3F position = plane.getPosition();
2832
2833      // Turn everything into a "surface" property for the ConvexShape.
2834
2835      char buffer[1024];
2836      dSprintf(buffer, sizeof(buffer), "%g %g %g %g %g %g %g",
2837         quat.x, quat.y, quat.z, quat.w,
2838         position.x, position.y, position.z
2839      );
2840
2841      // Add the surface.
2842
2843      static StringTableEntry sSurface = StringTable->insert("surface");
2844      shape->setDataField(sSurface, NULL, buffer);
2845   }
2846
2847   // Copy the transform.
2848
2849   shape->setTransform(polyObject->getTransform());
2850   shape->setScale(polyObject->getScale());
2851
2852   // Register the shape.
2853
2854   if (!shape->registerObject())
2855   {
2856      Con::errorf("WorldEditor::createConvexShapeFrom - Could not register ConvexShape!");
2857      delete shape;
2858      return NULL;
2859   }
2860
2861   return shape;
2862}
2863
2864DefineEngineMethod( GuiConvexEditorCtrl, hollowSelection, void, (), , "" )
2865{
2866   object->hollowSelection();
2867}
2868
2869DefineEngineMethod( GuiConvexEditorCtrl, recenterSelection, void, (), , "" )
2870{
2871   object->recenterSelection();
2872}
2873
2874DefineEngineMethod( GuiConvexEditorCtrl, hasSelection, S32, (), , "" )
2875{
2876   return object->hasSelection();
2877}
2878
2879DefineEngineMethod( GuiConvexEditorCtrl, handleDelete, void, (), , "" )
2880{
2881   object->handleDelete();
2882}
2883
2884DefineEngineMethod( GuiConvexEditorCtrl, handleDeselect, void, (), , "" )
2885{
2886   object->handleDeselect();
2887}
2888
2889DefineEngineMethod( GuiConvexEditorCtrl, dropSelectionAtScreenCenter, void, (), , "" )
2890{
2891   object->dropSelectionAtScreenCenter();
2892}
2893
2894DefineEngineMethod( GuiConvexEditorCtrl, selectConvex, void, (ConvexShape *convex), , "( ConvexShape )" )
2895{
2896if (convex)
2897      object->setSelection( convex, -1 );
2898}
2899
2900DefineEngineMethod( GuiConvexEditorCtrl, splitSelectedFace, void, (), , "" )
2901{
2902   object->splitSelectedFace();
2903}
2904
2905DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVOffset, Point2F, (), ,
2906   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2907
2908   "@param objB  Object to mount onto us\n"
2909   "@param slot  Mount slot ID\n"
2910   "@param txfm (optional) mount offset transform\n"
2911   "@return true if successful, false if failed (objB is not valid)")
2912{
2913   //return Point2F(0, 0);
2914   return object->getSelectedFaceUVOffset();
2915}
2916
2917DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVScale, Point2F, (), ,
2918   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2919
2920   "@param objB  Object to mount onto us\n"
2921   "@param slot  Mount slot ID\n"
2922   "@param txfm (optional) mount offset transform\n"
2923   "@return true if successful, false if failed (objB is not valid)")
2924{
2925   //return Point2F(0, 0);
2926   return object->getSelectedFaceUVScale();
2927}
2928
2929DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVOffset, void, ( Point2F offset ), ( Point2F(0,0) ),
2930   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2931
2932   "@param objB  Object to mount onto us\n"
2933   "@param slot  Mount slot ID\n"
2934   "@param txfm (optional) mount offset transform\n"
2935   "@return true if successful, false if failed (objB is not valid)")
2936{
2937   //return Point2F(0, 0);
2938   return object->setSelectedFaceUVOffset(offset);
2939}
2940
2941DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVScale, void, (Point2F scale), (Point2F(0, 0)),
2942   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2943
2944   "@param objB  Object to mount onto us\n"
2945   "@param slot  Mount slot ID\n"
2946   "@param txfm (optional) mount offset transform\n"
2947   "@return true if successful, false if failed (objB is not valid)")
2948{
2949   //return Point2F(0, 0);
2950   return object->setSelectedFaceUVScale(scale);
2951}
2952
2953DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceMaterial, void, (const char* materialName), (""),
2954   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2955
2956   "@param objB  Object to mount onto us\n"
2957   "@param slot  Mount slot ID\n"
2958   "@param txfm (optional) mount offset transform\n"
2959   "@return true if successful, false if failed (objB is not valid)")
2960{
2961   //return Point2F(0, 0);
2962   if (!String::compare(materialName, ""))
2963      return;
2964
2965   object->setSelectedFaceMaterial(materialName);
2966}
2967
2968DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceMaterial, const char*, (), ,
2969   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2970
2971   "@param objB  Object to mount onto us\n"
2972   "@param slot  Mount slot ID\n"
2973   "@param txfm (optional) mount offset transform\n"
2974   "@return true if successful, false if failed (objB is not valid)")
2975{
2976   return object->getSelectedFaceMaterial();
2977}
2978
2979DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceHorzFlip, void, (bool flipped), (false),
2980   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2981
2982   "@param objB  Object to mount onto us\n"
2983   "@param slot  Mount slot ID\n"
2984   "@param txfm (optional) mount offset transform\n"
2985   "@return true if successful, false if failed (objB is not valid)")
2986{
2987   object->setSelectedFaceHorzFlip(flipped);
2988}
2989
2990DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceVertFlip, void, (bool flipped), (false),
2991   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
2992
2993   "@param objB  Object to mount onto us\n"
2994   "@param slot  Mount slot ID\n"
2995   "@param txfm (optional) mount offset transform\n"
2996   "@return true if successful, false if failed (objB is not valid)")
2997{
2998   object->setSelectedFaceVertFlip(flipped);
2999}
3000
3001DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceHorzFlip, bool, (), ,
3002   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3003
3004   "@param objB  Object to mount onto us\n"
3005   "@param slot  Mount slot ID\n"
3006   "@param txfm (optional) mount offset transform\n"
3007   "@return true if successful, false if failed (objB is not valid)")
3008{
3009   return object->getSelectedFaceHorzFlip();
3010}
3011
3012DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceVertFlip, bool, (), ,
3013   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3014
3015   "@param objB  Object to mount onto us\n"
3016   "@param slot  Mount slot ID\n"
3017   "@param txfm (optional) mount offset transform\n"
3018   "@return true if successful, false if failed (objB is not valid)")
3019{
3020   return object->getSelectedFaceVertFlip();
3021}
3022
3023DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceZRot, void, (float degrees), (0.0),
3024   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3025
3026   "@param objB  Object to mount onto us\n"
3027   "@param slot  Mount slot ID\n"
3028   "@param txfm (optional) mount offset transform\n"
3029   "@return true if successful, false if failed (objB is not valid)")
3030{
3031   object->setSelectedFaceZRot(degrees);
3032}
3033
3034DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceZRot, float, (), ,
3035   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3036
3037   "@param objB  Object to mount onto us\n"
3038   "@param slot  Mount slot ID\n"
3039   "@param txfm (optional) mount offset transform\n"
3040   "@return true if successful, false if failed (objB is not valid)")
3041{
3042   return object->getSelectedFaceZRot();
3043}
3044
3045DefineEngineMethod(GuiConvexEditorCtrl, toggleGridSnapping, void, (),,
3046   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3047
3048   "@param objB  Object to mount onto us\n"
3049   "@param slot  Mount slot ID\n"
3050   "@param txfm (optional) mount offset transform\n"
3051   "@return true if successful, false if failed (objB is not valid)")
3052{
3053   object->toggleGridSnapping();
3054}
3055
3056DefineEngineMethod(GuiConvexEditorCtrl, setGridSnapSize, void, (float gridSize), (1.0),
3057   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3058
3059   "@param objB  Object to mount onto us\n"
3060   "@param slot  Mount slot ID\n"
3061   "@param txfm (optional) mount offset transform\n"
3062   "@return true if successful, false if failed (objB is not valid)")
3063{
3064   object->setGridSnapSize(gridSize);
3065}
3066
3067DefineEngineMethod(GuiConvexEditorCtrl, getGridSnapSize, float, (),,
3068   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3069
3070   "@param objB  Object to mount onto us\n"
3071   "@param slot  Mount slot ID\n"
3072   "@param txfm (optional) mount offset transform\n"
3073   "@return true if successful, false if failed (objB is not valid)")
3074{
3075   return object->getGridSnapSize();
3076}
3077
3078DefineEngineMethod(GuiConvexEditorCtrl, updateShape, void, (),,
3079   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
3080
3081   "@param objB  Object to mount onto us\n"
3082   "@param slot  Mount slot ID\n"
3083   "@param txfm (optional) mount offset transform\n"
3084   "@return true if successful, false if failed (objB is not valid)")
3085{
3086   //return Point2F(0, 0);
3087   return object->updateShape();
3088}
3089