guiConvexShapeEditorCtrl.cpp
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp
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