VPathEditor.cpp 59 KB

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