Mover.cpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/Mover.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 2/15/01 10:15a $*
  29. * *
  30. * $Revision:: 15 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "stdafx.h"
  36. #include "mover.h"
  37. #include "utils.h"
  38. #include "cameramgr.h"
  39. #include "leveleditdoc.h"
  40. #include "leveleditview.h"
  41. #include "node.h"
  42. #include "phys3.h"
  43. ///////////////////////////////////////////////////////////////////////////
  44. //
  45. // Clip_Point
  46. //
  47. ///////////////////////////////////////////////////////////////////////////
  48. static inline bool
  49. Clip_Point (Vector3 *point, const AABoxClass &box)
  50. {
  51. Vector3 temp_point = *point;
  52. //
  53. // Clip the temporary point
  54. //
  55. temp_point.X = max (temp_point.X, box.Center.X - box.Extent.X);
  56. temp_point.Y = max (temp_point.Y, box.Center.Y - box.Extent.Y);
  57. temp_point.Z = max (temp_point.Z, box.Center.Z - box.Extent.Z);
  58. temp_point.X = min (temp_point.X, box.Center.X + box.Extent.X);
  59. temp_point.Y = min (temp_point.Y, box.Center.Y + box.Extent.Y);
  60. temp_point.Z = min (temp_point.Z, box.Center.Z + box.Extent.Z);
  61. //
  62. // Did the clip change the point?
  63. //
  64. bool retval = (point->X != temp_point.X);
  65. retval |= (point->Y != temp_point.Y);
  66. retval |= (point->Z != temp_point.Z);
  67. //
  68. // Pass the new point back to the caller
  69. //
  70. (*point) = temp_point;
  71. return retval;
  72. }
  73. ///////////////////////////////////////////////////////////////////////
  74. //
  75. // Get_Mouse_Ray
  76. //
  77. ///////////////////////////////////////////////////////////////////////
  78. void
  79. MoverClass::Get_Mouse_Ray
  80. (
  81. const POINT & mouse_pos,
  82. float length,
  83. Vector3 & start,
  84. Vector3 & end
  85. )
  86. {
  87. // The start of the ray is simply the camera's position
  88. start = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ().Get_Translation ();
  89. //
  90. // Ensure the 'point' is correct for this mode (fullscreen/windowed)
  91. //
  92. float xpos = mouse_pos.x;
  93. float ypos = mouse_pos.y;
  94. ::Constrain_Point_To_Aspect_Ratio (xpos, ypos);
  95. // The 'end' of the ray is the world coordinates of the supplied point
  96. ::Get_Camera_Mgr ()->Get_Camera ()->Device_To_World_Space (Vector2 (xpos, ypos), &end);
  97. //
  98. // Recalculate the length of the ray
  99. //
  100. end = start + ((end - start) * length);
  101. return ;
  102. }
  103. ///////////////////////////////////////////////////////////////////////
  104. //
  105. // Get_Mouse_Ray
  106. //
  107. ///////////////////////////////////////////////////////////////////////
  108. void
  109. MoverClass::Get_Mouse_Ray
  110. (
  111. float length,
  112. Vector3 &start,
  113. Vector3 &end
  114. )
  115. {
  116. //
  117. // Ensure the 'point' is correct for this mode (fullscreen/windowed)
  118. //
  119. CPoint point;
  120. ::GetCursorPos (&point);
  121. ::Get_Main_View ()->ScreenToClient (&point);
  122. Get_Mouse_Ray (point, length, start, end);
  123. return ;
  124. }
  125. ///////////////////////////////////////////////////////////////////////
  126. //
  127. // Get_LOS_Ray
  128. //
  129. ///////////////////////////////////////////////////////////////////////
  130. void
  131. MoverClass::Get_LOS_Ray
  132. (
  133. const POINT & mouse_pos,
  134. float length,
  135. Vector3 & start,
  136. Vector3 & end
  137. )
  138. {
  139. // Get the transformation matrix for the camera
  140. Matrix3D camera_tm = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ();
  141. //
  142. // The start and end's of the ray are the camera's position
  143. // and 'length' down the camera's -z axis.
  144. //
  145. start = camera_tm.Get_Translation ();
  146. end = camera_tm * Vector3 (0, 0, -length);
  147. return ;
  148. }
  149. ///////////////////////////////////////////////////////////////////////
  150. //
  151. // Get_LOS_Ray
  152. //
  153. ///////////////////////////////////////////////////////////////////////
  154. void
  155. MoverClass::Get_LOS_Ray
  156. (
  157. float length,
  158. Vector3 &start,
  159. Vector3 &end
  160. )
  161. {
  162. //
  163. // Ensure the 'point' is correct for this mode (fullscreen/windowed)
  164. //
  165. CPoint point;
  166. ::GetCursorPos (&point);
  167. ::Get_Main_View ()->ScreenToClient (&point);
  168. Get_LOS_Ray (point, length, start, end);
  169. return ;
  170. }
  171. ///////////////////////////////////////////////////////////////////////
  172. //
  173. // Position_Node
  174. //
  175. ///////////////////////////////////////////////////////////////////////
  176. void
  177. MoverClass::Position_Node (NodeClass *node)
  178. {
  179. float distance = 1000.0F;
  180. //
  181. // Determine what ray to cast the node along
  182. //
  183. Vector3 ray_start;
  184. Vector3 ray_end;
  185. Get_LOS_Ray (distance, ray_start, ray_end);
  186. Position_Node_Along_Ray (node, ray_start, ray_end);
  187. return ;
  188. }
  189. ///////////////////////////////////////////////////////////////////////
  190. //
  191. // Position_Node_Along_Ray
  192. //
  193. ///////////////////////////////////////////////////////////////////////
  194. void
  195. MoverClass::Position_Node_Along_Ray (NodeClass *node)
  196. {
  197. //
  198. // Determine what ray to cast the node along
  199. //
  200. Vector3 ray_start;
  201. Vector3 ray_end;
  202. Get_Mouse_Ray (350.00F, ray_start, ray_end);
  203. Position_Node_Along_Ray (node, ray_start, ray_end);
  204. return ;
  205. }
  206. ///////////////////////////////////////////////////////////////////////
  207. //
  208. // Position_Nodes_Along_Ray
  209. //
  210. ///////////////////////////////////////////////////////////////////////
  211. void
  212. MoverClass::Position_Nodes_Along_Ray (void)
  213. {
  214. //
  215. // Determine what ray to cast the node along
  216. //
  217. Vector3 ray_start;
  218. Vector3 ray_end;
  219. Get_Mouse_Ray (350.00F, ray_start, ray_end);
  220. Position_Nodes_Along_Ray (ray_start, ray_end);
  221. return ;
  222. }
  223. ///////////////////////////////////////////////////////////////////////
  224. //
  225. // Position_Nodes_Along_Ray
  226. //
  227. ///////////////////////////////////////////////////////////////////////
  228. void
  229. MoverClass::Position_Nodes_Along_Ray (const Vector3 &start, const Vector3 &end)
  230. {
  231. NODE_LIST list;
  232. Vector3 center = ::Get_Scene_Editor ()->Build_Node_List (list);
  233. if (list.Count () == 1) {
  234. Position_Node_Along_Ray (list[0], start, end);
  235. } else {
  236. Position_Nodes_Along_Ray (list, center, start, end);
  237. }
  238. return ;
  239. }
  240. ///////////////////////////////////////////////////////////////////////
  241. //
  242. // Position_Nodes_Along_Ray
  243. //
  244. ///////////////////////////////////////////////////////////////////////
  245. Vector3
  246. MoverClass::Position_Nodes_Along_Ray
  247. (
  248. NODE_LIST & list,
  249. const Vector3 &tracking_pt,
  250. const Vector3 &start,
  251. const Vector3 &end
  252. )
  253. {
  254. if (list.Count () == 1) {
  255. return Position_Node_Along_Ray (list[0], start, end);
  256. }
  257. Vector3 position (tracking_pt);
  258. //
  259. // Turn off collision detection
  260. //
  261. for (int index = 0; index < list.Count (); index ++) {
  262. PhysClass *phys_obj = list[index]->Peek_Physics_Obj ();
  263. if (phys_obj != NULL) {
  264. phys_obj->Inc_Ignore_Counter();
  265. }
  266. }
  267. //
  268. // Cast the ray into the world so we can stop the objects at whatever it hits
  269. //
  270. CastResultStruct res;
  271. if (Cast_Ray (res, start, end, GAME_COLLISION_GROUP) != NULL) {
  272. position = start + (end - start) * res.Fraction;
  273. }
  274. // Calculate a delta to move each object
  275. Vector3 delta = position - tracking_pt;
  276. //
  277. // Re-position the nodes
  278. //
  279. for (index = 0; index < list.Count (); index ++) {
  280. NodeClass *node = list[index];
  281. PhysClass *phys_obj = node->Peek_Physics_Obj ();
  282. if (phys_obj != NULL) {
  283. //
  284. // Move the node and turn collision back on
  285. //
  286. node->Translate (delta);
  287. phys_obj->Dec_Ignore_Counter();
  288. }
  289. }
  290. ::Set_Modified ();
  291. return position;
  292. }
  293. ///////////////////////////////////////////////////////////////////////
  294. //
  295. // Position_Node_Along_Ray
  296. //
  297. ///////////////////////////////////////////////////////////////////////
  298. Vector3
  299. MoverClass::Position_Node_Along_Ray
  300. (
  301. NodeClass * node,
  302. const Vector3 &start,
  303. const Vector3 &end
  304. )
  305. {
  306. Vector3 position (0, 0, 0);
  307. PhysClass *phys_obj = node->Peek_Physics_Obj ();
  308. if (phys_obj != NULL) {
  309. position = node->Get_Transform ().Get_Translation ();
  310. // Don't include this node in the collision test
  311. phys_obj->Inc_Ignore_Counter();
  312. //
  313. // Cast the ray into the world so we can stop the object at whatever it hits
  314. //
  315. CastResultStruct res;
  316. if (Cast_Ray (res, start, end, GAME_COLLISION_GROUP) != NULL) {
  317. //
  318. // Determine the new position based on whether or not the
  319. // ray-cast hit anything.
  320. //
  321. position = start + (end - start) * res.Fraction;
  322. //
  323. // Get the collision box for this render obj
  324. //
  325. AABoxClass box;
  326. RenderObjClass *model = phys_obj->Peek_Model ();
  327. RenderObjClass *world_box = model->Get_Sub_Object_By_Name ("WORLDBOX");
  328. if (world_box != NULL) {
  329. world_box->Get_Obj_Space_Bounding_Box (box);
  330. MEMBER_RELEASE (world_box);
  331. } else {
  332. model->Get_Obj_Space_Bounding_Box (box);
  333. }
  334. box.Extent.Z = WWMATH_EPSILON;
  335. //
  336. // Move the object so its not embedded in the surface
  337. //
  338. Vector3 temp_pt = box.Center - res.Normal;
  339. ::Clip_Point (&temp_pt, box);
  340. float len = (temp_pt - box.Center).Length () + WWMATH_EPSILON;
  341. position += (res.Normal * len);
  342. //
  343. // Move the node
  344. //
  345. node->Translate (position - node->Get_Transform ().Get_Translation ());
  346. }
  347. phys_obj->Dec_Ignore_Counter();
  348. ::Set_Modified ();
  349. }
  350. return position;
  351. }
  352. ///////////////////////////////////////////////////////////////////////
  353. //
  354. // Calc_Ray_Intersection_XY
  355. //
  356. ///////////////////////////////////////////////////////////////////////
  357. bool
  358. MoverClass::Calc_Ray_Intersection_XY
  359. (
  360. float plane,
  361. const Vector3 &ray_start,
  362. const Vector3 &ray_end,
  363. Vector3 & result
  364. )
  365. {
  366. // Assume no intersection
  367. bool intersected = false;
  368. if ((ray_end.Z - ray_start.Z) != 0.00F) {
  369. // Calculate the fraction of the distance along the ray where the
  370. // Z value of the ray is the same as the Z value of the plane.
  371. // This simulates an intersection of the ray with the x-y plane at depth 'z'.
  372. double fraction = double(plane - ray_start.Z) / double(ray_end.Z - ray_start.Z);
  373. // If the fraction is between 0 and 1, then the ray intersects the plane
  374. if ((fraction >= 0) && (fraction <= 1.0F)) {
  375. // Now calcuate the intersection point based on this fraction.
  376. // To do this we use the parameterized form of a line equation:
  377. // P = P1 + (P2 - P1) * t
  378. // (Where t is a percentage between 0 and 1)
  379. result = ray_start + ((ray_end - ray_start) * fraction);
  380. // Success!
  381. intersected = true;
  382. }
  383. }
  384. // Return the true/false result code
  385. return intersected;
  386. }
  387. ///////////////////////////////////////////////////////////////////////
  388. //
  389. // Calc_Ray_Intersection_XZ
  390. //
  391. ///////////////////////////////////////////////////////////////////////
  392. bool
  393. MoverClass::Calc_Ray_Intersection_XZ
  394. (
  395. float plane,
  396. const Vector3 &ray_start,
  397. const Vector3 &ray_end,
  398. Vector3 & result
  399. )
  400. {
  401. // Assume no intersection
  402. bool intersected = false;
  403. if ((ray_end.Y - ray_start.Y) != 0.00F) {
  404. // Calculate the fraction of the distance along the ray where the
  405. // Y value of the ray is the same as the Y value of the plane.
  406. // This simulates an intersection of the ray with the x-z plane at depth 'y'.
  407. double fraction = double(plane - ray_start.Y) / double(ray_end.Y - ray_start.Y);
  408. // If the fraction is between 0 and 1, then the ray intersects the plane
  409. if ((fraction >= 0) && (fraction <= 1.0F)) {
  410. // Now calcuate the intersection point based on this fraction.
  411. // To do this we use the parameterized form of a line equation:
  412. // P = P1 + (P2 - P1) * t
  413. // (Where t is a percentage between 0 and 1)
  414. result = ray_start + ((ray_end - ray_start) * fraction);
  415. // Success!
  416. intersected = true;
  417. }
  418. }
  419. // Return the true/false result code
  420. return intersected;
  421. }
  422. ///////////////////////////////////////////////////////////////////////
  423. //
  424. // Calc_Ray_Intersection_YZ
  425. //
  426. ///////////////////////////////////////////////////////////////////////
  427. bool
  428. MoverClass::Calc_Ray_Intersection_YZ
  429. (
  430. float plane,
  431. const Vector3 &ray_start,
  432. const Vector3 &ray_end,
  433. Vector3 & result
  434. )
  435. {
  436. // Assume no intersection
  437. bool intersected = false;
  438. if ((ray_end.X - ray_start.X) != 0.00F) {
  439. // Calculate the fraction of the distance along the ray where the
  440. // X value of the ray is the same as the X value of the plane.
  441. // This simulates an intersection of the ray with the y-z plane at depth 'x'.
  442. double fraction = double(plane - ray_start.X) / double(ray_end.X - ray_start.X);
  443. // If the fraction is between 0 and 1, then the ray intersects the plane
  444. if ((fraction >= 0) && (fraction <= 1.0F)) {
  445. // Now calcuate the intersection point based on this fraction.
  446. // To do this we use the parameterized form of a line equation:
  447. // P = P1 + (P2 - P1) * t
  448. // (Where t is a percentage between 0 and 1)
  449. result = ray_start + ((ray_end - ray_start) * fraction);
  450. // Success!
  451. intersected = true;
  452. }
  453. }
  454. // Return the true/false result code
  455. return intersected;
  456. }
  457. ///////////////////////////////////////////////////////////////////////
  458. //
  459. // Transform_Node
  460. //
  461. ///////////////////////////////////////////////////////////////////////
  462. void
  463. MoverClass::Transform_Node
  464. (
  465. NodeClass * node,
  466. const Matrix3D & transform
  467. )
  468. {
  469. //
  470. // Move this node by the translation delta
  471. //
  472. Matrix3D curr_transform = node->Get_Transform ();
  473. Move_Node (node, transform.Get_Translation () - curr_transform.Get_Translation ());
  474. //
  475. // Determine a rotation matrix that is relative to the node's current transform
  476. //
  477. Matrix3D relative_transform;
  478. curr_transform.Get_Orthogonal_Inverse (relative_transform);
  479. Matrix3D rotation_matrix = relative_transform * transform;
  480. rotation_matrix.Set_Translation (Vector3 (0, 0, 0));
  481. //
  482. // Rotate the node by this matrix, centered about the new position.
  483. //
  484. Matrix3D coord_system (transform.Get_Translation ());
  485. Rotate_Node (node, rotation_matrix, coord_system);
  486. return ;
  487. }
  488. ///////////////////////////////////////////////////////////////////////
  489. //
  490. // Transform_Nodes
  491. //
  492. ///////////////////////////////////////////////////////////////////////
  493. void
  494. MoverClass::Transform_Nodes
  495. (
  496. NodeClass * node,
  497. const Matrix3D & transform
  498. )
  499. {
  500. NODE_LIST list;
  501. ::Get_Scene_Editor ()->Build_Node_List (list);
  502. Transform_Nodes (list, node, transform);
  503. return ;
  504. }
  505. ///////////////////////////////////////////////////////////////////////
  506. //
  507. // Transform_Nodes
  508. //
  509. ///////////////////////////////////////////////////////////////////////
  510. void
  511. MoverClass::Transform_Nodes
  512. (
  513. NODE_LIST & list,
  514. NodeClass * node,
  515. const Matrix3D & transform
  516. )
  517. {
  518. Matrix3D curr_transform = node->Get_Transform ();
  519. //
  520. // Move this list of nodes by the translation delta
  521. //
  522. Move_Nodes (list, transform.Get_Translation () - curr_transform.Get_Translation ());
  523. //
  524. // Determine a rotation matrix that is relative to the node's current transform
  525. //
  526. Matrix3D relative_transform;
  527. curr_transform.Get_Orthogonal_Inverse (relative_transform);
  528. Matrix3D rotation_matrix = relative_transform * transform;
  529. rotation_matrix.Set_Translation (Vector3 (0, 0, 0));
  530. //
  531. // Rotate the list of nodes by this matrix, centered about the new position.
  532. //
  533. Rotate_Nodes (list, rotation_matrix, transform.Get_Translation ());
  534. return ;
  535. }
  536. ///////////////////////////////////////////////////////////////////////
  537. //
  538. // Move_Node
  539. //
  540. ///////////////////////////////////////////////////////////////////////
  541. void
  542. MoverClass::Move_Node (NodeClass *node, const Vector3 &translation)
  543. {
  544. node->Translate (translation);
  545. ::Set_Modified ();
  546. return ;
  547. }
  548. ///////////////////////////////////////////////////////////////////////
  549. //
  550. // Move_Nodes
  551. //
  552. ///////////////////////////////////////////////////////////////////////
  553. void
  554. MoverClass::Simple_Move_Nodes (NODE_LIST &list, const Vector3 &translation)
  555. {
  556. for (int index = 0; index < list.Count (); index ++) {
  557. NodeClass *node = list[index];
  558. node->Translate (translation);
  559. }
  560. return ;
  561. }
  562. ///////////////////////////////////////////////////////////////////////
  563. //
  564. // Move_Nodes
  565. //
  566. ///////////////////////////////////////////////////////////////////////
  567. void
  568. MoverClass::Move_Nodes (const Vector3 &translation)
  569. {
  570. NODE_LIST list;
  571. ::Get_Scene_Editor ()->Build_Node_List (list);
  572. Simple_Move_Nodes (list, translation);
  573. return ;
  574. }
  575. ///////////////////////////////////////////////////////////////////////
  576. //
  577. // Move_Nodes
  578. //
  579. ///////////////////////////////////////////////////////////////////////
  580. Vector3
  581. MoverClass::Move_Nodes (NODE_LIST &list, const Vector3 &tracking_point)
  582. {
  583. //
  584. // Calculate the new position for the group
  585. //
  586. Matrix3D coord_system (1);
  587. Vector3 new_pos = Calc_New_Position (coord_system, tracking_point);
  588. //
  589. // Loop through all the nodes and move them by the calculated delta
  590. //
  591. for (int index = 0; index < list.Count (); index ++) {
  592. NodeClass *node = list[index];
  593. //
  594. // Move the node
  595. //
  596. if (node != NULL) {
  597. node->Translate (new_pos - tracking_point);
  598. }
  599. }
  600. Set_Modified ();
  601. return new_pos;
  602. }
  603. ///////////////////////////////////////////////////////////////////////
  604. //
  605. // Calc_New_Position
  606. //
  607. ///////////////////////////////////////////////////////////////////////
  608. Vector3
  609. MoverClass::Calc_New_Position
  610. (
  611. const Matrix3D & coord_system,
  612. const Vector3 & start_in_world_coords,
  613. LPPOINT mouse_pos
  614. )
  615. {
  616. Vector3 return_point = start_in_world_coords;
  617. Vector3 start_point = start_in_world_coords;
  618. //
  619. // The start of the ray is simply the camera's position
  620. //
  621. Vector3 ray_start = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ().Get_Translation ();
  622. //
  623. // Ensure the 'mouse-point' is correct for this mode (fullscreen/windowed)
  624. //
  625. CPoint point;
  626. if (mouse_pos == NULL) {
  627. ::GetCursorPos (&point);
  628. ::Get_Main_View()->ScreenToClient (&point);
  629. } else {
  630. point = (*mouse_pos);
  631. }
  632. float xpos = point.x;
  633. float ypos = point.y;
  634. ::Constrain_Point_To_Aspect_Ratio (xpos, ypos);
  635. //
  636. // The 'end' of the ray is the world coordinates of the mouse point
  637. //
  638. Vector3 ray_end;
  639. ::Get_Camera_Mgr ()->Get_Camera ()->Device_To_World_Space (Vector2 (xpos, ypos), &ray_end);
  640. //
  641. // However, now we must transform all our coords into the coordinate system we were passed.
  642. //
  643. Matrix3D coord_system_inv;
  644. coord_system.Get_Orthogonal_Inverse (coord_system_inv);
  645. ray_start = coord_system_inv * ray_start;
  646. ray_end = coord_system_inv * ray_end;
  647. start_point = coord_system_inv * start_point;
  648. return_point = coord_system_inv * return_point;
  649. //
  650. // Move the ray's endpoint along the line 1000 meters
  651. //
  652. ray_end = ray_start + ((ray_end - ray_start) * 1000.00F);
  653. //
  654. // Should we restrict movement to the z-axis?
  655. //
  656. if ((::GetKeyState (VK_SHIFT) < 0) ||
  657. (::Get_Current_Document ()->Get_Axis_Restriction () == CLevelEditDoc::RESTRICT_Z)) {
  658. // Determine which plane (y-z or x-z) to base the movement on
  659. float deltax = ::fabs (ray_end.X - ray_start.X);
  660. float deltay = ::fabs (ray_end.Y - ray_start.Y);
  661. // Determine where the ray intersects this plane
  662. if (deltax > deltay) {
  663. // Determine where the ray intersects the YZ plane
  664. Vector3 result;
  665. if (Calc_Ray_Intersection_YZ (start_point.X, ray_start, ray_end, result)) {
  666. return_point.Z = result.Z;
  667. }
  668. } else {
  669. // Determine where the ray intersects the XZ plane
  670. Vector3 result;
  671. if (Calc_Ray_Intersection_XZ (start_point.Y, ray_start, ray_end, result)) {
  672. return_point.Z = result.Z;
  673. }
  674. }
  675. } else {
  676. // Determine where the ray intersects the XY plane
  677. Vector3 result;
  678. if (Calc_Ray_Intersection_XY (start_point.Z, ray_start, ray_end, result)) {
  679. //
  680. // Now apply the axis restrictions
  681. //
  682. if (::Get_Current_Document ()->Get_Axis_Restriction () == CLevelEditDoc::RESTRICT_X) {
  683. return_point.X = result.X;
  684. } else if (::Get_Current_Document ()->Get_Axis_Restriction () == CLevelEditDoc::RESTRICT_Y) {
  685. return_point.Y = result.Y;
  686. } else {
  687. return_point = result;
  688. }
  689. }
  690. }
  691. //
  692. // Now convert the return value to world coords
  693. //
  694. return_point = coord_system * return_point;
  695. // Return the new point
  696. return return_point;
  697. }
  698. ///////////////////////////////////////////////////////////////////////
  699. //
  700. // Rotate_Nodes
  701. //
  702. ///////////////////////////////////////////////////////////////////////
  703. void
  704. MoverClass::Rotate_Nodes
  705. (
  706. float deltax,
  707. float deltay,
  708. const Quaternion & rotation
  709. )
  710. {
  711. NODE_LIST list;
  712. Vector3 center = ::Get_Scene_Editor ()->Build_Node_List (list);
  713. Rotate_Nodes (list, center, deltax, deltay, rotation);
  714. return ;
  715. }
  716. ///////////////////////////////////////////////////////////////////////
  717. //
  718. // Rotate_Nodes
  719. //
  720. ///////////////////////////////////////////////////////////////////////
  721. void
  722. MoverClass::Rotate_Nodes
  723. (
  724. NODE_LIST & list,
  725. const Vector3 & center,
  726. float deltax,
  727. float deltay,
  728. const Quaternion & rotation
  729. )
  730. {
  731. Matrix3D rotation_matrix (1);
  732. //
  733. // Are we restricting movement to a specific axis?
  734. //
  735. switch (::Get_Current_Document ()->Get_Axis_Restriction ()) {
  736. case CLevelEditDoc::RESTRICT_X:
  737. rotation_matrix.Rotate_X (deltax * 3.0F);
  738. break;
  739. case CLevelEditDoc::RESTRICT_Y:
  740. rotation_matrix.Rotate_Y (deltay * 3.0F);
  741. break;
  742. case CLevelEditDoc::RESTRICT_Z:
  743. rotation_matrix.Rotate_Z (deltay * 3.0F);
  744. break;
  745. case CLevelEditDoc::RESTRICT_NONE:
  746. rotation_matrix.Set_Rotation (rotation);
  747. break;
  748. }
  749. Rotate_Nodes (list, rotation_matrix, center);
  750. return ;
  751. }
  752. ///////////////////////////////////////////////////////////////////////
  753. //
  754. // Rotate_Nodes
  755. //
  756. ///////////////////////////////////////////////////////////////////////
  757. void
  758. MoverClass::Rotate_Nodes
  759. (
  760. NODE_LIST & list,
  761. const Matrix3D & rotation_matrix,
  762. const Vector3 & center
  763. )
  764. {
  765. //
  766. // Setup the rotation
  767. //
  768. Matrix3D coord_system (1);
  769. coord_system.Set_Translation (center);
  770. //
  771. // Determine if we should restrict rotation or not
  772. //
  773. bool restrict_rotation = false;
  774. for (int index = 0; index < list.Count (); index ++) {
  775. restrict_rotation |= list[index]->Is_Rotation_Restricted ();
  776. }
  777. //
  778. // Loop through all the nodes and rotate them
  779. //
  780. for (index = 0; index < list.Count (); index ++) {
  781. NodeClass *node = list[index];
  782. //
  783. // Rotate the node
  784. //
  785. if (restrict_rotation == false) {
  786. Rotate_Node_Freely (node, rotation_matrix, coord_system);
  787. } else {
  788. Rotate_Node_Z90 (node, rotation_matrix, coord_system);
  789. }
  790. }
  791. Set_Modified ();
  792. return ;
  793. }
  794. ///////////////////////////////////////////////////////////////////////
  795. //
  796. // Rotate_Nodes_Z
  797. //
  798. ///////////////////////////////////////////////////////////////////////
  799. void
  800. MoverClass::Rotate_Nodes_Z (float multiplier)
  801. {
  802. NODE_LIST list;
  803. Vector3 center = ::Get_Scene_Editor ()->Build_Node_List (list);
  804. Rotate_Nodes_Z (list, center, multiplier);
  805. return ;
  806. }
  807. ///////////////////////////////////////////////////////////////////////
  808. //
  809. // Rotate_Nodes_Z
  810. //
  811. ///////////////////////////////////////////////////////////////////////
  812. void
  813. MoverClass::Rotate_Nodes_Z
  814. (
  815. NODE_LIST & list,
  816. const Vector3 & center,
  817. float multiplier
  818. )
  819. {
  820. Matrix3D coord_system (1);
  821. coord_system.Set_Translation (center);
  822. //
  823. // Determine if we should restrict rotation or not
  824. //
  825. bool restrict_rotation = false;
  826. for (int index = 0; index < list.Count (); index ++) {
  827. restrict_rotation |= list[index]->Is_Rotation_Restricted ();
  828. }
  829. //
  830. // Loop through all the nodes and rotate them
  831. //
  832. for (index = 0; index < list.Count (); index ++) {
  833. NodeClass *node = list[index];
  834. //
  835. // Determine which rotation matrix to use (Z90 lock, or normal)
  836. //
  837. Matrix3D rotation_matrix (1);
  838. if (restrict_rotation == false) {
  839. rotation_matrix.Rotate_Z (DEG_TO_RAD (5.0F) * multiplier);
  840. } else if (multiplier > 0.0F) {
  841. rotation_matrix.Rotate_Z ((float)DEG_TO_RAD (-90));
  842. } else {
  843. rotation_matrix.Rotate_Z ((float)DEG_TO_RAD (90));
  844. }
  845. // Rotate the node
  846. node->Rotate (rotation_matrix, coord_system);
  847. }
  848. Set_Modified ();
  849. return ;
  850. }
  851. ///////////////////////////////////////////////////////////////////////
  852. //
  853. // Rotate_Node_Z90
  854. //
  855. ///////////////////////////////////////////////////////////////////////
  856. void
  857. MoverClass::Rotate_Node_Z90
  858. (
  859. NodeClass * node,
  860. const Matrix3D & rotation_matrix,
  861. const Matrix3D & coord_system
  862. )
  863. {
  864. if (node->Is_Locked () == false) {
  865. //
  866. // Get the transformation matrix
  867. //
  868. Matrix3D transform = node->Get_Transform ();
  869. Vector3 translation = transform.Get_Translation ();
  870. bool allow_translation = bool(coord_system.Get_Translation () != translation);
  871. Quaternion orientation = node->Get_Orientation ();
  872. transform.Set_Rotation (orientation);
  873. //
  874. // Rotate the transformation matrix in the provided coordinate system
  875. //
  876. ::Rotate_Matrix (transform, rotation_matrix, coord_system, &transform);
  877. //
  878. // Remember the orientation of the new matrix
  879. //
  880. orientation = ::Build_Quaternion (transform);
  881. node->Set_Orientation (orientation);
  882. double new_z_rot = transform.Get_Z_Rotation ();
  883. if (new_z_rot < 0) {
  884. new_z_rot += DEG_TO_RAD (360);
  885. }
  886. if (allow_translation) {
  887. translation = transform.Get_Translation ();
  888. }
  889. // Restrict translation if necessary
  890. transform.Make_Identity ();
  891. // Based on the z oomponent of the rotation, determine which
  892. // direction the object should be facing
  893. if ((new_z_rot > DEG_TO_RAD (45)) && (new_z_rot <= DEG_TO_RAD (135))) {
  894. transform = Matrix3D::RotateZ90;
  895. } else if ((new_z_rot > DEG_TO_RAD (135)) && (new_z_rot <= DEG_TO_RAD (225))) {
  896. transform = Matrix3D::RotateZ180;
  897. } else if ((new_z_rot > DEG_TO_RAD (225)) && (new_z_rot <= DEG_TO_RAD (315))) {
  898. transform = Matrix3D::RotateZ270;
  899. }
  900. //
  901. // Translate the matrix as necessary
  902. //
  903. transform.Set_Translation (translation);
  904. //
  905. // Pass the new transformation matrix onto the object
  906. //
  907. node->Set_Transform (transform);
  908. node->On_Rotate ();
  909. }
  910. return ;
  911. }
  912. ///////////////////////////////////////////////////////////////////////
  913. //
  914. // Rotate_Node_Freely
  915. //
  916. ///////////////////////////////////////////////////////////////////////
  917. void
  918. MoverClass::Rotate_Node_Freely
  919. (
  920. NodeClass * node,
  921. const Matrix3D & rotation_matrix,
  922. const Matrix3D & coord_system
  923. )
  924. {
  925. if (node->Is_Locked () == false) {
  926. Matrix3D tm = node->Get_Transform ();
  927. //
  928. // Translate this node in the specified coordinate system
  929. //
  930. Matrix3D coord_inv;
  931. Matrix3D coord_to_obj;
  932. coord_system.Get_Orthogonal_Inverse (coord_inv);
  933. Matrix3D::Multiply (coord_inv, tm, &coord_to_obj);
  934. Matrix3D::Multiply (coord_system, rotation_matrix, &tm);
  935. Matrix3D::Multiply (tm, coord_to_obj, &tm);
  936. if (!tm.Is_Orthogonal ()) {
  937. tm.Re_Orthogonalize ();
  938. TRACE ("Matrix wasn't orthogonal.\n");
  939. }
  940. //
  941. // Rotate the object and do post processing
  942. //
  943. node->Set_Transform (tm);
  944. node->On_Rotate ();
  945. }
  946. return ;
  947. }
  948. ///////////////////////////////////////////////////////////////////////
  949. //
  950. // Rotate_Node
  951. //
  952. ///////////////////////////////////////////////////////////////////////
  953. void
  954. MoverClass::Rotate_Node
  955. (
  956. NodeClass * node,
  957. const Matrix3D & rotation_matrix,
  958. const Matrix3D & coord_system
  959. )
  960. {
  961. //
  962. // Determine whether the node can be rotated free-form or
  963. // is restricted to 90 deg rotations about the Z axis.
  964. //
  965. if (node->Is_Rotation_Restricted () == false) {
  966. Rotate_Node_Freely (node, rotation_matrix, coord_system);
  967. } else {
  968. Rotate_Node_Z90 (node, rotation_matrix, coord_system);
  969. }
  970. return ;
  971. }
  972. ///////////////////////////////////////////////////////////////////////
  973. //
  974. // Translate_Node
  975. //
  976. ///////////////////////////////////////////////////////////////////////
  977. void
  978. MoverClass::Translate_Node (NodeClass *node, const Vector3 &vector)
  979. {
  980. if (node->Is_Locked () == false) {
  981. //
  982. // Move the physics object by the requested amount
  983. //
  984. Matrix3D tm = node->Get_Transform ();
  985. tm.Set_Translation (tm.Get_Translation () + vector);
  986. node->Set_Transform (tm);
  987. //phys_obj->Set_Position (tm.Get_Translation () + vector);
  988. /*Phys3Class *phys3_obj = phys_obj->As_Phys3Class ();
  989. if (phys3_obj != NULL) {
  990. phys3_obj->Set_Velocity (vector);
  991. }*/
  992. // Notify the node
  993. node->On_Translate ();
  994. }
  995. return ;
  996. }