VPathEditor.cpp 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194
  1. //-----------------------------------------------------------------------------
  2. // Verve
  3. // Copyright (C) 2014 - Violent Tulip
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. //-----------------------------------------------------------------------------
  23. #include "torqueConfig.h"
  24. #ifdef TORQUE_TOOLS
  25. #include "VPathEditor.h"
  26. #include "console/consoleTypes.h"
  27. #include "gfx/gfxDrawUtil.h"
  28. #include "gfx/primBuilder.h"
  29. #include "gui/worldEditor/worldEditor.h"
  30. #include "math/mathUtils.h"
  31. #include "sim/netConnection.h"
  32. //-----------------------------------------------------------------------------
  33. static F32 gProjectDistance = 2000.f;
  34. static F32 gSelectionDistance = 2.f;
  35. static ColorI gPathColor( 255, 255, 255 );
  36. static ColorI gPathColorSel( 0, 255, 255 );
  37. static ColorI gNodeLookAtPointColor( 255, 127, 39 );
  38. //-----------------------------------------------------------------------------
  39. // Implement the Edit Mode enum list.
  40. ImplementEnumType( VPathEditorMode, "" )
  41. { VPathEditor::k_Gizmo, "GIZMO" },
  42. { VPathEditor::k_AddNode, "ADDNODE" },
  43. { VPathEditor::k_DeleteNode, "DELETENODE" },
  44. EndImplementEnumType;
  45. //-----------------------------------------------------------------------------
  46. IMPLEMENT_CONOBJECT( VPathEditor );
  47. //-----------------------------------------------------------------------------
  48. VPathEditor::VPathEditor( void ) :
  49. mIsDirty( false ),
  50. mEditMode( k_Gizmo ),
  51. mEditWeight( false ),
  52. mEditWeightHandle( -1 )
  53. {
  54. // Void.
  55. }
  56. bool VPathEditor::onAdd( void )
  57. {
  58. if ( !Parent::onAdd() )
  59. {
  60. return false;
  61. }
  62. // Assign Gizmo Name.
  63. mGizmo->assignName( "VPathEditorGizmo" );
  64. return true;
  65. }
  66. bool VPathEditor::onWake( void )
  67. {
  68. // Clear Selection.
  69. updateSelection( NULL, -1 );
  70. // Return Parent Value.
  71. return Parent::onWake();
  72. }
  73. void VPathEditor::initPersistFields( void )
  74. {
  75. addField( "IsDirty", TypeBool, Offset( mIsDirty, VPathEditor ) );
  76. addField( "EditMode", TYPEID<EditMode>(), Offset( mEditMode, VPathEditor ) );
  77. Parent::initPersistFields();
  78. }
  79. //-----------------------------------------------------------------------------
  80. //
  81. // Gui Events
  82. //
  83. //-----------------------------------------------------------------------------
  84. void VPathEditor::on3DMouseDown( const Gui3DMouseEvent &pEvent )
  85. {
  86. // Using the Gizmo?
  87. if ( mEditMode != k_Gizmo )
  88. {
  89. // No, Quit Now.
  90. return;
  91. }
  92. // Gizmo Event.
  93. mGizmo->on3DMouseDown( pEvent );
  94. if ( isValidSelection() )
  95. {
  96. // Store Node Information.
  97. pushNodeEdit();
  98. switch( mGizmoProfile->mode )
  99. {
  100. case MoveMode:
  101. case RotateMode:
  102. {
  103. if ( mGizmo->getSelection() != Gizmo::None )
  104. {
  105. // Using Gizmo.
  106. return;
  107. }
  108. } break;
  109. case ScaleMode:
  110. {
  111. if ( isEditingWeight( pEvent ) )
  112. {
  113. // Editing Weights.
  114. return;
  115. }
  116. } break;
  117. }
  118. }
  119. else if ( mSelection.Path )
  120. {
  121. // Store Path Information.
  122. pushPathEdit();
  123. if ( mGizmo->getSelection() != Gizmo::None )
  124. {
  125. // Using Gizmo.
  126. return;
  127. }
  128. }
  129. // Update Selection.
  130. if ( !updateSelection( pEvent ) )
  131. {
  132. // Clear Selection.
  133. updateSelection( NULL, -1 );
  134. }
  135. }
  136. void VPathEditor::on3DMouseUp( const Gui3DMouseEvent &pEvent )
  137. {
  138. switch ( mEditMode )
  139. {
  140. case k_Gizmo :
  141. {
  142. // Gizmo Event.
  143. mGizmo->on3DMouseUp( pEvent );
  144. // Handle History Actions.
  145. popPathEdit();
  146. popNodeEdit();
  147. // Clear Editing.
  148. mEditWeight = false;
  149. } break;
  150. case k_AddNode :
  151. {
  152. if ( mSelection.Path != NULL )
  153. {
  154. // Add New!
  155. addNode( pEvent );
  156. // Dirty.
  157. mIsDirty = true;
  158. }
  159. } break;
  160. case k_DeleteNode :
  161. {
  162. // Update Selection.
  163. if ( updateSelection( pEvent ) )
  164. {
  165. if ( isValidSelection() )
  166. {
  167. // Delete Node.
  168. deleteNode( mSelection.Node );
  169. // Dirty.
  170. mIsDirty = true;
  171. }
  172. // Clear Node Selection.
  173. updateSelection( mSelection.Path, -1 );
  174. }
  175. } break;
  176. }
  177. }
  178. void VPathEditor::on3DMouseMove( const Gui3DMouseEvent &pEvent )
  179. {
  180. // Update?
  181. if ( mEditMode != k_Gizmo || !mSelection.Path )
  182. {
  183. return;
  184. }
  185. // Update Gizmo?
  186. if ( mSelection.Node == -1 || mGizmoProfile->mode != ScaleMode )
  187. {
  188. // Gizmo Event.
  189. mGizmo->on3DMouseMove( pEvent );
  190. }
  191. }
  192. void VPathEditor::on3DMouseDragged( const Gui3DMouseEvent &pEvent )
  193. {
  194. // Update?
  195. if ( mEditMode != k_Gizmo || !mSelection.Path )
  196. {
  197. return;
  198. }
  199. // Update Gizmo?
  200. if ( mSelection.Node == -1 || mGizmoProfile->mode != ScaleMode )
  201. {
  202. // Gizmo Event.
  203. mGizmo->on3DMouseDragged( pEvent );
  204. // Handle Gizmo?
  205. if ( mGizmo->getSelection() == Gizmo::None )
  206. {
  207. // Return.
  208. return;
  209. }
  210. }
  211. // Editing the Path?
  212. if ( mSelection.Node == -1 )
  213. {
  214. switch ( mGizmoProfile->mode )
  215. {
  216. case MoveMode :
  217. {
  218. // Fetch Node Position.
  219. const Point3F oldPosition = mSelection.Path->getPosition();
  220. // Determine New Position.
  221. const Point3F newPosition = ( oldPosition + mGizmo->getOffset() );
  222. // Apply New Position.
  223. setPathPosition( newPosition );
  224. // Dirty.
  225. mIsDirty = true;
  226. mPathEdit.Dirty = true;
  227. } break;
  228. /*
  229. case RotateMode :
  230. {
  231. // Rotation Delta.
  232. MatrixF deltaRotation( EulerF( mGizmo->getDeltaRot() ) );
  233. // Fetch Current Transform.
  234. MatrixF mat = mSelection.Path->getTransform();
  235. mat.mul( deltaRotation );
  236. // Apply New Transform.
  237. setPathTransform( mat );
  238. // Dirty.
  239. mIsDirty = true;
  240. mPathEdit.Dirty = true;
  241. } break;
  242. case ScaleMode :
  243. {
  244. // Apply New Scale.
  245. setPathScale( mGizmo->getScale() );
  246. // Dirty.
  247. mIsDirty = true;
  248. mPathEdit.Dirty = true;
  249. } break;
  250. */
  251. }
  252. }
  253. // No, Editing a Node
  254. else
  255. {
  256. switch ( mGizmoProfile->mode )
  257. {
  258. case MoveMode :
  259. {
  260. // Fetch Node.
  261. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  262. // Fetch Node Position.
  263. const Point3F oldPosition = node->getLocalPosition();
  264. // Invert Transform.
  265. MatrixF pathTransform = mSelection.Path->getTransform();
  266. pathTransform.setPosition( Point3F::Zero );
  267. pathTransform.inverse();
  268. Point3F deltaPosition = mGizmo->getOffset();
  269. pathTransform.mulP( deltaPosition );
  270. // Apply New Position.
  271. setNodePosition( mSelection.Node, ( oldPosition + deltaPosition ) );
  272. } break;
  273. case RotateMode :
  274. {
  275. // Fetch Node.
  276. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  277. // Invert Transform.
  278. MatrixF pathTransform = mSelection.Path->getTransform();
  279. pathTransform.setPosition( Point3F::Zero );
  280. pathTransform.inverse();
  281. // Rotation Delta.
  282. MatrixF deltaRotation( EulerF( mGizmo->getDeltaRot() ) );
  283. pathTransform.mul( deltaRotation );
  284. // Fetch Current Transform.
  285. MatrixF mat = node->getWorldTransform();
  286. mat.mul( deltaRotation );
  287. // Construct Quat.
  288. QuatF newRotation;
  289. newRotation.set( mat );
  290. // Apply New Rotation.
  291. setNodeRotation( mSelection.Node, newRotation );
  292. } break;
  293. case ScaleMode :
  294. {
  295. if ( isEditingWeight() )
  296. {
  297. // Edit Weight.
  298. updateWeight( pEvent );
  299. }
  300. } break;
  301. }
  302. }
  303. }
  304. //-----------------------------------------------------------------------------
  305. //
  306. // Reference Methods.
  307. //
  308. //-----------------------------------------------------------------------------
  309. VPath *VPathEditor::getClientPath( VPath *pPath )
  310. {
  311. if ( !pPath )
  312. {
  313. return NULL;
  314. }
  315. NetConnection *toServer = NetConnection::getConnectionToServer();
  316. NetConnection *toClient = NetConnection::getLocalClientConnection();
  317. if ( !toServer || !toClient )
  318. {
  319. return NULL;
  320. }
  321. const S32 ghostIndex = toClient->getGhostIndex( pPath );
  322. if ( ghostIndex == -1 )
  323. {
  324. return NULL;
  325. }
  326. return dynamic_cast<VPath*>( toServer->resolveGhost( ghostIndex ) );
  327. }
  328. //-----------------------------------------------------------------------------
  329. //
  330. // Selection Methods.
  331. //
  332. //-----------------------------------------------------------------------------
  333. bool VPathEditor::updateSelection( const Gui3DMouseEvent &pEvent )
  334. {
  335. const Point3F pt0 = pEvent.pos;
  336. const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
  337. RayInfo ri;
  338. if ( !gServerContainer.collideBox( pt0, pt1, MarkerObjectType, &ri ) )
  339. {
  340. // No Object.
  341. return false;
  342. }
  343. VPath *path = dynamic_cast<VPath*>( ri.object );
  344. if ( !path )
  345. {
  346. // No Path Object.
  347. return false;
  348. }
  349. // No Node.
  350. S32 nodeIndex = -1;
  351. for ( VPathNodeIterator itr = path->mNodeList.begin(); itr != path->mNodeList.end(); itr++ )
  352. {
  353. VPathNode *node = ( *itr );
  354. Point3F projPosition;
  355. project( node->getWorldPosition(), &projPosition );
  356. if ( projPosition.z <= 0.0f )
  357. {
  358. continue;
  359. }
  360. const Point2I rectHalfSize( 8, 8 );
  361. const Point2I screenPosition( ( S32 )projPosition.x, ( S32 )projPosition.y );
  362. const RectI screenRect( screenPosition - rectHalfSize, 2 * rectHalfSize );
  363. // Mouse Close Enough?
  364. if ( screenRect.pointInRect( pEvent.mousePoint ) )
  365. {
  366. // Select Node.
  367. nodeIndex = ( itr - path->mNodeList.begin() );
  368. }
  369. }
  370. // Set Selection.
  371. updateSelection( path, nodeIndex );
  372. // Valid Selection.
  373. return true;
  374. }
  375. void VPathEditor::updateSelection( VPath *pPathObject, const S32 &pNodeIndex )
  376. {
  377. // Store Selection.
  378. mSelection.Path = pPathObject;
  379. mSelection.Node = pNodeIndex;
  380. // Quick Update.
  381. updateSelection();
  382. // Return Buffer.
  383. char buffer[2][32];
  384. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", ( pPathObject ) ? pPathObject->getId() : 0 );
  385. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  386. // Callback.
  387. Con::executef( this, "onUpdateSelection", buffer[0], buffer[1] );
  388. }
  389. void VPathEditor::updateSelection( void )
  390. {
  391. if ( !isValidSelection() )
  392. {
  393. // No Further Updates.
  394. return;
  395. }
  396. // Fetch Node.
  397. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  398. // Fetch Node Rotation Matrix.
  399. MatrixF mat;
  400. node->getWorldRotation().setMatrix( &mat );
  401. // Determine Tangent Axis.
  402. Point3F pt0( VPath::gBezierAxis * node->getWeight() );
  403. Point3F pt1( -VPath::gBezierAxis * node->getWeight() );
  404. // Rotate Axis.
  405. mat.mulP( pt0 );
  406. mat.mulP( pt1 );
  407. // Offset Points.
  408. pt0 += node->getWorldPosition();
  409. pt1 += node->getWorldPosition();
  410. // Store Points.
  411. mSelection.TangentHandle[0] = pt0;
  412. mSelection.TangentHandle[1] = pt1;
  413. }
  414. DefineEngineMethod( VPathEditor, clearSelection, void, (),, "( void )" )
  415. {
  416. // Clear Selection.
  417. object->updateSelection( NULL, -1 );
  418. }
  419. DefineEngineMethod(VPathEditor, setSelection, void, (SceneObject* sceneObject, S32 nodeIndex), (nullAsType<SceneObject*>(), -1), "( pObject, [pNodeIndex] )")
  420. {
  421. if (sceneObject == nullptr)
  422. {
  423. Con::errorf("VPathEditor::setSelection() - Unable to select target Object.");
  424. return;
  425. }
  426. // Fetch Path.
  427. VPath *path = dynamic_cast<VPath*>(sceneObject);
  428. if ( !path )
  429. {
  430. Con::errorf( "VPathEditor::setSelection() - Unable to select target Object." );
  431. return;
  432. }
  433. object->updateSelection( path, nodeIndex);
  434. }
  435. DefineEngineMethod( VPathEditor, isValidSelection, bool, (),, "( void )" )
  436. {
  437. return object->isValidSelection();
  438. }
  439. DefineEngineMethod( VPathEditor, getSelectedPath, S32, (),, "( void )" )
  440. {
  441. // Fetch Path.
  442. VPath *path = object->mSelection.Path;
  443. // Return ID.
  444. return ( path ) ? path->getId() : 0;
  445. }
  446. DefineEngineMethod( VPathEditor, getSelectedNode, S32, (),, "( void )" )
  447. {
  448. // Return Node Index.
  449. return ( object->mSelection.Path ) ? object->mSelection.Node : -1;
  450. }
  451. DefineEngineMethod( VPathEditor, deleteSelection, void, (),, "( void )" )
  452. {
  453. // Valid Selection?
  454. if ( object->isValidSelection() )
  455. {
  456. object->deleteNode( object->mSelection.Node );
  457. }
  458. }
  459. //-----------------------------------------------------------------------------
  460. //
  461. // Weight Editing Methods.
  462. //
  463. //-----------------------------------------------------------------------------
  464. bool VPathEditor::isEditingWeight( const Gui3DMouseEvent &pEvent )
  465. {
  466. if ( !isValidSelection() || mSelection.Path->mPathType != VPath::k_PathBezier )
  467. {
  468. // False.
  469. mEditWeight = false;
  470. // Invalid Selection.
  471. return false;
  472. }
  473. const Point3F pt0 = pEvent.pos;
  474. const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
  475. // Min Index.
  476. S32 minNode = -1;
  477. F32 minDistance = F32_MAX;
  478. for ( S32 i = 0; i < 2; i++ )
  479. {
  480. Point3F pt;
  481. if ( !Utility::FindNearestPointOnLine( mSelection.TangentHandle[i], pt0, pt1, &pt ) )
  482. {
  483. // Skip.
  484. continue;
  485. }
  486. // Distance.
  487. const F32 ptDistance = ( pt - mSelection.TangentHandle[i] ).len();
  488. if ( ptDistance < minDistance )
  489. {
  490. // Store Index.
  491. minNode = i;
  492. // Store Distance.
  493. minDistance = ptDistance;
  494. }
  495. }
  496. if ( minDistance > gSelectionDistance )
  497. {
  498. // False.
  499. mEditWeight = false;
  500. // Too Far Away.
  501. return false;
  502. }
  503. // True.
  504. mEditWeight = true;
  505. mEditWeightHandle = minNode;
  506. return true;
  507. }
  508. void VPathEditor::updateWeight( const Gui3DMouseEvent &pEvent )
  509. {
  510. if ( !isEditingWeight() )
  511. {
  512. // Woops!
  513. return;
  514. }
  515. // Fetch Current Node.
  516. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  517. Point3F nodePos = node->getWorldPosition();
  518. // Fetch Node Transform.
  519. MatrixF mat = node->getWorldTransform();
  520. // Fetch the Normal.
  521. const VectorF planeNormal = mat.getColumn3F( 0 );
  522. // Construct Plane.
  523. const PlaneF plane( nodePos, planeNormal );
  524. Point3F iPt;
  525. if ( plane.intersect( pEvent.pos, pEvent.vec, &iPt ) )
  526. {
  527. /*
  528. // Fetch Edit Vector.
  529. VectorF tangentVect( mSelection.TangentHandle[mEditWeightHandle] - nodePos );
  530. tangentVect.normalize();
  531. // Fetch Mouse Vector.
  532. VectorF mouseVec( iPt - nodePos );
  533. F32 mouseDist = mouseVec.len();
  534. mouseVec.normalize();
  535. // Find the Angles.
  536. F32 tangentAngle = mAtan2( -tangentVect.z, tangentVect.x );
  537. F32 mouseAngle = mAtan2( -mouseVec.z, mouseVec.x );
  538. // Determine Sign.
  539. const S32 sign = ( planeNormal.y > 0.f ) ? -1.f : 1.f;
  540. // Delta Rotation..
  541. const QuatF deltaRotation( AngAxisF( planeNormal, sign * ( mouseAngle - tangentAngle ) ) );
  542. // Calculate New Rotation.
  543. QuatF newRotation;
  544. newRotation.mul( nodePos, deltaRotation );
  545. // Apply Rotation.
  546. setNodeRotation( mSelection.Node, newRotation );
  547. */
  548. /*
  549. // Fetch Edit Vector.
  550. VectorF handleVec( mSelection.TangentHandle[mEditWeightHandle] - nodePos );
  551. handleVec.normalize();
  552. // Fetch Mouse Vector.
  553. VectorF mouseVec( iPt - nodePos );
  554. mouseVec.normalize();
  555. // Find the Angles.
  556. F32 handleAngle = Utility::GetPitch( handleVec ); //mAtan2( -handleVec.z, handleVec.x );
  557. F32 mouseAngle = Utility::GetPitch( mouseVec ); //mAtan2( -mouseVec.z, mouseVec.x );
  558. // Determine Sign.
  559. const S32 sign = ( planeNormal.y > 0.f ) ? -1.f : 1.f;
  560. // Delta Rotation.
  561. MatrixF rotMat;
  562. AngAxisF::RotateY( sign * ( mouseAngle - handleAngle ), &rotMat );
  563. // Rotate.
  564. mat.mul( rotMat );
  565. QuatF newRotation;
  566. newRotation.set( mat );
  567. // Apply Rotation.
  568. setNodeRotation( mSelection.Node, newRotation );
  569. */
  570. // Apply Weight.
  571. setNodeWeight( mSelection.Node, ( iPt - nodePos ).len() );
  572. }
  573. }
  574. //-----------------------------------------------------------------------------
  575. //
  576. // Path Editing Methods.
  577. //
  578. //-----------------------------------------------------------------------------
  579. void VPathEditor::setPathPosition( const Point3F &pPosition )
  580. {
  581. // Fetch Paths.
  582. VPath *serverPath = mSelection.Path;
  583. VPath *clientPath = getClientPath( serverPath );
  584. // Update Position.
  585. serverPath->setPosition( pPosition );
  586. clientPath->setPosition( pPosition );
  587. // Update Selection.
  588. updateSelection();
  589. }
  590. void VPathEditor::setPathRotation( const QuatF &pRotation )
  591. {
  592. // Determine the Matrix.
  593. MatrixF mat;
  594. pRotation.setMatrix( &mat );
  595. mat.setPosition( mSelection.Path->getPosition() );
  596. // Update Transform.
  597. setPathTransform( mat );
  598. }
  599. void VPathEditor::setPathTransform( const MatrixF &pTransform )
  600. {
  601. // Fetch Paths.
  602. VPath *serverPath = mSelection.Path;
  603. VPath *clientPath = getClientPath( serverPath );
  604. // Update Transform.
  605. serverPath->setTransform( pTransform );
  606. clientPath->setTransform( pTransform );
  607. // Update Selection.
  608. updateSelection();
  609. }
  610. void VPathEditor::setPathScale( const VectorF &pScale )
  611. {
  612. // Fetch Paths.
  613. VPath *serverPath = mSelection.Path;
  614. VPath *clientPath = getClientPath( serverPath );
  615. // Fetch Current Scale.
  616. VectorF scale = serverPath->getScale();
  617. scale.convolve( pScale );
  618. // Update Scale.
  619. serverPath->setScale( scale );
  620. clientPath->setScale( scale );
  621. // Update Selection.
  622. updateSelection();
  623. }
  624. //-----------------------------------------------------------------------------
  625. //
  626. // Node Editing Methods.
  627. //
  628. //-----------------------------------------------------------------------------
  629. bool VPathEditor::getPointOnPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
  630. {
  631. if ( pPath->getNodeCount() < 2 )
  632. {
  633. // Start / End Points.
  634. const Point3F pt0 = pEvent.pos;
  635. const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
  636. // Create Intersection Plane.
  637. const PlaneF plane( pPath->getPosition(), VPath::gBezierUp );
  638. // Intersection Point.
  639. Point3F intersectionPoint;
  640. if ( !plane.intersect( pEvent.pos, pEvent.vec, &intersectionPoint ) )
  641. {
  642. // No Intersection.
  643. return false;
  644. }
  645. // I'th Node.
  646. pNode = pPath->getNodeCount();
  647. // Set Identity.
  648. pTransform.identity();
  649. // Set Position.
  650. pTransform.setPosition( intersectionPoint );
  651. // Return.
  652. return true;
  653. }
  654. switch ( pPath->mPathType )
  655. {
  656. case VPath::k_PathLinear :
  657. {
  658. return getPointOnLinearPath( pPath, pEvent, pNode, pTransform );
  659. } break;
  660. case VPath::k_PathBezier :
  661. {
  662. return getPointOnBezierPath( pPath, pEvent, pNode, pTransform );
  663. } break;
  664. }
  665. return false;
  666. }
  667. bool VPathEditor::getPointOnLinearPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
  668. {
  669. // Start / End Points.
  670. const Point3F pt0 = pEvent.pos;
  671. const Point3F pt1 = pEvent.pos + pEvent.vec * gProjectDistance;
  672. S32 minNode = -1;
  673. F32 minDistance = F32_MAX;
  674. Point3F minPoint( 0.f, 0.f, 0.f );
  675. for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
  676. {
  677. // Fetch Nodes.
  678. VPathNode *srcNode = ( *itr );
  679. VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
  680. // Project to Screen.
  681. Point3F srcNodeScreenPosition, dstNodeScreenPosition;
  682. project( srcNode->getWorldPosition(), &srcNodeScreenPosition );
  683. project( dstNode->getWorldPosition(), &dstNodeScreenPosition );
  684. // Skip?
  685. if ( srcNodeScreenPosition.z > 1.f && dstNodeScreenPosition.z > 1.f )
  686. {
  687. continue;
  688. }
  689. Point3F ptOut0, ptOut1;
  690. F32 ptOutDistance;
  691. if ( !Utility::FindNearestDistanceBetweenLines( pt0, pt1,
  692. srcNode->getWorldPosition(), dstNode->getWorldPosition(),
  693. &ptOut0, &ptOut1, &ptOutDistance ) )
  694. {
  695. continue;
  696. }
  697. if ( ptOutDistance < minDistance )
  698. {
  699. minDistance = ptOutDistance;
  700. minPoint = ptOut1;
  701. minNode = ( itr - pPath->mNodeList.begin() );
  702. }
  703. }
  704. // Distance too Large?
  705. if ( minDistance > 0.25f )
  706. {
  707. // Invalid.
  708. return false;
  709. }
  710. // Setup.
  711. pTransform.identity();
  712. pTransform.setPosition( minPoint );
  713. // Store Node.
  714. pNode = minNode;
  715. return true;
  716. }
  717. bool VPathEditor::getPointOnBezierPath( VPath *pPath, const Gui3DMouseEvent &pEvent, S32 &pNode, MatrixF &pTransform )
  718. {
  719. S32 minNode = -1;
  720. F32 minInterp = 0.f;
  721. F32 minDistance = F32_MAX;
  722. Point3F minPoint( 0.f, 0.f, 0.f );
  723. for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
  724. {
  725. // Fetch Nodes.
  726. VPathNode *srcNode = ( *itr );
  727. VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
  728. // Project to Screen.
  729. Point3F srcNodeScreenPosition, dstNodeScreenPosition;
  730. project( srcNode->getWorldPosition(), &srcNodeScreenPosition );
  731. project( dstNode->getWorldPosition(), &dstNodeScreenPosition );
  732. // Skip?
  733. if ( srcNodeScreenPosition.z > 1.f && dstNodeScreenPosition.z > 1.f )
  734. {
  735. continue;
  736. }
  737. // Positions.
  738. const Point3F &pt0 = srcNode->getWorldPosition();
  739. const Point3F &pt3 = dstNode->getWorldPosition();
  740. // Fetch Node Rotation Matrices.
  741. MatrixF mat0, mat1;
  742. srcNode->getWorldRotation().setMatrix( &mat0 );
  743. dstNode->getWorldRotation().setMatrix( &mat1 );
  744. // Determine Tangent Axis.
  745. Point3F pt1( VPath::gBezierAxis * srcNode->getWeight() );
  746. Point3F pt2( -VPath::gBezierAxis * dstNode->getWeight() );
  747. // Rotate Axis.
  748. mat0.mulP( pt1 );
  749. mat1.mulP( pt2 );
  750. // Offset Points.
  751. pt1 += pt0;
  752. pt2 += pt3;
  753. for ( F32 t = 0.f, it = 1.f; t <= 1.f; t += 0.1f, it = ( 1.f - t ) )
  754. {
  755. // Calculate Position.
  756. Point3F pos = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
  757. // Determine the Screen Position.
  758. Point3F screenPos;
  759. project( pos, &screenPos );
  760. // Behind?
  761. if ( screenPos.z > 1.f )
  762. {
  763. // Skip Point.
  764. continue;
  765. }
  766. // Determine the Distance.
  767. F32 screenDistance = Point2F( screenPos.x - pEvent.mousePoint.x, screenPos.y - pEvent.mousePoint.y ).lenSquared();
  768. // Min Distance?
  769. if ( screenDistance < minDistance )
  770. {
  771. // Store.
  772. minDistance = screenDistance;
  773. minInterp = t;
  774. minPoint = pos;
  775. minNode = ( itr - pPath->mNodeList.begin() );
  776. }
  777. }
  778. }
  779. // Distance too Large?
  780. if ( minDistance > 1000.f )
  781. {
  782. // Invalid.
  783. return false;
  784. }
  785. // Fetch Orientation.
  786. const VectorF &orientation = pPath->getPathOrientation( pPath->getNode( minNode ),
  787. pPath->getNode( ( minNode + 1 ) % pPath->getNodeCount() ),
  788. minInterp, true );
  789. // Z-Axis.
  790. VectorF zVec = -orientation;
  791. zVec.normalize();
  792. // X-Axis.
  793. VectorF xVec = mCross( VPath::gBezierUp, zVec );
  794. xVec.normalize();
  795. // Y-Axis.
  796. VectorF yVec = mCross( zVec, xVec );
  797. yVec.normalize();
  798. // Setup Object Transform.
  799. pTransform.identity();
  800. pTransform.setColumn( 0, xVec );
  801. pTransform.setColumn( 1, -zVec );
  802. pTransform.setColumn( 2, yVec );
  803. // Set the Position.
  804. pTransform.setPosition( minPoint );
  805. // Store Node.
  806. pNode = minNode;
  807. return true;
  808. }
  809. void VPathEditor::addNode( const Gui3DMouseEvent &pEvent )
  810. {
  811. VPath *path = mSelection.Path;
  812. if ( !path )
  813. {
  814. // Woops!
  815. return;
  816. }
  817. // Min Index.
  818. S32 nodeIndex = -1;
  819. MatrixF nodeTransform( true );
  820. if ( !getPointOnPath( path, pEvent, nodeIndex, nodeTransform ) )
  821. {
  822. // Can't Add.
  823. return;
  824. }
  825. // Invert Transform.
  826. MatrixF pathTransform = mSelection.Path->getTransform();
  827. pathTransform.setPosition( Point3F::Zero );
  828. pathTransform.inverse();
  829. Point3F nodePosition = ( nodeTransform.getPosition() - mSelection.Path->getPosition() );
  830. pathTransform.mulP( nodePosition );
  831. // Node Rotation.
  832. nodeTransform.mul( pathTransform );
  833. QuatF nodeRotation( nodeTransform );
  834. // Node Weights.
  835. F32 nodeWeight = 10.f;
  836. // Add New Node.
  837. VPathNode *node = path->addNode( nodePosition, nodeRotation, nodeWeight, ++nodeIndex );
  838. // Valid Node?
  839. if ( !node )
  840. {
  841. return;
  842. }
  843. // Update Size.
  844. path->updateContainer();
  845. // Calculate Path.
  846. path->calculatePath();
  847. UndoManager *historyManager = NULL;
  848. if ( !Sim::findObject( "EUndoManager", historyManager ) )
  849. {
  850. Con::errorf( "VPathEditor::addNode() - EUndoManager not found!" );
  851. return;
  852. }
  853. // Create Undo Action.
  854. VPathEditorAddNodeAction *editAction = new VPathEditorAddNodeAction();
  855. // Store Editor.
  856. editAction->mEditor = this;
  857. // Store Node Details.
  858. editAction->mPath = path;
  859. editAction->mNodeIndex = nodeIndex;
  860. editAction->mNodePosition = nodePosition;
  861. editAction->mNodeRotation = nodeRotation;
  862. editAction->mNodeWeight = nodeWeight;
  863. // Add To Manager.
  864. historyManager->addAction( editAction );
  865. // Set World Editor Dirty.
  866. setWorldEditorDirty();
  867. }
  868. void VPathEditor::deleteNode( const S32 &pNodeIndex )
  869. {
  870. VPath *path = mSelection.Path;
  871. if ( !path )
  872. {
  873. // Woops!
  874. return;
  875. }
  876. // Fetch Node Properites.
  877. VPathNode *node = path->getNode( pNodeIndex );
  878. const Point3F position = node->getLocalPosition();
  879. const QuatF rotation = node->getLocalRotation();
  880. const F32 weight = node->getWeight();
  881. // Delete Node.
  882. path->deleteNode( pNodeIndex );
  883. // Update Path.
  884. path->updateContainer();
  885. // Calculate Path.
  886. path->calculatePath();
  887. // Selected Node?
  888. const S32 _nodeIndex = pNodeIndex;
  889. if ( pNodeIndex == mSelection.Node )
  890. {
  891. // Update Selection.
  892. updateSelection( mSelection.Path, -1 );
  893. }
  894. UndoManager *historyManager = NULL;
  895. if ( !Sim::findObject( "EUndoManager", historyManager ) )
  896. {
  897. Con::errorf( "VPathEditor::deleteNode() - EUndoManager not found!" );
  898. return;
  899. }
  900. // Create Undo Action.
  901. VPathEditorDeleteNodeAction *editAction = new VPathEditorDeleteNodeAction();
  902. // Store Editor.
  903. editAction->mEditor = this;
  904. // Store Node Details.
  905. editAction->mPath = path;
  906. editAction->mNodeIndex = _nodeIndex;
  907. editAction->mNodePosition = position;
  908. editAction->mNodeRotation = rotation;
  909. editAction->mNodeWeight = weight;
  910. // Add To Manager.
  911. historyManager->addAction( editAction );
  912. // Set World Editor Dirty.
  913. setWorldEditorDirty();
  914. }
  915. void VPathEditor::setNodePosition( const S32 &pNodeIndex, const Point3F &pPosition )
  916. {
  917. // Fetch Paths.
  918. VPath *serverPath = mSelection.Path;
  919. VPath *clientPath = getClientPath( serverPath );
  920. // Sanity!
  921. if ( !serverPath || !clientPath )
  922. {
  923. return;
  924. }
  925. // Change?
  926. if ( serverPath->getNodeLocalPosition( pNodeIndex ) == pPosition )
  927. {
  928. return;
  929. }
  930. // Set Position.
  931. serverPath->setNodePosition( pNodeIndex, pPosition );
  932. clientPath->setNodePosition( pNodeIndex, pPosition );
  933. // Update Selection.
  934. updateSelection();
  935. // Dirty.
  936. mIsDirty = true;
  937. mNodeEdit.Dirty = true;
  938. // Arg Buffer.
  939. char buffer[3][32];
  940. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
  941. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  942. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
  943. // Callback.
  944. Con::executef( this, "onUpdateNodePosition", buffer[0], buffer[1], buffer[2] );
  945. }
  946. void VPathEditor::setNodeRotation( const S32 &pNodeIndex, const QuatF &pRotation )
  947. {
  948. // Fetch Paths.
  949. VPath *serverPath = mSelection.Path;
  950. VPath *clientPath = getClientPath( serverPath );
  951. // Sanity!
  952. if ( !serverPath || !clientPath )
  953. {
  954. return;
  955. }
  956. // Change?
  957. if ( serverPath->getNodeLocalRotation( pNodeIndex ) == pRotation )
  958. {
  959. return;
  960. }
  961. // Set Position.
  962. serverPath->setNodeRotation( pNodeIndex, pRotation );
  963. clientPath->setNodeRotation( pNodeIndex, pRotation );
  964. // Update Selection.
  965. updateSelection();
  966. // Dirty.
  967. mIsDirty = true;
  968. mNodeEdit.Dirty = true;
  969. // Arg Buffer.
  970. char buffer[3][32];
  971. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
  972. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  973. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
  974. // Callback.
  975. Con::executef( this, "onUpdateNodeRotation", buffer[0], buffer[1], buffer[2] );
  976. }
  977. void VPathEditor::setNodeWeight( const S32 &pNodeIndex, const F32 &pWeight )
  978. {
  979. // Fetch Paths.
  980. VPath *serverPath = mSelection.Path;
  981. VPath *clientPath = getClientPath( serverPath );
  982. // Sanity!
  983. if ( !serverPath || !clientPath )
  984. {
  985. return;
  986. }
  987. // Change?
  988. if ( serverPath->getNodeWeight( pNodeIndex ) == pWeight )
  989. {
  990. return;
  991. }
  992. // Set Weight.
  993. serverPath->setNodeWeight( pNodeIndex, pWeight );
  994. clientPath->setNodeWeight( pNodeIndex, pWeight );
  995. // Update Selection.
  996. updateSelection();
  997. // Dirty.
  998. mIsDirty = true;
  999. mNodeEdit.Dirty = true;
  1000. // Arg Buffer.
  1001. char buffer[3][32];
  1002. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
  1003. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  1004. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
  1005. // Callback.
  1006. Con::executef( this, "onUpdateNodeWeight", buffer[0], buffer[1], buffer[2] );
  1007. }
  1008. void VPathEditor::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType )
  1009. {
  1010. // Fetch Paths.
  1011. VPath *serverPath = mSelection.Path;
  1012. VPath *clientPath = getClientPath( serverPath );
  1013. // Sanity!
  1014. if ( !serverPath || !clientPath )
  1015. {
  1016. return;
  1017. }
  1018. // Set Orientation Mode.
  1019. serverPath->setNodeOrientationMode( pNodeIndex, pType );
  1020. clientPath->setNodeOrientationMode( pNodeIndex, pType );
  1021. // Dirty.
  1022. mIsDirty = true;
  1023. mNodeEdit.Dirty = true;
  1024. // Arg Buffer.
  1025. char buffer[3][32];
  1026. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
  1027. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  1028. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
  1029. // Callback.
  1030. Con::executef( this, "onUpdateNodeOrientation", buffer[0], buffer[1], buffer[2] );
  1031. }
  1032. void VPathEditor::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType, const Point3F &pPoint )
  1033. {
  1034. // Fetch Paths.
  1035. VPath *serverPath = mSelection.Path;
  1036. VPath *clientPath = getClientPath( serverPath );
  1037. // Sanity!
  1038. if ( !serverPath || !clientPath )
  1039. {
  1040. return;
  1041. }
  1042. // Set Orientation Mode.
  1043. serverPath->setNodeOrientationMode( pNodeIndex, pType, pPoint );
  1044. clientPath->setNodeOrientationMode( pNodeIndex, pType, pPoint );
  1045. // Dirty.
  1046. mIsDirty = true;
  1047. mNodeEdit.Dirty = true;
  1048. // Arg Buffer.
  1049. char buffer[3][32];
  1050. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mSelection.Path->getId() );
  1051. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pNodeIndex );
  1052. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mSelection.Node == pNodeIndex ) );
  1053. // Callback.
  1054. Con::executef( this, "onUpdateNodeOrientation", buffer[0], buffer[1], buffer[2] );
  1055. }
  1056. void VPathEditor::pushPathEdit( void )
  1057. {
  1058. // Clear Current Edit Dirty.
  1059. mPathEdit.Dirty = false;
  1060. if ( mSelection.Path != NULL )
  1061. {
  1062. // Store Node Details.
  1063. mPathEdit.Transform = mSelection.Path->getTransform();
  1064. }
  1065. }
  1066. void VPathEditor::popPathEdit( void )
  1067. {
  1068. // Did Edit?
  1069. if ( mPathEdit.Dirty && mSelection.Path != NULL )
  1070. {
  1071. UndoManager *historyManager = NULL;
  1072. if ( !Sim::findObject( "EUndoManager", historyManager ) )
  1073. {
  1074. Con::errorf( "VPathEditor - EUndoManager not found!" );
  1075. return;
  1076. }
  1077. // Create Undo Action.
  1078. VPathEditorEditPathAction *editAction = new VPathEditorEditPathAction( "Edit Path" );
  1079. // Store Editor.
  1080. editAction->mEditor = this;
  1081. // Store Path Details.
  1082. editAction->mPath = mSelection.Path;
  1083. editAction->mTransform = mPathEdit.Transform;
  1084. // Add To Manager.
  1085. historyManager->addAction( editAction );
  1086. // Clear Dirty.
  1087. mPathEdit.Dirty = false;
  1088. // Set World Editor Dirty.
  1089. setWorldEditorDirty();
  1090. }
  1091. }
  1092. void VPathEditor::pushNodeEdit( void )
  1093. {
  1094. // Clear Current Edit Dirty.
  1095. mNodeEdit.Dirty = false;
  1096. if ( isValidSelection() )
  1097. {
  1098. // Fetch Node.
  1099. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  1100. // Store Node Details.
  1101. mNodeEdit.Position = node->getLocalPosition();
  1102. mNodeEdit.Rotation = node->getLocalRotation();
  1103. mNodeEdit.Weight = node->getWeight();
  1104. }
  1105. }
  1106. void VPathEditor::popNodeEdit( void )
  1107. {
  1108. // Did Edit?
  1109. if ( mNodeEdit.Dirty && isValidSelection() )
  1110. {
  1111. UndoManager *historyManager = NULL;
  1112. if ( !Sim::findObject( "EUndoManager", historyManager ) )
  1113. {
  1114. Con::errorf( "VPathEditor - EUndoManager not found!" );
  1115. return;
  1116. }
  1117. // Create Undo Action.
  1118. VPathEditorEditNodeAction *editAction = new VPathEditorEditNodeAction( "Edit Node" );
  1119. // Store Editor.
  1120. editAction->mEditor = this;
  1121. // Store Node Details.
  1122. editAction->mPath = mSelection.Path;
  1123. editAction->mNodeIndex = mSelection.Node;
  1124. editAction->mNodePosition = mNodeEdit.Position;
  1125. editAction->mNodeRotation = mNodeEdit.Rotation;
  1126. editAction->mNodeWeight = mNodeEdit.Weight;
  1127. editAction->mNodeOrientation = mSelection.Path->getNode( mSelection.Node )->getOrientationMode();
  1128. // Add To Manager.
  1129. historyManager->addAction( editAction );
  1130. // Clear Dirty.
  1131. mNodeEdit.Dirty = false;
  1132. // Set World Editor Dirty.
  1133. setWorldEditorDirty();
  1134. }
  1135. }
  1136. void VPathEditor::setWorldEditorDirty( void )
  1137. {
  1138. WorldEditor *worldEditor;
  1139. if ( Sim::findObject( "EWorldEditor", worldEditor ) )
  1140. {
  1141. worldEditor->setDirty();
  1142. }
  1143. }
  1144. //-----------------------------------------------------------------------------
  1145. //
  1146. // Render Methods.
  1147. //
  1148. //-----------------------------------------------------------------------------
  1149. void VPathEditor::setStateBlock( void )
  1150. {
  1151. // Valid State Block?
  1152. if ( !mStateBlock )
  1153. {
  1154. // Setup Definition.
  1155. GFXStateBlockDesc def;
  1156. def.blendDefined = true;
  1157. def.blendEnable = true;
  1158. def.blendSrc = GFXBlendSrcAlpha;
  1159. def.blendDest = GFXBlendInvSrcAlpha;
  1160. def.zDefined = true;
  1161. def.cullDefined = false;
  1162. // Create State Block.
  1163. mStateBlock = GFX->createStateBlock( def );
  1164. }
  1165. // Set State Block.
  1166. GFX->setStateBlock( mStateBlock );
  1167. }
  1168. void VPathEditor::renderScene( const RectI &pUpdateRect )
  1169. {
  1170. // Setup State Block.
  1171. setStateBlock();
  1172. if ( isValidSelection() )
  1173. {
  1174. // Fetch Current Node.
  1175. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  1176. // Render Gizmo?
  1177. if ( mEditMode == k_Gizmo && mGizmoProfile->mode != ScaleMode )
  1178. {
  1179. // Fetch Node Transform.
  1180. MatrixF mat= node->getWorldTransform();
  1181. // Move Gizmo.
  1182. mGizmo->set( mat, node->getWorldPosition(), Point3F( 1.0f, 1.0f, 1.0f ) );
  1183. // Render Gizmo.
  1184. mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix );
  1185. }
  1186. // Render Handles?
  1187. if ( mSelection.Path->mPathType == VPath::k_PathBezier )
  1188. {
  1189. // Fetch Tangent Handles.
  1190. const Point3F &pt0 = mSelection.TangentHandle[0];
  1191. const Point3F &pt1 = mSelection.TangentHandle[1];
  1192. // State Block.
  1193. GFXStateBlockDesc desc;
  1194. desc.setZReadWrite( true, true );
  1195. desc.fillMode = GFXFillSolid;
  1196. // Set Color.
  1197. PrimBuild::color( gPathColorSel );
  1198. // Render Line.
  1199. PrimBuild::begin( GFXLineList, 2 );
  1200. PrimBuild::vertex3fv( pt0 );
  1201. PrimBuild::vertex3fv( pt1 );
  1202. PrimBuild::end();
  1203. // Render Handles.
  1204. GFX->getDrawUtil()->drawSphere( desc, 0.1f, pt0, gPathColorSel );
  1205. GFX->getDrawUtil()->drawSphere( desc, 0.1f, pt1, gPathColorSel );
  1206. }
  1207. // ToPoint Node?
  1208. if ( node->getOrientationMode().Type == VPathNode::k_OrientationToPoint )
  1209. {
  1210. PrimBuild::color( gNodeLookAtPointColor );
  1211. PrimBuild::begin( GFXLineStrip, 2 );
  1212. PrimBuild::vertex3fv( node->getWorldPosition() );
  1213. PrimBuild::vertex3fv( node->getOrientationMode().Point );
  1214. PrimBuild::end();
  1215. }
  1216. }
  1217. else if ( mSelection.Path && mEditMode == k_Gizmo )
  1218. {
  1219. switch ( mGizmoProfile->mode )
  1220. {
  1221. case MoveMode:
  1222. {
  1223. // Fetch Path Transform.
  1224. const MatrixF &mat = mSelection.Path->getTransform();
  1225. // Fetch the Path's Box Center.
  1226. const Point3F &pos = mSelection.Path->getWorldBox().getCenter();
  1227. // Move Gizmo.
  1228. mGizmo->set( mat, pos, Point3F( 1.0f, 1.0f, 1.0f ) );
  1229. // Render Gizmo.
  1230. mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix );
  1231. } break;
  1232. }
  1233. }
  1234. // Render Path Segments.
  1235. renderPaths( k_RenderSegments );
  1236. // Set Clip Rect.
  1237. GFX->setClipRect( pUpdateRect );
  1238. // Render Path Nodes.
  1239. renderPaths( k_RenderNodes );
  1240. if ( isValidSelection() )
  1241. {
  1242. // Fetch Current Node.
  1243. VPathNode *node = mSelection.Path->getNode( mSelection.Node );
  1244. // ToPoint Node?
  1245. if ( node->getOrientationMode().Type == VPathNode::k_OrientationToPoint )
  1246. {
  1247. // Project to Screen.
  1248. Point3F screenPosition;
  1249. project( node->getOrientationMode().Point, &screenPosition );
  1250. if ( screenPosition.z <= 1.0f )
  1251. {
  1252. // Determine the center & size of the node rectangle.
  1253. Point2I nodeCenter = Point2I( screenPosition.x, screenPosition.y );
  1254. Point2I nodeHalfSize = Point2I( 8, 8 );
  1255. // Determine Render Rectangle.
  1256. RectI nodeRect;
  1257. nodeRect.point = nodeCenter - nodeHalfSize;
  1258. nodeRect.extent = ( 2 * nodeHalfSize );
  1259. // Draw?
  1260. if ( getBounds().overlaps( nodeRect ) )
  1261. {
  1262. // Render the Point.
  1263. GFX->getDrawUtil()->drawRectFill( nodeRect, gNodeLookAtPointColor );
  1264. }
  1265. }
  1266. }
  1267. }
  1268. }
  1269. void VPathEditor::renderPaths( const RenderType &pRenderType )
  1270. {
  1271. SimSet *objectSet = VPath::getServerSet();
  1272. for ( SimSetIterator itr( objectSet ); *itr; ++itr )
  1273. {
  1274. VPath *path = dynamic_cast<VPath*>( *itr );
  1275. if ( path )
  1276. {
  1277. // Render Path.
  1278. renderPath( pRenderType, path, ( path == mSelection.Path ) ? gPathColorSel : gPathColor );
  1279. }
  1280. }
  1281. }
  1282. void VPathEditor::renderPath( const RenderType &pRenderType, VPath *pPath, const ColorI &pColor )
  1283. {
  1284. if ( !pPath )
  1285. {
  1286. // Sanity!
  1287. return;
  1288. }
  1289. switch ( pRenderType )
  1290. {
  1291. case k_RenderSegments :
  1292. {
  1293. switch ( pPath->mPathType )
  1294. {
  1295. case VPath::k_PathLinear :
  1296. {
  1297. renderLinearPath( pPath, pColor );
  1298. } break;
  1299. case VPath::k_PathBezier :
  1300. {
  1301. renderBezierPath( pPath, pColor );
  1302. } break;
  1303. }
  1304. } break;
  1305. case k_RenderNodes :
  1306. {
  1307. // Fetch Draw Util.
  1308. GFXDrawUtil *drawUtil = GFX->getDrawUtil();
  1309. // Fetch Bounds.
  1310. RectI bounds = getBounds();
  1311. const Point2I nodeMinHalfSize( 8, 8 );
  1312. for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
  1313. {
  1314. // Fetch Node.
  1315. VPathNode *node = ( *itr );
  1316. // Project to Screen.
  1317. Point3F screenPosition;
  1318. project( node->getWorldPosition(), &screenPosition );
  1319. if ( screenPosition.z > 1.0f )
  1320. {
  1321. continue;
  1322. }
  1323. // Determine the node text information.
  1324. const char *nodeText = avar( "%d", ( itr - pPath->mNodeList.begin() ) );
  1325. const Point2I nodeTextHalfSize = Point2I( 0.5f * (F32)getControlProfile()->mFont->getStrWidth( nodeText ),
  1326. 0.5f * (F32)getControlProfile()->mFont->getHeight() );
  1327. // Determine the center & size of the node rectangle.
  1328. Point2I nodeCenter = Point2I( screenPosition.x, screenPosition.y );
  1329. Point2I nodeHalfSize = Point2I( nodeTextHalfSize.x + 3, nodeTextHalfSize.y + 3 );
  1330. nodeHalfSize.setMax( nodeMinHalfSize );
  1331. // Determine Render Rectangle.
  1332. RectI nodeRect;
  1333. nodeRect.point = nodeCenter - nodeHalfSize;
  1334. nodeRect.extent = ( 2 * nodeHalfSize );
  1335. // Draw?
  1336. if ( !bounds.overlaps( nodeRect ) )
  1337. {
  1338. continue;
  1339. }
  1340. // Render the Point.
  1341. drawUtil->drawRectFill( nodeRect, pColor );
  1342. // Draw the node index text.
  1343. drawUtil->setBitmapModulation( getControlProfile()->mFontColor );
  1344. drawUtil->drawText( getControlProfile()->mFont, nodeCenter - nodeTextHalfSize, nodeText );
  1345. }
  1346. } break;
  1347. }
  1348. }
  1349. void VPathEditor::renderLinearPath( VPath *pPath, const ColorI &pColor )
  1350. {
  1351. if ( pPath->mNodeList.size() < 2 )
  1352. {
  1353. // No Lines.
  1354. return;
  1355. }
  1356. PrimBuild::color( pColor );
  1357. PrimBuild::begin( GFXLineStrip, ( pPath->mNodeList.size() + 1 ) );
  1358. for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
  1359. {
  1360. // Apply Vertex.
  1361. PrimBuild::vertex3fv( ( *itr )->getWorldPosition() );
  1362. }
  1363. // Loop Back.
  1364. PrimBuild::vertex3fv( pPath->mNodeList.front()->getWorldPosition() );
  1365. PrimBuild::end();
  1366. }
  1367. void VPathEditor::renderBezierPath( VPath *pPath, const ColorI &pColor )
  1368. {
  1369. if ( pPath->mNodeList.size() < 2 )
  1370. {
  1371. // No Lines.
  1372. return;
  1373. }
  1374. PrimBuild::color( pColor );
  1375. PrimBuild::begin( GFXLineStrip, U32( ( ( 1.01f / 0.01f ) + 1 ) * pPath->mNodeList.size() ) );
  1376. for ( VPathNodeIterator itr = pPath->mNodeList.begin(); itr != pPath->mNodeList.end(); itr++ )
  1377. {
  1378. // Fetch Nodes.
  1379. VPathNode *srcNode = ( *itr );
  1380. VPathNode *dstNode = ( itr == ( pPath->mNodeList.end() - 1 ) ) ? ( *( pPath->mNodeList.begin() ) ) : ( *( itr + 1 ) );
  1381. // Positions.
  1382. const Point3F &pt0 = srcNode->getWorldPosition();
  1383. const Point3F &pt3 = dstNode->getWorldPosition();
  1384. // Fetch Node Rotation Matrices.
  1385. MatrixF mat0, mat1;
  1386. srcNode->getWorldRotation().setMatrix( &mat0 );
  1387. dstNode->getWorldRotation().setMatrix( &mat1 );
  1388. // Determine Tangent Axis.
  1389. Point3F pt1( VPath::gBezierAxis * srcNode->getWeight() );
  1390. Point3F pt2( -VPath::gBezierAxis * dstNode->getWeight() );
  1391. // Rotate Axis.
  1392. mat0.mulP( pt1 );
  1393. mat1.mulP( pt2 );
  1394. // Offset Points.
  1395. pt1 += pt0;
  1396. pt2 += pt3;
  1397. for ( F32 t = 0.f, it = 1.f; t <= 1.f; t += 0.01f, it = ( 1.f - t ) )
  1398. {
  1399. // Calculate Position.
  1400. Point3F pos = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
  1401. // Apply Vertex.
  1402. PrimBuild::vertex3fv( pos );
  1403. }
  1404. }
  1405. PrimBuild::end();
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. //
  1409. // History Events
  1410. //
  1411. //-----------------------------------------------------------------------------
  1412. void VPathEditor::VPathEditorEditPathAction::undo( void )
  1413. {
  1414. const MatrixF oldTransform = mTransform;
  1415. const MatrixF newTransform = mPath->getTransform();
  1416. // Apply Old Values.
  1417. mEditor->setPathTransform( oldTransform );
  1418. // The ol' Switcheroo.
  1419. mTransform = newTransform;
  1420. // Update Selection.
  1421. mEditor->updateSelection();
  1422. if ( mPath == mEditor->mSelection.Path )
  1423. {
  1424. // Arg Buffer.
  1425. char buffer[32];
  1426. dSprintf( buffer, sizeof( buffer ), "%d", mPath->getId() );
  1427. // Callback.
  1428. Con::executef( mEditor, "onUpdatePath", buffer );
  1429. }
  1430. // Set World Editor Dirty.
  1431. mEditor->setWorldEditorDirty();
  1432. }
  1433. void VPathEditor::VPathEditorEditPathAction::redo( void )
  1434. {
  1435. // Undo.
  1436. undo();
  1437. }
  1438. void VPathEditor::VPathEditorEditNodeAction::undo( void )
  1439. {
  1440. // Fetch Properties.
  1441. const Point3F oldPosition = mNodePosition;
  1442. const QuatF oldRotation = mNodeRotation;
  1443. const F32 oldWeight = mNodeWeight;
  1444. const VPathNode::sOrientation oldOrientation = mNodeOrientation;
  1445. VPathNode *node = mPath->getNode( mNodeIndex );
  1446. const Point3F newPosition = node->getLocalPosition();
  1447. const QuatF newRotation = node->getLocalRotation();
  1448. const F32 newWeight = node->getWeight();
  1449. const VPathNode::sOrientation newOrientation = node->getOrientationMode();
  1450. // Apply Old Values.
  1451. mPath->setNodePosition( mNodeIndex, oldPosition );
  1452. mPath->setNodeRotation( mNodeIndex, oldRotation );
  1453. mPath->setNodeWeight( mNodeIndex, oldWeight );
  1454. switch( oldOrientation.Type )
  1455. {
  1456. case VPathNode::k_OrientationFree :
  1457. {
  1458. // Orient Free.
  1459. mPath->setNodeOrientationMode( mNodeIndex, oldOrientation.Type );
  1460. } break;
  1461. case VPathNode::k_OrientationToPoint :
  1462. {
  1463. // Orient To Point.
  1464. mPath->setNodeOrientationMode( mNodeIndex, oldOrientation.Type, oldOrientation.Point );
  1465. } break;
  1466. }
  1467. // The ol' Switcheroo.
  1468. mNodePosition = newPosition;
  1469. mNodeRotation = newRotation;
  1470. mNodeWeight = newWeight;
  1471. mNodeOrientation = newOrientation;
  1472. // Update Selection.
  1473. mEditor->updateSelection();
  1474. if ( mPath == mEditor->mSelection.Path )
  1475. {
  1476. // Arg Buffer.
  1477. char buffer[3][32];
  1478. dSprintf( buffer[0], sizeof( buffer[0] ), "%d", mPath->getId() );
  1479. dSprintf( buffer[1], sizeof( buffer[1] ), "%d", mNodeIndex );
  1480. dSprintf( buffer[2], sizeof( buffer[2] ), "%d", ( mEditor->mSelection.Node == mNodeIndex ) );
  1481. // Callback.
  1482. Con::executef( mEditor, "onUpdateNode", buffer[0], buffer[1], buffer[2] );
  1483. }
  1484. // Set World Editor Dirty.
  1485. mEditor->setWorldEditorDirty();
  1486. }
  1487. void VPathEditor::VPathEditorEditNodeAction::redo( void )
  1488. {
  1489. // Undo.
  1490. undo();
  1491. }
  1492. void VPathEditor::VPathEditorAddNodeAction::undo( void )
  1493. {
  1494. // Selected Node?
  1495. if ( mNodeIndex == mEditor->mSelection.Node )
  1496. {
  1497. // Update Selection.
  1498. mEditor->updateSelection( mEditor->mSelection.Path, -1 );
  1499. }
  1500. // Delete Node.
  1501. mPath->deleteNode( mNodeIndex );
  1502. // Update Size.
  1503. mPath->updateContainer();
  1504. // Calculate Path.
  1505. mPath->calculatePath();
  1506. // Set World Editor Dirty.
  1507. mEditor->setWorldEditorDirty();
  1508. }
  1509. void VPathEditor::VPathEditorAddNodeAction::redo( void )
  1510. {
  1511. // Add Node.
  1512. VPathNode *node = mPath->addNode( mNodePosition, mNodeRotation, mNodeWeight, mNodeIndex );
  1513. // Valid Node?
  1514. if ( node )
  1515. {
  1516. // Update Size.
  1517. mPath->updateContainer();
  1518. // Calculate Path.
  1519. mPath->calculatePath();
  1520. }
  1521. // Set World Editor Dirty.
  1522. mEditor->setWorldEditorDirty();
  1523. }
  1524. void VPathEditor::VPathEditorDeleteNodeAction::undo( void )
  1525. {
  1526. // Add Node.
  1527. VPathNode *node = mPath->addNode( mNodePosition, mNodeRotation, mNodeWeight, mNodeIndex );
  1528. // Valid Node?
  1529. if ( node )
  1530. {
  1531. // Update Size.
  1532. mPath->updateContainer();
  1533. // Calculate Path.
  1534. mPath->calculatePath();
  1535. }
  1536. // Set World Editor Dirty.
  1537. mEditor->setWorldEditorDirty();
  1538. }
  1539. void VPathEditor::VPathEditorDeleteNodeAction::redo( void )
  1540. {
  1541. // Delete Node.
  1542. mPath->deleteNode( mNodeIndex );
  1543. // Update Size.
  1544. mPath->updateContainer();
  1545. // Calculate Path.
  1546. mPath->calculatePath();
  1547. // Set World Editor Dirty.
  1548. mEditor->setWorldEditorDirty();
  1549. }
  1550. //-----------------------------------------------------------------------------
  1551. //
  1552. // Script Edit Methods
  1553. //
  1554. //-----------------------------------------------------------------------------
  1555. DefineEngineMethod( VPathEditor, setNodePosition, void, (Point3F position), (Point3F::Zero), "( pPosition )" )
  1556. {
  1557. // Valid Selection?
  1558. if ( !object->isValidSelection() )
  1559. {
  1560. Con::warnf( "VPathEditor::setNodePosition() - Invalid Node Selection." );
  1561. return;
  1562. }
  1563. // Store.
  1564. object->pushNodeEdit();
  1565. // Apply Update.
  1566. object->setNodePosition( object->mSelection.Node, position );
  1567. // Create Undo Action.
  1568. object->popNodeEdit();
  1569. }
  1570. DefineEngineMethod( VPathEditor, setNodeRotation, void, (AngAxisF aa), (AngAxisF( Point3F( 0, 0, 1 ), 0)), "( pRotation )" )
  1571. {
  1572. // Valid Selection?
  1573. if ( !object->isValidSelection() )
  1574. {
  1575. Con::warnf( "VPathEditor::setNodeRotation() - Invalid Node Selection." );
  1576. return;
  1577. }
  1578. // Fetch Rotation.
  1579. QuatF rotation;
  1580. // Set Rotation.
  1581. rotation.set( aa );
  1582. // Store.
  1583. object->pushNodeEdit();
  1584. // Apply Update.
  1585. object->setNodeRotation( object->mSelection.Node, rotation );
  1586. // Create Undo Action.
  1587. object->popNodeEdit();
  1588. }
  1589. DefineEngineMethod( VPathEditor, setNodeWeight, void, (F32 weight), (1), "( pWeight )" )
  1590. {
  1591. // Valid Selection?
  1592. if ( !object->isValidSelection() )
  1593. {
  1594. Con::warnf( "VPathEditor::setNodeWeight() - Invalid Node Selection." );
  1595. return;
  1596. }
  1597. // Store.
  1598. object->pushNodeEdit();
  1599. // Apply Update.
  1600. object->setNodeWeight( object->mSelection.Node, weight);
  1601. // Create Undo Action.
  1602. object->popNodeEdit();
  1603. }
  1604. DefineEngineMethod( VPathEditor, setNodeOrientationMode, void, (String orientationType, Point3F lookAtPoint), ("", Point3F::One), "( string pOrientationType, [vector pPoint] )" )
  1605. {
  1606. // Valid Selection?
  1607. if ( !object->isValidSelection() )
  1608. {
  1609. Con::warnf( "VPathEditor::setNodeOrientationMode() - Invalid Node Selection." );
  1610. return;
  1611. }
  1612. // Store.
  1613. object->pushNodeEdit();
  1614. // Orient?
  1615. const VPathNode::eOrientationType type = VPathNode::getOrientationTypeEnum(orientationType);
  1616. switch ( type )
  1617. {
  1618. case VPathNode::k_OrientationFree :
  1619. {
  1620. // Apply Mode.
  1621. object->setNodeOrientationMode( object->mSelection.Node, type );
  1622. } break;
  1623. case VPathNode::k_OrientationToPoint:
  1624. {
  1625. // Apply Mode.
  1626. object->setNodeOrientationMode( object->mSelection.Node, type, lookAtPoint );
  1627. } break;
  1628. }
  1629. // Create Undo Action.
  1630. object->popNodeEdit();
  1631. }
  1632. //-----------------------------------------------------------------------------
  1633. //
  1634. // Utility
  1635. //
  1636. //-----------------------------------------------------------------------------
  1637. bool Utility::FindNearestDistanceBetweenLines( const Point3F &pA0, const Point3F &pA1, const Point3F &pB0, const Point3F &pB1, Point3F *pOutA, Point3F *pOutB, F32 *pDist )
  1638. {
  1639. const Point3F pA1A0 = ( pA1 - pA0 );
  1640. if ( pA1A0.isZero() )
  1641. {
  1642. return false;
  1643. }
  1644. const Point3F pB1B0 = ( pB1 - pB0 );
  1645. if ( pB1B0.isZero() )
  1646. {
  1647. return false;
  1648. }
  1649. const Point3F pA0B0 = ( pA0 - pB0 );
  1650. const F32 &d1343 = pA0B0.x * pB1B0.x + pA0B0.y * pB1B0.y + pA0B0.z * pB1B0.z;
  1651. const F32 &d4321 = pB1B0.x * pA1A0.x + pB1B0.y * pA1A0.y + pB1B0.z * pA1A0.z;
  1652. const F32 &d1321 = pA0B0.x * pA1A0.x + pA0B0.y * pA1A0.y + pA0B0.z * pA1A0.z;
  1653. const F32 &d4343 = pB1B0.x * pB1B0.x + pB1B0.y * pB1B0.y + pB1B0.z * pB1B0.z;
  1654. const F32 &d2121 = pA1A0.x * pA1A0.x + pA1A0.y * pA1A0.y + pA1A0.z * pA1A0.z;
  1655. const F32 &denom = d2121 * d4343 - d4321 * d4321;
  1656. if ( mIsZero( denom ) )
  1657. {
  1658. return false;
  1659. }
  1660. const F32 &mua = ( d1343 * d4321 - d1321 * d4343 ) / denom;
  1661. const F32 &mub = ( d1343 + d4321 * mua ) / d4343;
  1662. *pOutA = pA0 + mua *pA1A0;
  1663. *pOutB = pB0 + mub *pB1B0;
  1664. // Store Distance.
  1665. *pDist = ( ( *pOutA ) - ( *pOutB ) ).len();
  1666. return true;
  1667. }
  1668. bool Utility::IntersectLineSegment( const Point3F &pA0, const Point3F &pA1, const Point3F &pB0, const Point3F &pB1, const bool pSnap, Point3F *pX )
  1669. {
  1670. //
  1671. // Finding the intersection with the following method:
  1672. // We have line a going from P1 to P2:
  1673. // Pa = P1 + ua( P2 - P1 )
  1674. // and line b going from P3 to P4:
  1675. // Pb = P3 + ub( P4 - P3 )
  1676. //
  1677. // Solving for Pa = Pb:
  1678. // x1 + ua( x2 - x1 ) = x3 + ub( x4 - x3 )
  1679. // y1 + ua( y2 - y1 ) = y3 + ub( y4 - y3 )
  1680. //
  1681. // Solving for ua and ub:
  1682. // ua = ( ( x4 - x3 )( y1 - y3 ) - ( y4 - y3 )( x1 - x3 ) ) / d
  1683. // ub = ( ( x2 - x1 )( y1 - y3 ) - ( y2 - y1 )( x1 - x3 ) ) / d
  1684. // denom = ( y4 - y3 )( x2 - x1 ) - ( x4 - x3 )( y2 - y1 )
  1685. //
  1686. // x = x1 + ua( x2 - x1 )
  1687. // y = y1 + ua( y2 - y1 )
  1688. //
  1689. const F32 d = ( ( pB1.y - pB0.y ) * ( pA1.x - pA0.x ) ) - ( ( pB1.x - pB0.x ) * ( pA1.y - pA0.y ) );
  1690. if ( d == 0.0f )
  1691. {
  1692. // Lines are parallel
  1693. return false;
  1694. }
  1695. // Find the point of intersection
  1696. const F32 uA = ( ( ( pB1.x - pB0.x ) * ( pA0.y - pB0.y ) ) - ( ( pB1.y - pB0.y ) * ( pA0.x - pB0.x ) ) ) / d;
  1697. const F32 uB = ( ( ( pA1.x - pA0.x ) * ( pA0.y - pB0.y ) ) - ( ( pA1.y - pA0.y ) * ( pA0.x - pB0.x ) ) ) / d;
  1698. if ( !pSnap
  1699. && ( ( uA < 0.0f ) || ( uA > 1.0f )
  1700. || ( uB < 0.0f ) || ( uB > 1.0f ) ) )
  1701. {
  1702. return false;
  1703. }
  1704. if ( pX )
  1705. {
  1706. if ( uA < 0.0f )
  1707. {
  1708. *pX = pA0;
  1709. }
  1710. else if ( uA > 1.f )
  1711. {
  1712. *pX = pA1;
  1713. }
  1714. else
  1715. {
  1716. // The path intersects the segment
  1717. *pX = pA0 + uA * ( pA1 - pA0 );
  1718. }
  1719. }
  1720. return true;
  1721. }
  1722. bool Utility::FindNearestPointOnLine( const Point3F &pSrcPosition, const Point3F &pA0, const Point3F &pA1, Point3F *pDstPosition )
  1723. {
  1724. const Point3F up( 0.0f, 0.0f, 1.0f );
  1725. Point3F dir = ( pA1 - pA0 );
  1726. dir.normalize();
  1727. Point3F normal = mCross( dir, up );
  1728. normal.normalize();
  1729. // Find the nearest intersection point between the point and the line
  1730. const Point3F b0 = pSrcPosition + ( normal * 100000.0f );
  1731. const Point3F b1 = pSrcPosition - ( normal * 100000.0f );
  1732. return IntersectLineSegment( pA0, pA1, b0, b1, true, pDstPosition );
  1733. }
  1734. F32 Utility::GetPitch( const VectorF &pVec )
  1735. {
  1736. F32 pitch;
  1737. if ( mFabs( pVec.x ) > mFabs( pVec.y ) )
  1738. {
  1739. pitch = mAtan2( mFabs( pVec.z ), mFabs( pVec.x ) );
  1740. }
  1741. else
  1742. {
  1743. pitch = mAtan2( mFabs( pVec.z ), mFabs( pVec.y ) );
  1744. }
  1745. if ( pVec.z < 0.f )
  1746. {
  1747. pitch = -pitch;
  1748. }
  1749. return pitch;
  1750. }
  1751. F32 Utility::GetYaw( const VectorF &pVec )
  1752. {
  1753. F32 yaw = mAtan2( pVec.x, pVec.y );
  1754. if ( yaw < 0.f )
  1755. {
  1756. yaw += M_2PI_F;
  1757. }
  1758. return yaw;
  1759. }
  1760. #endif