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. mFaceSEL( -1 ),
  56. mFaceHL( -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. mMouseDown( false ),
  66. mCreateTool( NULL ),
  67. mSavedGizmoFlags( -1 ),
  68. mHasCopied( false ),
  69. mLastUndo( NULL ),
  70. mUndoManager( NULL ),
  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. }