VPathEditor.cpp 59 KB

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