guiConvexShapeEditorCtrl.cpp 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gui/worldEditor/guiConvexShapeEditorCtrl.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/engineAPI.h"
  26. #include "T3D/convexShape.h"
  27. #include "renderInstance/renderPassManager.h"
  28. #include "collision/collision.h"
  29. #include "math/util/frustum.h"
  30. #include "math/mathUtils.h"
  31. #include "gfx/gfxPrimitiveBuffer.h"
  32. #include "gfx/gfxTextureHandle.h"
  33. #include "gfx/gfxTransformSaver.h"
  34. #include "gfx/primBuilder.h"
  35. #include "gfx/gfxDrawUtil.h"
  36. #include "scene/sceneRenderState.h"
  37. #include "scene/sceneManager.h"
  38. #include "gui/core/guiCanvas.h"
  39. #include "gui/buttons/guiButtonCtrl.h"
  40. #include "gui/worldEditor/undoActions.h"
  41. #include "T3D/gameBase/gameConnection.h"
  42. #include "gfx/sim/debugDraw.h"
  43. #include "collision/optimizedPolyList.h"
  44. #include "core/volume.h"
  45. #include "gui/worldEditor/worldEditor.h"
  46. #include "T3D/prefab.h"
  47. IMPLEMENT_CONOBJECT( GuiConvexEditorCtrl );
  48. ConsoleDocClass( GuiConvexEditorCtrl,
  49. "@brief The base class for the sketch tool\n\n"
  50. "Editor use only.\n\n"
  51. "@internal"
  52. );
  53. GuiConvexEditorCtrl::GuiConvexEditorCtrl()
  54. : mIsDirty( false ),
  55. mFaceHL( -1 ),
  56. mFaceSEL( -1 ),
  57. mFaceSavedXfm( true ),
  58. mSavedUndo( false ),
  59. mDragging( false ),
  60. mGizmoMatOffset( Point3F::Zero ),
  61. mPivotPos( Point3F::Zero ),
  62. mUsingPivot( false ),
  63. mSettingPivot( false ),
  64. mActiveTool( NULL ),
  65. mCreateTool( NULL ),
  66. mMouseDown( false ),
  67. mUndoManager( NULL ),
  68. mLastUndo( NULL ),
  69. mHasCopied( false ),
  70. mSavedGizmoFlags( -1 ),
  71. mCtrlDown( false )
  72. {
  73. mMaterialName = StringTable->insert("Grid512_OrangeLines_Mat");
  74. }
  75. GuiConvexEditorCtrl::~GuiConvexEditorCtrl()
  76. {
  77. }
  78. bool GuiConvexEditorCtrl::onAdd()
  79. {
  80. if ( !Parent::onAdd() )
  81. return false;
  82. SceneManager::getPreRenderSignal().notify( this, &GuiConvexEditorCtrl::_prepRenderImage );
  83. mCreateTool = new ConvexEditorCreateTool( this );
  84. return true;
  85. }
  86. void GuiConvexEditorCtrl::onRemove()
  87. {
  88. SceneManager::getPreRenderSignal().remove( this, &GuiConvexEditorCtrl::_prepRenderImage );
  89. SAFE_DELETE( mCreateTool );
  90. Parent::onRemove();
  91. }
  92. void GuiConvexEditorCtrl::initPersistFields()
  93. {
  94. addField( "isDirty", TypeBool, Offset( mIsDirty, GuiConvexEditorCtrl ) );
  95. addField( "materialName", TypeString, Offset(mMaterialName, GuiConvexEditorCtrl) );
  96. Parent::initPersistFields();
  97. }
  98. bool GuiConvexEditorCtrl::onWake()
  99. {
  100. if ( !Parent::onWake() )
  101. return false;
  102. SimGroup *missionGroup;
  103. if ( !Sim::findObject( "MissionGroup", missionGroup ) )
  104. return true;
  105. SimGroup::iterator itr = missionGroup->begin();
  106. for ( ; itr != missionGroup->end(); itr++ )
  107. {
  108. if ( dStrcmp( (*itr)->getClassName(), "ConvexShape" ) == 0 )
  109. {
  110. mConvexSEL = static_cast<ConvexShape*>( *itr );
  111. mGizmo->set( mConvexSEL->getTransform(), mConvexSEL->getPosition(), mConvexSEL->getScale() );
  112. return true;
  113. }
  114. }
  115. return true;
  116. }
  117. void GuiConvexEditorCtrl::onSleep()
  118. {
  119. Parent::onSleep();
  120. mConvexSEL = NULL;
  121. mConvexHL = NULL;
  122. }
  123. void GuiConvexEditorCtrl::setVisible( bool val )
  124. {
  125. //ConvexShape::smRenderEdges = value;
  126. if ( isProperlyAdded() )
  127. {
  128. if ( !val )
  129. {
  130. mFaceHL = -1;
  131. mConvexHL = NULL;
  132. setSelection( NULL, -1 );
  133. if ( mSavedGizmoFlags != -1 )
  134. {
  135. mGizmoProfile->flags = mSavedGizmoFlags;
  136. mSavedGizmoFlags = -1;
  137. }
  138. }
  139. else
  140. {
  141. mConvexHL = NULL;
  142. mFaceHL = -1;
  143. setSelection( NULL, -1 );
  144. WorldEditor *wedit;
  145. if ( Sim::findObject( "EWorldEditor", wedit ) )
  146. {
  147. S32 count = wedit->getSelectionSize();
  148. for ( S32 i = 0; i < count; i++ )
  149. {
  150. S32 objId = wedit->getSelectObject(i);
  151. ConvexShape *pShape;
  152. if ( Sim::findObject( objId, pShape ) )
  153. {
  154. mConvexSEL = pShape;
  155. wedit->clearSelection();
  156. wedit->selectObject( String::ToString("%i",objId) );
  157. break;
  158. }
  159. }
  160. }
  161. updateGizmoPos();
  162. mSavedGizmoFlags = mGizmoProfile->flags;
  163. }
  164. }
  165. Parent::setVisible( val );
  166. }
  167. void GuiConvexEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
  168. {
  169. mouseLock();
  170. mMouseDown = true;
  171. if ( event.modifier & SI_ALT )
  172. {
  173. setActiveTool( mCreateTool );
  174. mActiveTool->on3DMouseDown( event );
  175. return;
  176. }
  177. if ( mConvexSEL && isShapeValid( mConvexSEL ) )
  178. mLastValidShape = mConvexSEL->mSurfaces;
  179. if ( mConvexSEL &&
  180. mFaceSEL != -1 &&
  181. mGizmo->getMode() == RotateMode &&
  182. mGizmo->getSelection() == Gizmo::Centroid )
  183. {
  184. mSettingPivot = true;
  185. mSavedPivotPos = mGizmo->getPosition();
  186. setPivotPos( mConvexSEL, mFaceSEL, event );
  187. updateGizmoPos();
  188. return;
  189. }
  190. mGizmo->on3DMouseDown( event );
  191. }
  192. void GuiConvexEditorCtrl::on3DRightMouseDown(const Gui3DMouseEvent & event)
  193. {
  194. return;
  195. /*
  196. if ( mConvexSEL && mFaceSEL != -1 && mFaceSEL == mFaceHL )
  197. {
  198. _submitUndo( "Split ConvexShape face." );
  199. const MatrixF &surf = mConvexSEL->mSurfaces[mFaceSEL];
  200. MatrixF newSurf( surf );
  201. MatrixF rotMat( EulerF( 0.0f, mDegToRad( 2.0f ), 0.0f ) );
  202. newSurf *= rotMat;
  203. mConvexSEL->mSurfaces.insert( mFaceSEL+1, newSurf );
  204. }
  205. */
  206. }
  207. void GuiConvexEditorCtrl::on3DRightMouseUp(const Gui3DMouseEvent & event)
  208. {
  209. //ConvexShape *hitShape;
  210. //S32 hitFace;
  211. //bool hit = _cursorCast( event, &hitShape, &hitFace );
  212. //Con::printf( hit ? "HIT" : "MISS" );
  213. }
  214. void GuiConvexEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
  215. {
  216. mouseUnlock();
  217. mMouseDown = false;
  218. mHasCopied = false;
  219. mHasGeometry = false;
  220. if ( mActiveTool )
  221. {
  222. ConvexEditorTool::EventResult result = mActiveTool->on3DMouseUp( event );
  223. if ( result == ConvexEditorTool::Done )
  224. setActiveTool( NULL );
  225. return;
  226. }
  227. if ( !mSettingPivot && !mDragging && ( mGizmo->getSelection() == Gizmo::None || !mConvexSEL ) )
  228. {
  229. if ( mConvexSEL != mConvexHL )
  230. {
  231. setSelection( mConvexHL, -1 );
  232. }
  233. else
  234. {
  235. if ( mFaceSEL != mFaceHL )
  236. setSelection( mConvexSEL, mFaceHL );
  237. else
  238. setSelection( mConvexSEL, -1 );
  239. }
  240. mUsingPivot = false;
  241. }
  242. mSettingPivot = false;
  243. mSavedPivotPos = mGizmo->getPosition();
  244. mSavedUndo = false;
  245. mGizmo->on3DMouseUp( event );
  246. if ( mDragging )
  247. {
  248. mDragging = false;
  249. if ( mConvexSEL )
  250. {
  251. Vector< U32 > removedPlanes;
  252. mConvexSEL->cullEmptyPlanes( &removedPlanes );
  253. // If a face has been removed we need to validate / remap
  254. // our selected and highlighted faces.
  255. if ( !removedPlanes.empty() )
  256. {
  257. S32 prevFaceHL = mFaceHL;
  258. S32 prevFaceSEL = mFaceSEL;
  259. if ( removedPlanes.contains( mFaceHL ) )
  260. prevFaceHL = mFaceHL = -1;
  261. if ( removedPlanes.contains( mFaceSEL ) )
  262. prevFaceSEL = mFaceSEL = -1;
  263. for ( S32 i = 0; i < removedPlanes.size(); i++ )
  264. {
  265. if ( (S32)removedPlanes[i] < prevFaceSEL )
  266. mFaceSEL--;
  267. if ( (S32)removedPlanes[i] < prevFaceHL )
  268. mFaceHL--;
  269. }
  270. setSelection( mConvexSEL, mFaceSEL );
  271. // We need to reindex faces.
  272. updateShape( mConvexSEL );
  273. }
  274. }
  275. }
  276. updateGizmoPos();
  277. }
  278. void GuiConvexEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
  279. {
  280. if ( mActiveTool )
  281. {
  282. // If we have an active tool pass this event to it.
  283. // If it handled it, consume the event.
  284. if ( mActiveTool->on3DMouseMove( event ) )
  285. return;
  286. }
  287. ConvexShape *hitShape = NULL;
  288. S32 hitFace = -1;
  289. _cursorCast( event, &hitShape, &hitFace );
  290. if ( !mConvexSEL )
  291. {
  292. mConvexHL = hitShape;
  293. mFaceHL = -1;
  294. }
  295. else
  296. {
  297. if ( mConvexSEL == hitShape )
  298. {
  299. mConvexHL = hitShape;
  300. mFaceHL = hitFace;
  301. }
  302. else
  303. {
  304. // Mousing over a shape that is not the one currently selected.
  305. if ( mFaceSEL != -1 )
  306. {
  307. mFaceHL = -1;
  308. }
  309. else
  310. {
  311. mConvexHL = hitShape;
  312. mFaceHL = -1;
  313. }
  314. }
  315. }
  316. if ( mConvexSEL )
  317. mGizmo->on3DMouseMove( event );
  318. }
  319. void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
  320. {
  321. if ( mActiveTool )
  322. {
  323. // If we have an active tool pass this event to it.
  324. // If it handled it, consume the event.
  325. if ( mActiveTool->on3DMouseDragged( event ) )
  326. return;
  327. }
  328. //mGizmoProfile->rotateScalar = 0.55f;
  329. //mGizmoProfile->scaleScalar = 0.55f;
  330. if ( !mConvexSEL )
  331. return;
  332. if ( mGizmo->getMode() == RotateMode &&
  333. mGizmo->getSelection() == Gizmo::Centroid )
  334. {
  335. setPivotPos( mConvexSEL, mFaceSEL, event );
  336. mDragging = true;
  337. return;
  338. }
  339. mGizmo->on3DMouseDragged( event );
  340. if ( event.modifier & SI_SHIFT &&
  341. ( mGizmo->getMode() == MoveMode || mGizmo->getMode() == RotateMode ) &&
  342. !mHasCopied )
  343. {
  344. if ( mFaceSEL != -1 )
  345. {
  346. ConvexShape *newShape = mCreateTool->extrudeShapeFromFace( mConvexSEL, mFaceSEL );
  347. //newShape->_updateGeometry();
  348. submitUndo( CreateShape, newShape );
  349. setSelection( newShape, 0 );
  350. updateGizmoPos();
  351. mGizmo->on3DMouseDown( event );
  352. mHasCopied = true;
  353. mSavedUndo = true;
  354. }
  355. else
  356. {
  357. ConvexShape *newShape = new ConvexShape();
  358. newShape->setTransform( mConvexSEL->getTransform() );
  359. newShape->setScale( mConvexSEL->getScale() );
  360. newShape->mSurfaces.clear();
  361. newShape->mSurfaces.merge( mConvexSEL->mSurfaces );
  362. setupShape( newShape );
  363. submitUndo( CreateShape, newShape );
  364. setSelection( newShape, -1 );
  365. updateGizmoPos();
  366. mHasCopied = true;
  367. mSavedUndo = true;
  368. }
  369. return;
  370. }
  371. if ( mGizmo->getMode() == RotateMode &&
  372. event.modifier & SI_CTRL &&
  373. !mHasCopied &&
  374. mFaceSEL != -1 )
  375. {
  376. // Can must verify that splitting the face at the current angle
  377. // ( of the gizmo ) will generate a valid shape. If not enough rotation
  378. // has occurred we will have two faces that are coplanar and must wait
  379. // until later in the drag to perform the split.
  380. //AssertFatal( isShapeValid( mConvexSEL ), "Shape was already invalid at beginning of split operation." );
  381. if ( !isShapeValid( mConvexSEL ) )
  382. return;
  383. mLastValidShape = mConvexSEL->mSurfaces;
  384. Point3F rot = mGizmo->getDeltaTotalRot();
  385. rot.normalize();
  386. rot *= mDegToRad( 10.0f );
  387. MatrixF rotMat( (EulerF)rot );
  388. MatrixF worldToObj( mConvexSEL->getTransform() );
  389. worldToObj.scale( mConvexSEL->getScale() );
  390. worldToObj.inverse();
  391. mConvexSEL->mSurfaces.increment();
  392. MatrixF &newSurf = mConvexSEL->mSurfaces.last();
  393. newSurf = mConvexSEL->mSurfaces[mFaceSEL] * rotMat;
  394. //worldToObj.mul( mGizmo->getTransform() );
  395. //Point3F pos( mPivotPos );
  396. //worldToObj.mulP( pos );
  397. //newSurf.setPosition( pos );
  398. updateShape( mConvexSEL );
  399. if ( !isShapeValid( mConvexSEL ) )
  400. {
  401. mConvexSEL->mSurfaces = mLastValidShape;
  402. updateShape( mConvexSEL );
  403. }
  404. else
  405. {
  406. mHasCopied = true;
  407. mSavedUndo = true;
  408. mLastValidShape = mConvexSEL->mSurfaces;
  409. submitUndo( ModifyShape, mConvexSEL );
  410. setSelection( mConvexSEL, mConvexSEL->mSurfaces.size() - 1 );
  411. updateGizmoPos();
  412. }
  413. return;
  414. }
  415. // If we are dragging, but no gizmo selection...
  416. // Then treat this like a regular mouse move, update the highlighted
  417. // convex/face under the cursor and handle onMouseUp as we normally would
  418. // to change the selection.
  419. if ( mGizmo->getSelection() == Gizmo::None )
  420. {
  421. ConvexShape *hitShape = NULL;
  422. S32 hitFace = -1;
  423. _cursorCast( event, &hitShape, &hitFace );
  424. mFaceHL = hitFace;
  425. mConvexHL = hitShape;
  426. return;
  427. }
  428. mDragging = true;
  429. // Manipulating a face.
  430. if ( mFaceSEL != -1 )
  431. {
  432. if ( !mSavedUndo )
  433. {
  434. mSavedUndo = true;
  435. submitUndo( ModifyShape, mConvexSEL );
  436. }
  437. if ( mGizmo->getMode() == ScaleMode )
  438. {
  439. scaleFace( mConvexSEL, mFaceSEL, mGizmo->getScale() );
  440. }
  441. else
  442. {
  443. // Why does this have to be so ugly.
  444. if ( mGizmo->getMode() == RotateMode ||
  445. ( mGizmo->getMode() == MoveMode &&
  446. ( event.modifier & SI_CTRL ||
  447. ( mGizmo->getSelection() == Gizmo::Axis_Z && mHasCopied )
  448. )
  449. )
  450. )
  451. {
  452. const MatrixF &gMat = mGizmo->getTransform();
  453. MatrixF surfMat;
  454. surfMat.mul( mConvexSEL->mWorldToObj, gMat );
  455. MatrixF worldToObj ( mConvexSEL->getTransform() );
  456. worldToObj.scale( mConvexSEL->getScale() );
  457. worldToObj.inverse();
  458. Point3F newPos;
  459. newPos = gMat.getPosition();
  460. worldToObj.mulP( newPos );
  461. surfMat.setPosition( newPos );
  462. // Clear out floating point errors.
  463. cleanMatrix( surfMat );
  464. mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
  465. updateShape( mConvexSEL, mFaceSEL );
  466. }
  467. else
  468. {
  469. // Translating a face in x/y/z
  470. translateFace( mConvexSEL, mFaceSEL, mGizmo->getTotalOffset() );
  471. }
  472. }
  473. if ( isShapeValid( mConvexSEL ) )
  474. {
  475. AssertFatal( mConvexSEL->mSurfaces.size() > mFaceSEL, "mFaceSEL out of range." );
  476. mLastValidShape = mConvexSEL->mSurfaces;
  477. }
  478. else
  479. {
  480. AssertFatal( mLastValidShape.size() > mFaceSEL, "mFaceSEL out of range." );
  481. mConvexSEL->mSurfaces = mLastValidShape;
  482. updateShape( mConvexSEL );
  483. }
  484. return;
  485. }
  486. // Manipulating a whole Convex.
  487. if ( !mSavedUndo )
  488. {
  489. mSavedUndo = true;
  490. submitUndo( ModifyShape, mConvexSEL );
  491. }
  492. if ( mGizmo->getMode() == MoveMode )
  493. {
  494. mConvexSEL->setPosition( mGizmo->getPosition() );
  495. }
  496. else if ( mGizmo->getMode() == RotateMode )
  497. {
  498. mConvexSEL->setTransform( mGizmo->getTransform() );
  499. }
  500. else
  501. {
  502. mConvexSEL->setScale( mGizmo->getScale() );
  503. }
  504. if ( mConvexSEL->getClientObject() )
  505. {
  506. ConvexShape *clientObj = static_cast< ConvexShape* >( mConvexSEL->getClientObject() );
  507. clientObj->setTransform( mConvexSEL->getTransform() );
  508. clientObj->setScale( mConvexSEL->getScale() );
  509. }
  510. }
  511. void GuiConvexEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event)
  512. {
  513. }
  514. void GuiConvexEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
  515. {
  516. }
  517. bool GuiConvexEditorCtrl::onKeyDown( const GuiEvent &evt )
  518. {
  519. bool handled = false;
  520. switch ( evt.keyCode )
  521. {
  522. case KEY_ESCAPE:
  523. handled = handleEscape();
  524. break;
  525. case KEY_A:
  526. if ( evt.modifier & SI_ALT )
  527. {
  528. GizmoAlignment align = mGizmo->getProfile()->alignment;
  529. if ( align == World )
  530. mGizmo->getProfile()->alignment = Object;
  531. else
  532. mGizmo->getProfile()->alignment = World;
  533. handled = true;
  534. }
  535. break;
  536. case KEY_LCONTROL:
  537. //mCtrlDown = true;
  538. break;
  539. default:
  540. break;
  541. }
  542. return handled;
  543. }
  544. bool GuiConvexEditorCtrl::onKeyUp( const GuiEvent &evt )
  545. {
  546. bool handled = false;
  547. switch ( evt.keyCode )
  548. {
  549. case KEY_LCONTROL:
  550. //mCtrlDown = false;
  551. break;
  552. default:
  553. break;
  554. }
  555. return handled;
  556. }
  557. void GuiConvexEditorCtrl::get3DCursor( GuiCursor *&cursor,
  558. bool &visible,
  559. const Gui3DMouseEvent &event_ )
  560. {
  561. //cursor = mAddNodeCursor;
  562. //visible = false;
  563. cursor = NULL;
  564. visible = false;
  565. GuiCanvas *root = getRoot();
  566. if ( !root )
  567. return;
  568. S32 currCursor = PlatformCursorController::curArrow;
  569. if ( root->mCursorChanged == currCursor )
  570. return;
  571. PlatformWindow *window = root->getPlatformWindow();
  572. PlatformCursorController *controller = window->getCursorController();
  573. // We've already changed the cursor,
  574. // so set it back before we change it again.
  575. if( root->mCursorChanged != -1)
  576. controller->popCursor();
  577. // Now change the cursor shape
  578. controller->pushCursor(currCursor);
  579. root->mCursorChanged = currCursor;
  580. }
  581. void GuiConvexEditorCtrl::updateGizmo()
  582. {
  583. mGizmoProfile->restoreDefaultState();
  584. const GizmoMode &mode = mGizmoProfile->mode;
  585. S32 &flags = mGizmoProfile->flags;
  586. GizmoAlignment &align = mGizmoProfile->alignment;
  587. U8 keys = Input::getModifierKeys();
  588. mCtrlDown = keys & ( SI_LCTRL | SI_LSHIFT );
  589. bool altDown = keys & ( SI_LALT );
  590. if ( altDown )
  591. {
  592. flags = 0;
  593. return;
  594. }
  595. if ( mFaceSEL != -1 )
  596. {
  597. align = Object;
  598. flags |= GizmoProfile::CanRotateUniform;
  599. flags &= ~GizmoProfile::CanRotateScreen;
  600. }
  601. else
  602. {
  603. flags &= ~GizmoProfile::CanRotateUniform;
  604. flags |= GizmoProfile::CanRotateScreen;
  605. }
  606. if ( mFaceSEL != -1 && mode == ScaleMode )
  607. flags &= ~GizmoProfile::CanScaleZ;
  608. else
  609. flags |= GizmoProfile::CanScaleZ;
  610. if ( mFaceSEL != -1 && mode == MoveMode )
  611. {
  612. if ( mCtrlDown )
  613. flags &= ~( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );
  614. else
  615. flags |= ( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );
  616. }
  617. }
  618. void GuiConvexEditorCtrl::renderScene(const RectI & updateRect)
  619. {
  620. // Synch selected ConvexShape with the WorldEditor.
  621. WorldEditor *wedit;
  622. if ( Sim::findObject( "EWorldEditor", wedit) )
  623. {
  624. S32 count = wedit->getSelectionSize();
  625. if ( !mConvexSEL && count != 0 )
  626. wedit->clearSelection();
  627. else if ( mConvexSEL && count != 1 )
  628. {
  629. wedit->clearSelection();
  630. wedit->selectObject( mConvexSEL->getIdString() );
  631. }
  632. else if ( mConvexSEL && count == 1 )
  633. {
  634. if ( wedit->getSelectObject(0) != mConvexSEL->getId() )
  635. {
  636. wedit->clearSelection();
  637. wedit->selectObject( mConvexSEL->getIdString() );
  638. }
  639. }
  640. }
  641. // Update status bar text.
  642. SimObject *statusbar;
  643. if ( Sim::findObject( "EditorGuiStatusBar", statusbar ) )
  644. {
  645. String text( "Sketch Tool." );
  646. GizmoMode mode = mGizmo->getMode();
  647. if ( mMouseDown && mGizmo->getSelection() != Gizmo::None && mConvexSEL )
  648. {
  649. Point3F delta;
  650. String qualifier;
  651. if ( mode == RotateMode )
  652. {
  653. if ( mSettingPivot )
  654. delta = mGizmo->getPosition() - mSavedPivotPos;
  655. else
  656. delta = mGizmo->getDeltaTotalRot();
  657. }
  658. else if ( mode == MoveMode )
  659. delta = mGizmo->getTotalOffset();
  660. else if ( mode == ScaleMode )
  661. delta = mGizmo->getDeltaTotalScale();
  662. if ( mGizmo->getAlignment() == Object &&
  663. mode != ScaleMode )
  664. {
  665. mConvexSEL->mWorldToObj.mulV( delta );
  666. if ( mFaceSEL != -1 && mode != RotateMode )
  667. {
  668. MatrixF objToSurf( mConvexSEL->mSurfaces[ mFaceSEL ] );
  669. objToSurf.scale( mConvexSEL->getScale() );
  670. objToSurf.inverse();
  671. objToSurf.mulV( delta );
  672. }
  673. }
  674. if ( mIsZero( delta.x, 0.0001f ) )
  675. delta.x = 0.0f;
  676. if ( mIsZero( delta.y, 0.0001f ) )
  677. delta.y = 0.0f;
  678. if ( mIsZero( delta.z, 0.0001f ) )
  679. delta.z = 0.0f;
  680. if ( mode == RotateMode )
  681. {
  682. if ( mSettingPivot )
  683. text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
  684. else
  685. {
  686. delta.x = mRadToDeg( delta.x );
  687. delta.y = mRadToDeg( delta.y );
  688. delta.z = mRadToDeg( delta.z );
  689. text = String::ToString( "Delta angle ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
  690. }
  691. }
  692. else if ( mode == MoveMode )
  693. text = String::ToString( "Delta position ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
  694. else if ( mode == ScaleMode )
  695. text = String::ToString( "Delta scale ( x: %4.2f, y: %4.2f, z: %4.2f ).", delta.x, delta.y, delta.z );
  696. }
  697. else
  698. {
  699. if ( !mConvexSEL )
  700. text = "Sketch Tool. ALT + Click-Drag to create a new ConvexShape.";
  701. else if ( mFaceSEL == -1 )
  702. {
  703. if ( mode == MoveMode )
  704. text = "Move selection. SHIFT while dragging duplicates objects.";
  705. else if ( mode == RotateMode )
  706. text = "Rotate selection.";
  707. else if ( mode == ScaleMode )
  708. text = "Scale selection.";
  709. }
  710. else
  711. {
  712. if ( mode == MoveMode )
  713. text = "Move face. SHIFT while beginning a drag EXTRUDES a new convex. Press CTRL for alternate translation mode.";
  714. else if ( mode == RotateMode )
  715. text = "Rotate face. Gizmo/Pivot is draggable. CTRL while dragging splits/folds a new face. SHIFT while dragging extrudes a new convex.";
  716. else if ( mode == ScaleMode )
  717. text = "Scale face.";
  718. }
  719. }
  720. // Issue a warning in the status bar
  721. // if this convex has an excessive number of surfaces...
  722. if ( mConvexSEL && mConvexSEL->getSurfaces().size() > ConvexShape::smMaxSurfaces )
  723. {
  724. text = "WARNING: Reduce the number of surfaces on the selected ConvexShape, only the first 100 will be saved!";
  725. }
  726. Con::executef( statusbar, "setInfo", text.c_str() );
  727. Con::executef( statusbar, "setSelectionObjectsByCount", Con::getIntArg( mConvexSEL == NULL ? 0 : 1 ) );
  728. }
  729. if ( mActiveTool )
  730. mActiveTool->renderScene( updateRect );
  731. ColorI colorHL( 255, 50, 255, 255 );
  732. ColorI colorSEL( 255, 50, 255, 255 );
  733. ColorI colorNA( 255, 255, 255, 100 );
  734. GFXDrawUtil *drawer = GFX->getDrawUtil();
  735. if ( mConvexSEL && !mDragging )
  736. {
  737. if ( mFaceSEL == -1 )
  738. {
  739. GFXStateBlockDesc desc;
  740. desc.setBlend( true );
  741. desc.setZReadWrite( true, true );
  742. Box3F objBox = mConvexSEL->getObjBox();
  743. objBox.scale( mConvexSEL->getScale() );
  744. const MatrixF &objMat = mConvexSEL->getTransform();
  745. Point3F boxPos = objBox.getCenter();
  746. objMat.mulP( boxPos );
  747. drawer->drawObjectBox( desc, objBox.getExtents(), boxPos, objMat, ColorI::WHITE );
  748. }
  749. else
  750. {
  751. mConvexSEL->renderFaceEdges( -1, colorNA );
  752. drawFacePlane( mConvexSEL, mFaceSEL );
  753. }
  754. if ( mConvexHL == mConvexSEL &&
  755. mFaceHL != -1 &&
  756. mFaceHL != mFaceSEL &&
  757. mGizmo->getSelection() == Gizmo::None )
  758. {
  759. mConvexSEL->renderFaceEdges( mFaceHL, colorHL );
  760. }
  761. }
  762. if ( mConvexHL && mConvexHL != mConvexSEL )
  763. {
  764. mConvexHL->renderFaceEdges( -1 );
  765. }
  766. if ( mGizmo->getMode() != RotateMode && mUsingPivot )
  767. {
  768. mUsingPivot = false;
  769. updateGizmoPos();
  770. }
  771. F32 gizmoAlpha = 1.0f;
  772. if ( !mConvexSEL )
  773. gizmoAlpha = 0.0f;
  774. if ( mMouseDown && mGizmo->getSelection() != Gizmo::None && mConvexSEL )
  775. {
  776. if ( mSettingPivot )
  777. gizmoAlpha = 1.0f;
  778. else
  779. gizmoAlpha = 0.0f;
  780. }
  781. DebugDrawer::get()->render();
  782. {
  783. GFXTransformSaver saver;
  784. // Now draw all the 2d stuff!
  785. GFX->setClipRect(updateRect);
  786. if ( mConvexSEL && mFaceSEL != -1 )
  787. {
  788. Vector< Point3F > lineList;
  789. mConvexSEL->getSurfaceLineList( mFaceSEL, lineList );
  790. MatrixF objToWorld( mConvexSEL->getTransform() );
  791. objToWorld.scale( mConvexSEL->getScale() );
  792. for ( S32 i = 0; i < lineList.size(); i++ )
  793. objToWorld.mulP( lineList[i] );
  794. for ( S32 i = 0; i < lineList.size() - 1; i++ )
  795. {
  796. Point3F p0( lineList[i] );
  797. Point3F p1( lineList[i+1] );
  798. drawLine( p0, p1, colorSEL, 3.0f );
  799. }
  800. }
  801. if ( gizmoAlpha == 1.0f )
  802. {
  803. if ( mGizmoProfile->mode != NoneMode )
  804. mGizmo->renderText( mSaveViewport, mSaveModelview, mSaveProjection );
  805. }
  806. if ( mActiveTool )
  807. mActiveTool->render2D();
  808. }
  809. if ( gizmoAlpha == 1.0f )
  810. mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix, mLastCameraQuery.fov );
  811. }
  812. void GuiConvexEditorCtrl::drawFacePlane( ConvexShape *shape, S32 faceId )
  813. {
  814. // Build a vb of the face points ( in world space ) scaled outward in
  815. // the surface space in x/y with uv coords.
  816. /*
  817. Vector< Point3F > points;
  818. Vector< Point2F > coords;
  819. shape->getSurfaceTriangles( faceId, &points, &coords, false );
  820. if ( points.empty() )
  821. return;
  822. GFXVertexBufferHandle< GFXVertexPCT > vb;
  823. vb.set( GFX, points.size(), GFXBufferTypeVolatile );
  824. GFXVertexPCT *vert = vb.lock();
  825. for ( S32 i = 0; i < points.size(); i++ )
  826. {
  827. vert->point = points[i];
  828. vert->color.set( 255, 255, 255, 200 );
  829. vert->texCoord = coords[i];
  830. vert++;
  831. }
  832. vb.unlock();
  833. GFXTransformSaver saver;
  834. MatrixF renderMat( shape->getTransform() );
  835. renderMat.scale( shape->getScale() );
  836. GFX->multWorld( renderMat );
  837. GFXStateBlockDesc desc;
  838. desc.setBlend( true );
  839. desc.setCullMode( GFXCullNone );
  840. desc.setZReadWrite( true, false );
  841. desc.samplersDefined = true;
  842. desc.samplers[0] = GFXSamplerStateDesc::getWrapLinear();
  843. GFX->setStateBlockByDesc( desc );
  844. GFX->setVertexBuffer( vb );
  845. GFXTexHandle tex( "core/art/grids/512_transp", &GFXDefaultStaticDiffuseProfile, "ConvexEditor_grid" );
  846. GFX->setTexture( 0, tex );
  847. GFX->setupGenericShaders();
  848. GFX->drawPrimitive( GFXTriangleList, 0, points.size() / 3 );
  849. */
  850. }
  851. void GuiConvexEditorCtrl::scaleFace( ConvexShape *shape, S32 faceId, Point3F scale )
  852. {
  853. if ( !mHasGeometry )
  854. {
  855. mHasGeometry = true;
  856. mSavedGeometry = shape->mGeometry;
  857. mSavedSurfaces = shape->mSurfaces;
  858. }
  859. else
  860. {
  861. shape->mGeometry = mSavedGeometry;
  862. shape->mSurfaces = mSavedSurfaces;
  863. }
  864. if ( shape->mGeometry.faces.size() <= faceId )
  865. return;
  866. ConvexShape::Face &face = shape->mGeometry.faces[faceId];
  867. Vector< Point3F > &pointList = shape->mGeometry.points;
  868. AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
  869. Point3F projScale;
  870. scale.z = 1.0f;
  871. const MatrixF &surfToObj = shape->mSurfaces[ face.id ];
  872. MatrixF objToSurf( surfToObj );
  873. objToSurf.inverse();
  874. for ( S32 i = 0; i < face.points.size(); i++ )
  875. {
  876. Point3F &pnt = pointList[ face.points[i] ];
  877. objToSurf.mulP( pnt );
  878. pnt *= scale;
  879. surfToObj.mulP( pnt );
  880. }
  881. updateModifiedFace( shape, faceId );
  882. }
  883. void GuiConvexEditorCtrl::translateFace( ConvexShape *shape, S32 faceId, const Point3F &displace )
  884. {
  885. if ( !mHasGeometry )
  886. {
  887. mHasGeometry = true;
  888. mSavedGeometry = shape->mGeometry;
  889. mSavedSurfaces = shape->mSurfaces;
  890. }
  891. else
  892. {
  893. shape->mGeometry = mSavedGeometry;
  894. shape->mSurfaces = mSavedSurfaces;
  895. }
  896. if ( shape->mGeometry.faces.size() <= faceId )
  897. return;
  898. ConvexShape::Face &face = shape->mGeometry.faces[faceId];
  899. Vector< Point3F > &pointList = shape->mGeometry.points;
  900. AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
  901. // Transform displacement into object space.
  902. MatrixF worldToObj( shape->getTransform() );
  903. worldToObj.scale( shape->getScale() );
  904. worldToObj.inverse();
  905. Point3F displaceOS;
  906. worldToObj.mulV( displace, &displaceOS );
  907. for ( S32 i = 0; i < face.points.size(); i++ )
  908. {
  909. Point3F &pnt = pointList[ face.points[i] ];
  910. pnt += displaceOS;
  911. }
  912. updateModifiedFace( shape, faceId );
  913. }
  914. void GuiConvexEditorCtrl::updateModifiedFace( ConvexShape *shape, S32 faceId )
  915. {
  916. if ( shape->mGeometry.faces.size() <= faceId )
  917. return;
  918. ConvexShape::Face &face = shape->mGeometry.faces[faceId];
  919. Vector< Point3F > &pointList = shape->mGeometry.points;
  920. Vector< ConvexShape::Face > &faceList = shape->mGeometry.faces;
  921. for ( S32 i = 0; i < faceList.size(); i++ )
  922. {
  923. ConvexShape::Face &curFace = faceList[i];
  924. MatrixF &curSurface = shape->mSurfaces[ curFace.id ];
  925. U32 curPntCount = curFace.points.size();
  926. if ( curPntCount < 3 )
  927. continue;
  928. // Does this face use any of the points which we have modified?
  929. // Collect them in correct winding order.
  930. S32 pId0 = -1;
  931. for ( S32 j = 0; j < curFace.winding.size(); j++ )
  932. {
  933. if ( face.points.contains( curFace.points[ curFace.winding[ j ] ] ) )
  934. {
  935. pId0 = j;
  936. break;
  937. }
  938. }
  939. if ( pId0 == -1 )
  940. continue;
  941. S32 pId1 = -1, pId2 = -1;
  942. pId1 = ( pId0 + 1 ) % curFace.winding.size();
  943. pId2 = ( pId0 + 2 ) % curFace.winding.size();
  944. const Point3F &p0 = pointList[ curFace.points[ curFace.winding[ pId0 ] ] ];
  945. const Point3F &p1 = pointList[ curFace.points[ curFace.winding[ pId1 ] ] ];
  946. const Point3F &p2 = pointList[ curFace.points[ curFace.winding[ pId2 ] ] ];
  947. PlaneF newPlane( p0, p1, p2 );
  948. Point3F uvec = newPlane.getNormal();
  949. Point3F fvec = curSurface.getForwardVector();
  950. Point3F rvec = curSurface.getRightVector();
  951. F32 dt0 = mDot( uvec, fvec );
  952. F32 dt1 = mDot( uvec, rvec );
  953. if ( mFabs( dt0 ) < mFabs( dt1 ) )
  954. {
  955. rvec = mCross( fvec, uvec );
  956. rvec.normalizeSafe();
  957. fvec = mCross( uvec, rvec );
  958. fvec.normalizeSafe();
  959. }
  960. else
  961. {
  962. fvec = mCross( uvec, rvec );
  963. fvec.normalizeSafe();
  964. rvec = mCross( fvec, uvec );
  965. rvec.normalizeSafe();
  966. }
  967. curSurface.setColumn( 0, rvec );
  968. curSurface.setColumn( 1, fvec );
  969. curSurface.setColumn( 2, uvec );
  970. curSurface.setPosition( newPlane.getPosition() );
  971. }
  972. updateShape( shape );
  973. }
  974. bool GuiConvexEditorCtrl::isShapeValid( ConvexShape *shape )
  975. {
  976. // Test for no-geometry.
  977. if ( shape->mGeometry.points.empty() )
  978. return false;
  979. const Vector<Point3F> &pointList = shape->mGeometry.points;
  980. const Vector<ConvexShape::Face> &faceList = shape->mGeometry.faces;
  981. // Test that all points are shared by at least 3 faces.
  982. for ( S32 i = 0; i < pointList.size(); i++ )
  983. {
  984. U32 counter = 0;
  985. for ( S32 j = 0; j < faceList.size(); j++ )
  986. {
  987. if ( faceList[j].points.contains( i ) )
  988. counter++;
  989. }
  990. if ( counter < 3 )
  991. return false;
  992. }
  993. // Test for co-planar faces.
  994. for ( S32 i = 0; i < shape->mPlanes.size(); i++ )
  995. {
  996. for ( S32 j = i + 1; j < shape->mPlanes.size(); j++ )
  997. {
  998. F32 d = mDot( shape->mPlanes[i], shape->mPlanes[j] );
  999. if ( d > 0.999f )
  1000. return false;
  1001. }
  1002. }
  1003. // Test for faces with zero or negative area.
  1004. for ( S32 i = 0; i < shape->mGeometry.faces.size(); i++ )
  1005. {
  1006. if ( shape->mGeometry.faces[i].area < 0.0f )
  1007. return false;
  1008. if ( shape->mGeometry.faces[i].triangles.empty() )
  1009. return false;
  1010. }
  1011. return true;
  1012. }
  1013. void GuiConvexEditorCtrl::setupShape( ConvexShape *shape )
  1014. {
  1015. shape->setField( "material", mMaterialName );
  1016. shape->registerObject();
  1017. updateShape( shape );
  1018. SimGroup *group;
  1019. if ( Sim::findObject( "missionGroup", group ) )
  1020. group->addObject( shape );
  1021. }
  1022. void GuiConvexEditorCtrl::updateShape( ConvexShape *shape, S32 offsetFace )
  1023. {
  1024. shape->_updateGeometry( true );
  1025. /*
  1026. if ( offsetFace != -1 )
  1027. {
  1028. shape->mSurfaces[ offsetFace ].setPosition( mPivotPos );
  1029. }*/
  1030. synchClientObject( shape );
  1031. }
  1032. void GuiConvexEditorCtrl::synchClientObject( const ConvexShape *serverConvex )
  1033. {
  1034. if ( serverConvex->getClientObject() )
  1035. {
  1036. ConvexShape *clientConvex = static_cast< ConvexShape* >( serverConvex->getClientObject() );
  1037. clientConvex->setScale( serverConvex->getScale() );
  1038. clientConvex->setTransform( serverConvex->getTransform() );
  1039. clientConvex->mSurfaces.clear();
  1040. clientConvex->mSurfaces.merge( serverConvex->mSurfaces );
  1041. clientConvex->_updateGeometry(true);
  1042. }
  1043. }
  1044. void GuiConvexEditorCtrl::updateGizmoPos()
  1045. {
  1046. if ( mConvexSEL )
  1047. {
  1048. if ( mFaceSEL != -1 )
  1049. {
  1050. MatrixF surfMat = mConvexSEL->getSurfaceWorldMat( mFaceSEL );
  1051. MatrixF objToWorld( mConvexSEL->getTransform() );
  1052. objToWorld.scale( mConvexSEL->getScale() );
  1053. Point3F gizmoPos(0,0,0);
  1054. if ( mUsingPivot )
  1055. {
  1056. gizmoPos = mPivotPos;
  1057. }
  1058. else
  1059. {
  1060. Point3F faceCenterPnt = mConvexSEL->mSurfaces[ mFaceSEL ].getPosition();
  1061. objToWorld.mulP( faceCenterPnt );
  1062. mGizmoMatOffset = surfMat.getPosition() - faceCenterPnt;
  1063. gizmoPos = faceCenterPnt;
  1064. }
  1065. mGizmo->set( surfMat, gizmoPos, Point3F::One );
  1066. }
  1067. else
  1068. {
  1069. mGizmoMatOffset = Point3F::Zero;
  1070. mGizmo->set( mConvexSEL->getTransform(), mConvexSEL->getPosition(), mConvexSEL->getScale() );
  1071. }
  1072. }
  1073. }
  1074. bool GuiConvexEditorCtrl::setActiveTool( ConvexEditorTool *tool )
  1075. {
  1076. if ( mActiveTool == tool )
  1077. return false;
  1078. ConvexEditorTool *prevTool = mActiveTool;
  1079. ConvexEditorTool *newTool = tool;
  1080. if ( prevTool )
  1081. prevTool->onDeactivated( newTool );
  1082. mActiveTool = newTool;
  1083. if ( newTool )
  1084. newTool->onActivated( prevTool );
  1085. return true;
  1086. }
  1087. bool GuiConvexEditorCtrl::handleEscape()
  1088. {
  1089. if ( mActiveTool )
  1090. {
  1091. mActiveTool->onDeactivated( NULL );
  1092. mActiveTool = NULL;
  1093. return true;
  1094. }
  1095. if ( mFaceSEL != -1 )
  1096. {
  1097. setSelection( mConvexSEL, -1 );
  1098. return true;
  1099. }
  1100. if ( mConvexSEL )
  1101. {
  1102. setSelection( NULL, -1 );
  1103. return true;
  1104. }
  1105. return false;
  1106. }
  1107. bool GuiConvexEditorCtrl::handleDelete()
  1108. {
  1109. if ( mActiveTool )
  1110. {
  1111. mActiveTool->onDeactivated( NULL );
  1112. mActiveTool = NULL;
  1113. }
  1114. if ( mConvexSEL )
  1115. {
  1116. if ( mFaceSEL != -1 )
  1117. {
  1118. submitUndo( ModifyShape, mConvexSEL );
  1119. mConvexSEL->mSurfaces.erase_fast( mFaceSEL );
  1120. updateShape( mConvexSEL );
  1121. if ( !isShapeValid( mConvexSEL ) )
  1122. {
  1123. S32 selFace = mFaceSEL;
  1124. mLastUndo->undo();
  1125. mFaceSEL = selFace;
  1126. updateShape( mConvexSEL );
  1127. updateGizmoPos();
  1128. }
  1129. else
  1130. {
  1131. setSelection( mConvexSEL, -1 );
  1132. }
  1133. }
  1134. else
  1135. {
  1136. // Grab the mission editor undo manager.
  1137. UndoManager *undoMan = NULL;
  1138. if ( !Sim::findObject( "EUndoManager", undoMan ) )
  1139. {
  1140. Con::errorf( "GuiConvexEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
  1141. }
  1142. else
  1143. {
  1144. // Create the UndoAction.
  1145. MEDeleteUndoAction *action = new MEDeleteUndoAction("Deleted ConvexShape");
  1146. action->deleteObject( mConvexSEL );
  1147. mIsDirty = true;
  1148. mFaceHL = -1;
  1149. setSelection( NULL, -1 );
  1150. // Submit it.
  1151. undoMan->addAction( action );
  1152. }
  1153. }
  1154. }
  1155. return true;
  1156. }
  1157. bool GuiConvexEditorCtrl::hasSelection() const
  1158. {
  1159. return mConvexSEL != NULL;
  1160. }
  1161. void GuiConvexEditorCtrl::clearSelection()
  1162. {
  1163. mFaceHL = -1;
  1164. mConvexHL = NULL;
  1165. setSelection( NULL, -1 );
  1166. }
  1167. void GuiConvexEditorCtrl::handleDeselect()
  1168. {
  1169. if ( mActiveTool )
  1170. {
  1171. mActiveTool->onDeactivated( NULL );
  1172. mActiveTool = NULL;
  1173. }
  1174. mFaceHL = -1;
  1175. mConvexHL = NULL;
  1176. setSelection( NULL, -1 );
  1177. }
  1178. void GuiConvexEditorCtrl::setSelection( ConvexShape *shape, S32 faceId )
  1179. {
  1180. mFaceSEL = faceId;
  1181. mConvexSEL = shape;
  1182. updateGizmoPos();
  1183. Con::executef( this, "onSelectionChanged", shape ? shape->getIdString() : "", Con::getIntArg(faceId) );
  1184. }
  1185. void GuiConvexEditorCtrl::_prepRenderImage( SceneManager* sceneGraph, const SceneRenderState* state )
  1186. {
  1187. if ( !isAwake() )
  1188. return;
  1189. /*
  1190. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  1191. ri->type = RenderPassManager::RIT_Editor;
  1192. ri->renderDelegate.bind( this, &GuiConvexEditorCtrl::_renderObject );
  1193. ri->defaultKey = 100;
  1194. state->getRenderPass()->addInst( ri );
  1195. */
  1196. }
  1197. void GuiConvexEditorCtrl::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst )
  1198. {
  1199. }
  1200. void GuiConvexEditorCtrl::submitUndo( UndoType type, ConvexShape *shape )
  1201. {
  1202. Vector< ConvexShape* > shapes;
  1203. shapes.push_back( shape );
  1204. submitUndo( type, shapes );
  1205. }
  1206. void GuiConvexEditorCtrl::submitUndo( UndoType type, const Vector<ConvexShape*> &shapes )
  1207. {
  1208. // Grab the mission editor undo manager.
  1209. Sim::findObject( "EUndoManager", mUndoManager );
  1210. if ( !mUndoManager )
  1211. {
  1212. Con::errorf( "GuiConvexEditorCtrl::submitUndo() - EUndoManager not found!" );
  1213. return;
  1214. }
  1215. if ( type == ModifyShape )
  1216. {
  1217. // Setup the action.
  1218. GuiConvexEditorUndoAction *action = new GuiConvexEditorUndoAction( "Modified a ConvexShape" );
  1219. ConvexShape *shape = shapes.first();
  1220. action->mObjId = shape->getId();
  1221. action->mEditor = this;
  1222. action->mSavedObjToWorld = shape->getTransform();
  1223. action->mSavedScale = shape->getScale();
  1224. action->mSavedSurfaces.merge( shape->mSurfaces );
  1225. action->mUndoManager = mUndoManager;
  1226. mUndoManager->addAction( action );
  1227. mLastUndo = action;
  1228. }
  1229. else if ( type == CreateShape )
  1230. {
  1231. MECreateUndoAction *action = new MECreateUndoAction( "Create ConvexShape" );
  1232. for ( S32 i = 0; i < shapes.size(); i++ )
  1233. action->addObject( shapes[i] );
  1234. mUndoManager->addAction( action );
  1235. mLastUndo = action;
  1236. }
  1237. else if ( type == DeleteShape )
  1238. {
  1239. MEDeleteUndoAction *action = new MEDeleteUndoAction( "Deleted ConvexShape" );
  1240. for ( S32 i = 0; i < shapes.size(); i++ )
  1241. action->deleteObject( shapes[i] );
  1242. mUndoManager->addAction( action );
  1243. mLastUndo = action;
  1244. }
  1245. else if ( type == HollowShape )
  1246. {
  1247. CompoundUndoAction *action = new CompoundUndoAction( "Hollow ConvexShape" );
  1248. MECreateUndoAction *createAction = new MECreateUndoAction();
  1249. MEDeleteUndoAction *deleteAction = new MEDeleteUndoAction();
  1250. deleteAction->deleteObject( shapes.first() );
  1251. for ( S32 i = 1; i < shapes.size(); i++ )
  1252. createAction->addObject( shapes[i] );
  1253. action->addAction( deleteAction );
  1254. action->addAction( createAction );
  1255. mUndoManager->addAction( action );
  1256. mLastUndo = action;
  1257. }
  1258. mIsDirty = true;
  1259. }
  1260. bool GuiConvexEditorCtrl::_cursorCastCallback( RayInfo* ri )
  1261. {
  1262. // Reject anything that's not a ConvexShape.
  1263. return dynamic_cast< ConvexShape* >( ri->object );
  1264. }
  1265. bool GuiConvexEditorCtrl::_cursorCast( const Gui3DMouseEvent &event, ConvexShape **hitShape, S32 *hitFace )
  1266. {
  1267. RayInfo ri;
  1268. if ( gServerContainer.castRay( event.pos, event.pos + event.vec * 10000.0f, StaticShapeObjectType, &ri, &GuiConvexEditorCtrl::_cursorCastCallback ) &&
  1269. dynamic_cast< ConvexShape* >( ri.object ) )
  1270. {
  1271. // Do not select or edit ConvexShapes that are within a Prefab.
  1272. if ( Prefab::getPrefabByChild( ri.object ) )
  1273. return false;
  1274. *hitShape = static_cast< ConvexShape* >( ri.object );
  1275. *hitFace = ri.face;
  1276. mLastRayInfo = ri;
  1277. return true;
  1278. }
  1279. return false;
  1280. }
  1281. void GuiConvexEditorCtrl::setPivotPos( ConvexShape *shape, S32 faceId, const Gui3DMouseEvent &event )
  1282. {
  1283. PlaneF plane;
  1284. mTransformPlane( shape->getTransform(), shape->getScale(), shape->mPlanes[ faceId ], &plane );
  1285. Point3F start( event.pos );
  1286. Point3F end( start + event.vec * 10000.0f );
  1287. F32 t = plane.intersect( start, end );
  1288. if ( t >= 0.0f && t <= 1.0f )
  1289. {
  1290. Point3F hitPos;
  1291. hitPos.interpolate( start, end, t );
  1292. mPivotPos = hitPos;
  1293. mUsingPivot = true;
  1294. MatrixF worldToObj( shape->getTransform() );
  1295. worldToObj.scale( shape->getScale() );
  1296. worldToObj.inverse();
  1297. Point3F objPivotPos( mPivotPos );
  1298. worldToObj.mulP( objPivotPos );
  1299. updateGizmoPos();
  1300. }
  1301. }
  1302. void GuiConvexEditorCtrl::cleanMatrix( MatrixF &mat )
  1303. {
  1304. if ( mat.isAffine() )
  1305. return;
  1306. VectorF col0 = mat.getColumn3F(0);
  1307. VectorF col1 = mat.getColumn3F(1);
  1308. VectorF col2 = mat.getColumn3F(2);
  1309. col0.normalize();
  1310. col1.normalize();
  1311. col2.normalize();
  1312. col2 = mCross( col0, col1 );
  1313. col2.normalize();
  1314. col1 = mCross( col2, col0 );
  1315. col1.normalize();
  1316. col0 = mCross( col1, col2 );
  1317. col0.normalize();
  1318. mat.setColumn(0,col0);
  1319. mat.setColumn(1,col1);
  1320. mat.setColumn(2,col2);
  1321. AssertFatal( mat.isAffine(), "GuiConvexEditorCtrl::cleanMatrix, non-affine matrix" );
  1322. }
  1323. S32 GuiConvexEditorCtrl::getEdgeByPoints( ConvexShape *shape, S32 faceId, S32 p0, S32 p1 )
  1324. {
  1325. const ConvexShape::Face &face = shape->mGeometry.faces[faceId];
  1326. for ( S32 i = 0; i < face.edges.size(); i++ )
  1327. {
  1328. const ConvexShape::Edge &edge = face.edges[i];
  1329. if ( edge.p0 != p0 && edge.p0 != p1 )
  1330. continue;
  1331. if ( edge.p1 != p0 && edge.p1 != p1 )
  1332. continue;
  1333. return i;
  1334. }
  1335. return -1;
  1336. }
  1337. bool GuiConvexEditorCtrl::getEdgesTouchingPoint( ConvexShape *shape, S32 faceId, S32 pId, Vector< U32 > &edgeIdxList, S32 excludeEdge )
  1338. {
  1339. const ConvexShape::Face &face = shape->mGeometry.faces[faceId];
  1340. const Vector< ConvexShape::Edge > &edgeList = face.edges;
  1341. for ( S32 i = 0; i < edgeList.size(); i++ )
  1342. {
  1343. if ( i == excludeEdge )
  1344. continue;
  1345. const ConvexShape::Edge &curEdge = edgeList[i];
  1346. if ( curEdge.p0 == pId || curEdge.p1 == pId )
  1347. edgeIdxList.push_back(i);
  1348. }
  1349. return !edgeIdxList.empty();
  1350. }
  1351. void GuiConvexEditorUndoAction::undo()
  1352. {
  1353. ConvexShape *object = NULL;
  1354. if ( !Sim::findObject( mObjId, object ) )
  1355. return;
  1356. // Temporarily save the ConvexShape current data.
  1357. Vector< MatrixF > tempSurfaces;
  1358. tempSurfaces.merge( object->mSurfaces );
  1359. MatrixF tempObjToWorld( object->getTransform() );
  1360. Point3F tempScale( object->getScale() );
  1361. // Restore the Object to the UndoAction state.
  1362. object->mSurfaces.clear();
  1363. object->mSurfaces.merge( mSavedSurfaces );
  1364. object->setScale( mSavedScale );
  1365. object->setTransform( mSavedObjToWorld );
  1366. // Regenerate the ConvexShape and synch the client object.
  1367. object->_updateGeometry();
  1368. GuiConvexEditorCtrl::synchClientObject( object );
  1369. // If applicable set the selected ConvexShape and face
  1370. // on the editor.
  1371. mEditor->setSelection( object, -1 );
  1372. mEditor->updateGizmoPos();
  1373. // Now save the previous ConvexShape data in this UndoAction
  1374. // since an undo action must become a redo action and vice-versa
  1375. mSavedObjToWorld = tempObjToWorld;
  1376. mSavedScale = tempScale;
  1377. mSavedSurfaces.clear();
  1378. mSavedSurfaces.merge( tempSurfaces );
  1379. }
  1380. ConvexEditorCreateTool::ConvexEditorCreateTool( GuiConvexEditorCtrl *editor )
  1381. : Parent( editor ),
  1382. mStage( -1 ),
  1383. mNewConvex( NULL )
  1384. {
  1385. }
  1386. void ConvexEditorCreateTool::onActivated( ConvexEditorTool *prevTool )
  1387. {
  1388. mEditor->clearSelection();
  1389. mStage = -1;
  1390. mNewConvex = NULL;
  1391. }
  1392. void ConvexEditorCreateTool::onDeactivated( ConvexEditorTool *newTool )
  1393. {
  1394. if ( mNewConvex )
  1395. mNewConvex->deleteObject();
  1396. mStage = -1;
  1397. mNewConvex = NULL;
  1398. mEditor->mouseUnlock();
  1399. }
  1400. ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseDown( const Gui3DMouseEvent &event )
  1401. {
  1402. if ( mStage == -1 )
  1403. {
  1404. mEditor->setFirstResponder();
  1405. mEditor->mouseLock();
  1406. Point3F start( event.pos );
  1407. Point3F end( event.pos + event.vec * 10000.0f );
  1408. RayInfo ri;
  1409. bool hit = gServerContainer.castRay( event.pos, end, STATIC_COLLISION_TYPEMASK, &ri );
  1410. MatrixF objMat( true );
  1411. // Calculate the orientation matrix of the new ConvexShape
  1412. // based on what has been clicked.
  1413. if ( !hit )
  1414. {
  1415. objMat.setPosition( event.pos + event.vec * 100.0f );
  1416. }
  1417. else
  1418. {
  1419. if ( dynamic_cast< ConvexShape* >( ri.object ) )
  1420. {
  1421. ConvexShape *hitShape = static_cast< ConvexShape* >( ri.object );
  1422. objMat = hitShape->getSurfaceWorldMat( ri.face );
  1423. objMat.setPosition( ri.point );
  1424. }
  1425. else
  1426. {
  1427. Point3F rvec;
  1428. Point3F fvec( mEditor->getCameraMat().getForwardVector() );
  1429. Point3F uvec( ri.normal );
  1430. rvec = mCross( fvec, uvec );
  1431. if ( rvec.isZero() )
  1432. {
  1433. fvec = mEditor->getCameraMat().getRightVector();
  1434. rvec = mCross( fvec, uvec );
  1435. }
  1436. rvec.normalizeSafe();
  1437. fvec = mCross( uvec, rvec );
  1438. fvec.normalizeSafe();
  1439. uvec = mCross( rvec, fvec );
  1440. uvec.normalizeSafe();
  1441. objMat.setColumn( 0, rvec );
  1442. objMat.setColumn( 1, fvec );
  1443. objMat.setColumn( 2, uvec );
  1444. objMat.setPosition( ri.point );
  1445. }
  1446. }
  1447. mNewConvex = new ConvexShape();
  1448. mNewConvex->setTransform( objMat );
  1449. mNewConvex->setField( "material", Parent::mEditor->mMaterialName );
  1450. mNewConvex->registerObject();
  1451. mPlaneSizes.set( 0.1f, 0.1f, 0.1f );
  1452. mNewConvex->resizePlanes( mPlaneSizes );
  1453. mEditor->updateShape( mNewConvex );
  1454. mTransform = objMat;
  1455. mCreatePlane.set( objMat.getPosition(), objMat.getUpVector() );
  1456. }
  1457. else if ( mStage == 0 )
  1458. {
  1459. // Handle this on mouseUp
  1460. }
  1461. return Handled;
  1462. }
  1463. ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseUp( const Gui3DMouseEvent &event )
  1464. {
  1465. if ( mNewConvex && mStage == -1 )
  1466. {
  1467. mStage = 0;
  1468. mCreatePlane = PlaneF( mNewConvex->getPosition(), mNewConvex->getTransform().getForwardVector() );
  1469. mTransform.setPosition( mNewConvex->getPosition() );
  1470. return Handled;
  1471. }
  1472. else if ( mStage == 0 )
  1473. {
  1474. SimGroup *mg;
  1475. Sim::findObject( "MissionGroup", mg );
  1476. mg->addObject( mNewConvex );
  1477. mStage = -1;
  1478. // Grab the mission editor undo manager.
  1479. UndoManager *undoMan = NULL;
  1480. if ( !Sim::findObject( "EUndoManager", undoMan ) )
  1481. {
  1482. Con::errorf( "ConvexEditorCreateTool::on3DMouseDown() - EUndoManager not found!" );
  1483. mNewConvex = NULL;
  1484. return Failed;
  1485. }
  1486. // Create the UndoAction.
  1487. MECreateUndoAction *action = new MECreateUndoAction("Create ConvexShape");
  1488. action->addObject( mNewConvex );
  1489. // Submit it.
  1490. undoMan->addAction( action );
  1491. mEditor->setField( "isDirty", "1" );
  1492. mEditor->setSelection( mNewConvex, -1 );
  1493. mNewConvex = NULL;
  1494. mEditor->mouseUnlock();
  1495. return Done;
  1496. }
  1497. return Done;
  1498. }
  1499. ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseMove( const Gui3DMouseEvent &event )
  1500. {
  1501. if ( mStage == 0 )
  1502. {
  1503. Point3F start( event.pos );
  1504. Point3F end( start + event.vec * 10000.0f );
  1505. F32 t = mCreatePlane.intersect( start, end );
  1506. Point3F hitPos;
  1507. if ( t < 0.0f || t > 1.0f )
  1508. return Handled;
  1509. hitPos.interpolate( start, end, t );
  1510. MatrixF worldToObj( mTransform );
  1511. worldToObj.inverse();
  1512. worldToObj.mulP( hitPos );
  1513. F32 delta = ( hitPos.z );
  1514. mPlaneSizes.z = getMax( 0.1f, delta );
  1515. mNewConvex->resizePlanes( mPlaneSizes );
  1516. mEditor->updateShape( mNewConvex );
  1517. Point3F pos( mTransform.getPosition() );
  1518. pos += mPlaneSizes.z * 0.5f * mTransform.getUpVector();
  1519. mNewConvex->setPosition( pos );
  1520. }
  1521. return Handled;
  1522. }
  1523. ConvexEditorTool::EventResult ConvexEditorCreateTool::on3DMouseDragged( const Gui3DMouseEvent &event )
  1524. {
  1525. if ( !mNewConvex || mStage != -1 )
  1526. return Handled;
  1527. Point3F start( event.pos );
  1528. Point3F end( event.pos + event.vec * 10000.0f );
  1529. F32 t = mCreatePlane.intersect( start, end );
  1530. if ( t < 0.0f || t > 1.0f )
  1531. return Handled;
  1532. Point3F hitPos;
  1533. hitPos.interpolate( start, end, t );
  1534. MatrixF xfm( mTransform );
  1535. xfm.inverse();
  1536. xfm.mulP( hitPos);
  1537. Point3F scale;
  1538. scale.x = getMax( mFabs( hitPos.x ), 0.1f );
  1539. scale.y = getMax( mFabs( hitPos.y ), 0.1f );
  1540. scale.z = 0.1f;
  1541. mNewConvex->resizePlanes( scale );
  1542. mPlaneSizes = scale;
  1543. mEditor->updateShape( mNewConvex );
  1544. Point3F pos( mTransform.getPosition() );
  1545. pos += mTransform.getRightVector() * hitPos.x * 0.5f;
  1546. pos += mTransform.getForwardVector() * hitPos.y * 0.5f;
  1547. mNewConvex->setPosition( pos );
  1548. return Handled;
  1549. }
  1550. void ConvexEditorCreateTool::renderScene( const RectI &updateRect )
  1551. {
  1552. }
  1553. ConvexShape* ConvexEditorCreateTool::extrudeShapeFromFace( ConvexShape *inShape, S32 inFaceId )
  1554. {
  1555. ConvexShape::Geometry &inShapeGeometry = inShape->getGeometry();
  1556. ConvexShape::Face &inFace = inShapeGeometry.faces[inFaceId];
  1557. Vector< Point3F > &inShapePointList = inShapeGeometry.points;
  1558. Vector< MatrixF > &inShapeSurfaces = inShape->getSurfaces();
  1559. S32 shapeFaceCount = inFace.edges.size() + 2;
  1560. MatrixF inShapeToWorld( inShape->getTransform() );
  1561. inShapeToWorld.scale( inShape->getScale() );
  1562. //MatrixF inWorldToShape( inShapeToWorld );
  1563. //inWorldToShape.inverse();
  1564. MatrixF shapeToWorld;
  1565. shapeToWorld.mul( inShape->getTransform(), inShapeSurfaces[inFaceId] );
  1566. Point3F tmp( inShapeSurfaces[inFaceId].getPosition() );
  1567. inShapeToWorld.mulP( tmp );
  1568. shapeToWorld.setPosition( tmp );
  1569. MatrixF worldToShape( shapeToWorld );
  1570. worldToShape.inverse();
  1571. MatrixF inShapeToNewShape;
  1572. inShapeToNewShape.mul( inShapeToWorld, worldToShape );
  1573. ConvexShape *newShape = new ConvexShape;
  1574. newShape->setTransform( shapeToWorld );
  1575. Vector< MatrixF > &shapeSurfaces = newShape->getSurfaces();
  1576. shapeSurfaces.setSize( shapeFaceCount );
  1577. //shapeSurfaces.setSize( 2 );
  1578. const Point3F &shapePos = shapeToWorld.getPosition();
  1579. shapeSurfaces[0].identity();
  1580. shapeSurfaces[1].identity();
  1581. shapeSurfaces[1].setColumn( 0, -shapeSurfaces[1].getColumn3F(0) );
  1582. shapeSurfaces[1].setColumn( 2, -shapeSurfaces[1].getColumn3F(2) );
  1583. for ( S32 i = 0; i < inFace.winding.size(); i++ )
  1584. {
  1585. Point3F p0 = inShapePointList[ inFace.points[ inFace.winding[ i ] ] ];
  1586. Point3F p1;
  1587. if ( i+1 < inFace.winding.size() )
  1588. p1 = inShapePointList[ inFace.points[ inFace.winding[ i+1 ] ] ];
  1589. else
  1590. p1 = inShapePointList[ inFace.points[ inFace.winding[ 0 ] ] ];
  1591. inShapeToWorld.mulP( p0 );
  1592. inShapeToWorld.mulP( p1 );
  1593. Point3F newPos = MathUtils::mClosestPointOnSegment( p0, p1, shapePos );
  1594. Point3F rvec = p0 - p1;
  1595. rvec.normalizeSafe();
  1596. Point3F fvec = shapeToWorld.getUpVector();
  1597. Point3F uvec = mCross( rvec, fvec );
  1598. if ( i + 2 >= shapeSurfaces.size() )
  1599. continue;
  1600. //F32 dt = mDot( shapeToWorld.getUpVector(), rvec );
  1601. //AssertFatal( mIsZero( dt ), "bad" );
  1602. MatrixF &surf = shapeSurfaces[i+2];
  1603. surf.identity();
  1604. surf.setColumn( 0, rvec );
  1605. surf.setColumn( 1, fvec );
  1606. surf.setColumn( 2, uvec );
  1607. surf.setPosition( newPos );
  1608. surf.mulL( worldToShape );
  1609. }
  1610. newShape->setField( "material", Parent::mEditor->mMaterialName );
  1611. newShape->registerObject();
  1612. mEditor->updateShape( newShape );
  1613. SimGroup *group;
  1614. if ( Sim::findObject( "missionGroup", group ) )
  1615. group->addObject( newShape );
  1616. return newShape;
  1617. }
  1618. void GuiConvexEditorCtrl::hollowShape( ConvexShape *shape, F32 thickness )
  1619. {
  1620. // Create a new Convex for each face of the original shape.
  1621. // This is the same as an extrude from face operation going inward by the thickness
  1622. // for every face.
  1623. Vector< ConvexShape* > convexList;
  1624. for ( S32 i = 0; i < shape->mGeometry.faces.size(); i++ )
  1625. {
  1626. ConvexShape *faceShape = mCreateTool->extrudeShapeFromFace( shape, i );
  1627. MatrixF &inwardFace = faceShape->mSurfaces[1];
  1628. //MatrixF &outwardFace = faceShape->mSurfaces[0];
  1629. Point3F invec = inwardFace.getUpVector();
  1630. inwardFace.setPosition( inwardFace.getPosition() + invec * thickness );
  1631. updateShape( faceShape );
  1632. convexList.push_back( faceShape );
  1633. }
  1634. convexList.push_front( shape );
  1635. submitUndo( HollowShape, convexList );
  1636. }
  1637. void GuiConvexEditorCtrl::hollowSelection()
  1638. {
  1639. if ( mConvexSEL )
  1640. {
  1641. hollowShape( mConvexSEL, 0.15f );
  1642. setSelection( NULL, -1 );
  1643. }
  1644. }
  1645. void GuiConvexEditorCtrl::recenterSelection()
  1646. {
  1647. if ( mConvexSEL )
  1648. {
  1649. recenterShape( mConvexSEL );
  1650. updateGizmoPos();
  1651. }
  1652. }
  1653. void GuiConvexEditorCtrl::recenterShape( ConvexShape *shape )
  1654. {
  1655. submitUndo( ModifyShape, shape );
  1656. shape->recenter();
  1657. synchClientObject( shape );
  1658. }
  1659. void GuiConvexEditorCtrl::dropSelectionAtScreenCenter()
  1660. {
  1661. // This code copied from WorldEditor.
  1662. // All the dropping code would be moved to somewhere common, but its not.
  1663. if ( !mConvexSEL )
  1664. return;
  1665. // Calculate the center of the screen (in global screen coordinates)
  1666. Point2I offset = localToGlobalCoord(Point2I(0,0));
  1667. Point3F sp(F32(offset.x + F32(getExtent().x / 2)), F32(offset.y + (getExtent().y / 2)), 1.0f);
  1668. // Calculate the view distance to fit the selection
  1669. // within the camera's view.
  1670. const Box3F bounds = mConvexSEL->getWorldBox();
  1671. F32 radius = bounds.len()*0.5f;
  1672. F32 viewdist = calculateViewDistance(radius);
  1673. // Be careful of infinite sized objects, or just large ones in general.
  1674. if(viewdist > 100.0f )
  1675. viewdist = 100.0f;
  1676. // Position the selection
  1677. mConvexSEL->setPosition( smCamPos + smCamMatrix.getForwardVector() * viewdist );
  1678. synchClientObject( mConvexSEL );
  1679. updateGizmoPos();
  1680. }
  1681. void GuiConvexEditorCtrl::splitSelectedFace()
  1682. {
  1683. if ( !mConvexSEL || mFaceSEL == -1 )
  1684. return;
  1685. if ( !isShapeValid( mConvexSEL ) )
  1686. return;
  1687. mLastValidShape = mConvexSEL->mSurfaces;
  1688. const F32 radians = mDegToRad( 15.0f );
  1689. Point3F rot( 0, 0, 0 );
  1690. MatrixF rotMat( true );
  1691. mConvexSEL->mSurfaces.increment();
  1692. MatrixF &dstMat = mConvexSEL->mSurfaces.last();
  1693. const MatrixF &srcMat = mConvexSEL->mSurfaces[mFaceSEL];
  1694. for ( S32 i = 0; i < 6; i++ )
  1695. {
  1696. F32 sign = i > 2 ? -1.0f : 1.0f;
  1697. U32 idx = i % 3;
  1698. rot.zero();
  1699. rot[idx] = sign * radians;
  1700. rotMat.set( (EulerF)rot );
  1701. dstMat = srcMat * rotMat;
  1702. updateShape( mConvexSEL );
  1703. if ( isShapeValid( mConvexSEL ) )
  1704. {
  1705. mSavedSurfaces = mConvexSEL->mSurfaces;
  1706. mConvexSEL->mSurfaces = mLastValidShape;
  1707. submitUndo( ModifyShape, mConvexSEL );
  1708. mConvexSEL->mSurfaces = mSavedSurfaces;
  1709. mLastValidShape = mSavedSurfaces;
  1710. setSelection( mConvexSEL, mConvexSEL->mSurfaces.size() - 1 );
  1711. return;
  1712. }
  1713. }
  1714. mConvexSEL->mSurfaces = mLastValidShape;
  1715. updateShape( mConvexSEL );
  1716. updateGizmoPos();
  1717. }
  1718. DefineConsoleMethod( GuiConvexEditorCtrl, hollowSelection, void, (), , "" )
  1719. {
  1720. object->hollowSelection();
  1721. }
  1722. DefineConsoleMethod( GuiConvexEditorCtrl, recenterSelection, void, (), , "" )
  1723. {
  1724. object->recenterSelection();
  1725. }
  1726. DefineConsoleMethod( GuiConvexEditorCtrl, hasSelection, S32, (), , "" )
  1727. {
  1728. return object->hasSelection();
  1729. }
  1730. DefineConsoleMethod( GuiConvexEditorCtrl, handleDelete, void, (), , "" )
  1731. {
  1732. object->handleDelete();
  1733. }
  1734. DefineConsoleMethod( GuiConvexEditorCtrl, handleDeselect, void, (), , "" )
  1735. {
  1736. object->handleDeselect();
  1737. }
  1738. DefineConsoleMethod( GuiConvexEditorCtrl, dropSelectionAtScreenCenter, void, (), , "" )
  1739. {
  1740. object->dropSelectionAtScreenCenter();
  1741. }
  1742. DefineConsoleMethod( GuiConvexEditorCtrl, selectConvex, void, (ConvexShape *convex), , "( ConvexShape )" )
  1743. {
  1744. if (convex)
  1745. object->setSelection( convex, -1 );
  1746. }
  1747. DefineConsoleMethod( GuiConvexEditorCtrl, splitSelectedFace, void, (), , "" )
  1748. {
  1749. object->splitSelectedFace();
  1750. }