Box3D.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  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/Box3D.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 3/28/01 3:11p $*
  29. * *
  30. * $Revision:: 9 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. //
  36. //
  37. // Following is a diagram specifying which entries in the m_Verticies array
  38. // correspond to which verticies in the box (in object space).
  39. // I don't know how well this diagram is going to hold up to different editors/font sizes, etc
  40. // so I apologize in advance if its unreadable... ;>
  41. //
  42. //
  43. // 2 --------------- 3
  44. // /| /|
  45. // / | / |
  46. // / | / |
  47. // 6 --------------- 7 |
  48. // | | | |
  49. // | | | |
  50. // | 1|_________|___| 0
  51. // | / | /
  52. // | / | /
  53. // |/ |/
  54. // 5 --------------- 4
  55. //
  56. //
  57. //
  58. //
  59. #include "stdafx.h"
  60. #include "box3d.h"
  61. #include "coltest.h"
  62. #include "tri.h"
  63. #include "leveleditdoc.h"
  64. #include "cameramgr.h"
  65. #include "camera.h"
  66. /////////////////////////////////////////////////////////////////////////////////////////
  67. // Local constants and typedefs
  68. /////////////////////////////////////////////////////////////////////////////////////////
  69. typedef enum
  70. {
  71. FACE_FRONT = 0,
  72. FACE_BACK,
  73. FACE_TOP,
  74. FACE_BOTTOM,
  75. FACE_RIGHT,
  76. FACE_LEFT,
  77. FACE_COUNT
  78. } FACE_INDEX;
  79. const int FACE_VERTICIES[6][4] = {
  80. { 5, 4, 6, 7 }, { 0, 1, 3, 2 },
  81. { 3, 2, 7, 6 }, { 4, 5, 0, 1 },
  82. { 1, 5, 2, 6 }, { 4, 0, 7, 3 }
  83. };
  84. const float MIN_SIZE = 0.01F;
  85. /////////////////////////////////////////////////////////////////////////////////////////
  86. // Local prototypes
  87. /////////////////////////////////////////////////////////////////////////////////////////
  88. static bool Find_Intersection_Point (const AABoxClass &box, const Vector3 &p0, const Vector3 &p1, float *percent, Vector3 *intersection_point);
  89. /////////////////////////////////////////////////////////////////////////////////////////
  90. //
  91. // Create_Model
  92. //
  93. /////////////////////////////////////////////////////////////////////////////////////////
  94. void
  95. Box3DClass::Create_Model (void)
  96. {
  97. //
  98. // Assign a default vertex material for the model
  99. //
  100. VertexMaterialClass *vmat = new VertexMaterialClass ();
  101. vmat->Set_Lighting (false);
  102. vmat->Set_Ambient(0,0,0);
  103. vmat->Set_Diffuse(0,0,0);
  104. vmat->Set_Specular(0,0,0);
  105. vmat->Set_Emissive(1,1,1);
  106. vmat->Set_Opacity(0.5F);
  107. vmat->Set_Shininess(0.0f);
  108. //vmat->Set_Opacity (0.5F);
  109. Set_Vertex_Material (vmat);
  110. MEMBER_RELEASE (vmat);
  111. //
  112. // Use an alpha shader so the box will be transparent
  113. //
  114. Set_Shader (ShaderClass::_PresetAlphaSolidShader);
  115. Enable_Sort ();
  116. float half_width = m_Dimensions.Y / 2.0F;
  117. float half_height = m_Dimensions.Z / 2.0F;
  118. float half_depth = m_Dimensions.X / 2.0F;
  119. // Determine the object space coords of our 8 verticies
  120. m_Verticies[0].X = -half_depth;
  121. m_Verticies[0].Y = half_width;
  122. m_Verticies[0].Z = -half_height;
  123. m_Verticies[1].X = -half_depth;
  124. m_Verticies[1].Y = -half_width;
  125. m_Verticies[1].Z = -half_height;
  126. m_Verticies[2].X = -half_depth;
  127. m_Verticies[2].Y = -half_width;
  128. m_Verticies[2].Z = half_height;
  129. m_Verticies[3].X = -half_depth;
  130. m_Verticies[3].Y = half_width;
  131. m_Verticies[3].Z = half_height;
  132. m_Verticies[4].X = half_depth;
  133. m_Verticies[4].Y = half_width;
  134. m_Verticies[4].Z = -half_height;
  135. m_Verticies[5].X = half_depth;
  136. m_Verticies[5].Y = -half_width;
  137. m_Verticies[5].Z = -half_height;
  138. m_Verticies[6].X = half_depth;
  139. m_Verticies[6].Y = -half_width;
  140. m_Verticies[6].Z = half_height;
  141. m_Verticies[7].X = half_depth;
  142. m_Verticies[7].Y = half_width;
  143. m_Verticies[7].Z = half_height;
  144. //Set_Vertex_Color (Vector3 (0.0F, 0.0F, ((float)(iface)) * 0.15F));
  145. Set_Vertex_Color (Vector4 (0.0F, 0.5F, 0.0F, 0.5f));
  146. //Set_Vertex_Alpha (0.5F);
  147. // Loop through all the faces and create them from triangle strips.
  148. for (int iface = 0; iface < FACE_COUNT; iface ++) {
  149. Begin_Tri_Strip ();
  150. Easy_Vertex (m_Verticies[FACE_VERTICIES[iface][0]]);
  151. Easy_Vertex (m_Verticies[FACE_VERTICIES[iface][1]]);
  152. Easy_Vertex (m_Verticies[FACE_VERTICIES[iface][2]]);
  153. Easy_Vertex (m_Verticies[FACE_VERTICIES[iface][3]]);
  154. End_Tri_Strip ();
  155. }
  156. Set_Collision_Type (COLLISION_TYPE_0);
  157. return ;
  158. }
  159. /////////////////////////////////////////////////////////////////////////////////////////
  160. //
  161. // Set_Dimensions
  162. //
  163. /////////////////////////////////////////////////////////////////////////////////////////
  164. void
  165. Box3DClass::Set_Dimensions (const Vector3 &dimensions)
  166. {
  167. Set_Width (dimensions.Y);
  168. Set_Height (dimensions.Z);
  169. Set_Depth (dimensions.X);
  170. Update_Verticies ();
  171. return ;
  172. }
  173. /////////////////////////////////////////////////////////////////////////////////////////
  174. //
  175. // Set_Width
  176. //
  177. /////////////////////////////////////////////////////////////////////////////////////////
  178. void
  179. Box3DClass::Set_Width (float width)
  180. {
  181. width = ::fabs (width);
  182. // Determine if the widht actually changed or not
  183. float curr_width = m_Dimensions.Y;
  184. if (curr_width != width) {
  185. // Recalc the obj-space positions of our 8 verticies
  186. float half_width = width / 2.0F;
  187. m_Verticies[0].Y = half_width;
  188. m_Verticies[1].Y = -half_width;
  189. m_Verticies[2].Y = -half_width;
  190. m_Verticies[3].Y = half_width;
  191. m_Verticies[4].Y = half_width;
  192. m_Verticies[5].Y = -half_width;
  193. m_Verticies[6].Y = -half_width;
  194. m_Verticies[7].Y = half_width;
  195. // Keep a flag around that will tell us we need
  196. // to update the verticies in the model when we're ready
  197. m_bDirty = true;
  198. m_Dimensions.Y = width;
  199. }
  200. return ;
  201. }
  202. /////////////////////////////////////////////////////////////////////////////////////////
  203. //
  204. // Set_Height
  205. //
  206. /////////////////////////////////////////////////////////////////////////////////////////
  207. void
  208. Box3DClass::Set_Height (float height)
  209. {
  210. height = ::fabs (height);
  211. // Determine if the height actually changed or not
  212. float curr_height = m_Dimensions.Z;
  213. if (curr_height != height) {
  214. // Recalc the obj-space positions of our 8 verticies
  215. float half_height = height / 2.0F;
  216. m_Verticies[0].Z = -half_height;
  217. m_Verticies[1].Z = -half_height;
  218. m_Verticies[2].Z = half_height;
  219. m_Verticies[3].Z = half_height;
  220. m_Verticies[4].Z = -half_height;
  221. m_Verticies[5].Z = -half_height;
  222. m_Verticies[6].Z = half_height;
  223. m_Verticies[7].Z = half_height;
  224. // Keep a flag around that will tell us we need
  225. // to update the verticies in the model when we're ready
  226. m_bDirty = true;
  227. m_Dimensions.Z = height;
  228. }
  229. return ;
  230. }
  231. /////////////////////////////////////////////////////////////////////////////////////////
  232. //
  233. // Set_Depth
  234. //
  235. /////////////////////////////////////////////////////////////////////////////////////////
  236. void
  237. Box3DClass::Set_Depth (float depth)
  238. {
  239. depth = ::fabs (depth);
  240. // Determine if the depth actually changed or not
  241. float curr_depth = m_Dimensions.X;
  242. if (curr_depth != depth) {
  243. // Recalc the obj-space positions of our 8 verticies
  244. float half_depth = depth / 2.0F;
  245. m_Verticies[0].X = -half_depth;
  246. m_Verticies[1].X = -half_depth;
  247. m_Verticies[2].X = -half_depth;
  248. m_Verticies[3].X = -half_depth;
  249. m_Verticies[4].X = half_depth;
  250. m_Verticies[5].X = half_depth;
  251. m_Verticies[6].X = half_depth;
  252. m_Verticies[7].X = half_depth;
  253. // Keep a flag around that will tell us we need
  254. // to update the verticies in the model when we're ready
  255. m_bDirty = true;
  256. m_Dimensions.X = depth;
  257. }
  258. return ;
  259. }
  260. /////////////////////////////////////////////////////////////////////////////////////////
  261. //
  262. // Update_Verticies
  263. //
  264. /////////////////////////////////////////////////////////////////////////////////////////
  265. void
  266. Box3DClass::Update_Verticies (void)
  267. {
  268. if (m_bDirty) {
  269. // Loop through all 24 verticies in the model and
  270. // update their obj-space positions
  271. int ivertex = 0;
  272. for (int iface = 0; iface < FACE_COUNT; iface ++) {
  273. Easy_Move_Vertex (ivertex++, m_Verticies[FACE_VERTICIES[iface][0]]);
  274. Easy_Move_Vertex (ivertex++, m_Verticies[FACE_VERTICIES[iface][1]]);
  275. Easy_Move_Vertex (ivertex++, m_Verticies[FACE_VERTICIES[iface][2]]);
  276. Easy_Move_Vertex (ivertex++, m_Verticies[FACE_VERTICIES[iface][3]]);
  277. }
  278. // We're no longer dirty
  279. m_bDirty = false;
  280. Set_Dirty_Bounds ();
  281. Set_Dirty ();
  282. Invalidate_Cached_Bounding_Volumes ();
  283. Update_Cached_Bounding_Volumes ();
  284. }
  285. return ;
  286. }
  287. /////////////////////////////////////////////////////////////////////////////////////////
  288. //
  289. // Get_Vertex_Lock_Position
  290. //
  291. /////////////////////////////////////////////////////////////////////////////////////////
  292. Vector3
  293. Box3DClass::Get_Vertex_Lock_Position (int vertex)
  294. {
  295. Vector3 position (0, 0, 0);
  296. // Params OK?
  297. if ((vertex >= 0) && (vertex < 8)) {
  298. switch (vertex) {
  299. case 0:
  300. position = m_Verticies[6];
  301. break;
  302. case 1:
  303. position = m_Verticies[7];
  304. break;
  305. case 2:
  306. position = m_Verticies[4];
  307. break;
  308. case 3:
  309. position = m_Verticies[5];
  310. break;
  311. case 4:
  312. position = m_Verticies[2];
  313. break;
  314. case 5:
  315. position = m_Verticies[3];
  316. break;
  317. case 6:
  318. position = m_Verticies[0];
  319. break;
  320. case 7:
  321. position = m_Verticies[1];
  322. break;
  323. }
  324. // Convert the vertex position from obj space to world space
  325. //position += Get_Transform ().Get_Translation ();
  326. position = Get_Transform () * position;
  327. }
  328. // Return the vertex position
  329. return position;
  330. }
  331. /////////////////////////////////////////////////////////////////////////////////////////
  332. //
  333. // Position_Vertex
  334. //
  335. /////////////////////////////////////////////////////////////////////////////////////////
  336. void
  337. Box3DClass::Position_Vertex
  338. (
  339. int vertex,
  340. const Vector3 &new_position
  341. )
  342. {
  343. // Params OK?
  344. if ((vertex >= 0) && (vertex < 8)) {
  345. // Make a box from the vertex that we are 'locking' and
  346. // the new position
  347. Make_Box (Get_Vertex_Lock_Position (vertex), new_position);
  348. }
  349. return ;
  350. }
  351. /////////////////////////////////////////////////////////////////////////////////////////
  352. //
  353. // Translate_Vertex
  354. //
  355. /////////////////////////////////////////////////////////////////////////////////////////
  356. void
  357. Box3DClass::Translate_Vertex
  358. (
  359. int vertex,
  360. const Vector3 &translation
  361. )
  362. {
  363. // Params OK?
  364. if ((vertex >= 0) && (vertex < 8)) {
  365. float new_width = m_Dimensions.Y;
  366. float new_height = m_Dimensions.Z;
  367. float new_depth = m_Dimensions.X;
  368. // Modifiy the dimensions of the box
  369. new_width += translation.Y * 2.0F;
  370. new_height += translation.Z * 2.0F;
  371. new_depth += translation.X * 2.0F;
  372. // Modify the dimensions of the box if they are all valid
  373. if ((new_width >= MIN_SIZE) &&
  374. (new_height >= MIN_SIZE) &&
  375. (new_depth >= MIN_SIZE)) {
  376. Set_Dimensions (Vector3 (new_depth, new_width, new_height));
  377. }
  378. }
  379. return ;
  380. }
  381. /////////////////////////////////////////////////////////////////////////////////////////
  382. //
  383. // Make_Box
  384. //
  385. /////////////////////////////////////////////////////////////////////////////////////////
  386. void
  387. Box3DClass::Make_Box
  388. (
  389. const Vector3 &point1,
  390. const Vector3 &point2
  391. )
  392. {
  393. // Calculate the new center point for the box
  394. Vector3 delta = point2 - point1;
  395. Vector3 center = point1 + (delta / 2.0F);
  396. // Recalc the box's position to be centered around the 2 points
  397. Matrix3D transform = Get_Transform ();
  398. transform.Set_Translation (center);
  399. Set_Transform (transform);
  400. // Convert the 2 points to object space
  401. Matrix3D transform_inv;
  402. transform.Get_Orthogonal_Inverse (transform_inv);
  403. Vector3 obj_point1 = transform_inv * point1;
  404. Vector3 obj_point2 = transform_inv * point2;
  405. //Vector3 obj_point1 = point1 - center;
  406. //Vector3 obj_point2 = point2 - center;
  407. // Use these 2 points to determine the bottom left
  408. // and upper right points of the box
  409. Vector3 bottom_left;
  410. Vector3 upper_right;
  411. bottom_left.X = max (obj_point1.X, obj_point2.X);
  412. bottom_left.Y = min (obj_point1.Y, obj_point2.Y);
  413. bottom_left.Z = min (obj_point1.Z, obj_point2.Z);
  414. upper_right.X = min (obj_point1.X, obj_point2.X);
  415. upper_right.Y = max (obj_point1.Y, obj_point2.Y);
  416. upper_right.Z = max (obj_point1.Z, obj_point2.Z);
  417. // Given the bottom left and upper right coords, determine
  418. // what each of the 8 verticies are...
  419. m_Verticies[0].X = upper_right.X;
  420. m_Verticies[0].Y = upper_right.Y;
  421. m_Verticies[0].Z = bottom_left.Z;
  422. m_Verticies[1].X = upper_right.X;
  423. m_Verticies[1].Y = bottom_left.Y;
  424. m_Verticies[1].Z = bottom_left.Z;
  425. m_Verticies[2].X = upper_right.X;
  426. m_Verticies[2].Y = bottom_left.Y;
  427. m_Verticies[2].Z = upper_right.Z;
  428. m_Verticies[3].X = upper_right.X;
  429. m_Verticies[3].Y = upper_right.Y;
  430. m_Verticies[3].Z = upper_right.Z;
  431. m_Verticies[4].X = bottom_left.X;
  432. m_Verticies[4].Y = upper_right.Y;
  433. m_Verticies[4].Z = bottom_left.Z;
  434. m_Verticies[5].X = bottom_left.X;
  435. m_Verticies[5].Y = bottom_left.Y;
  436. m_Verticies[5].Z = bottom_left.Z;
  437. m_Verticies[6].X = bottom_left.X;
  438. m_Verticies[6].Y = bottom_left.Y;
  439. m_Verticies[6].Z = upper_right.Z;
  440. m_Verticies[7].X = bottom_left.X;
  441. m_Verticies[7].Y = upper_right.Y;
  442. m_Verticies[7].Z = upper_right.Z;
  443. // Recalc the box's dimensions and update its mesh
  444. m_Dimensions = upper_right - bottom_left;
  445. m_Dimensions.X = fabs (m_Dimensions.X);
  446. m_Dimensions.Y = fabs (m_Dimensions.Y);
  447. m_Dimensions.Z = fabs (m_Dimensions.Z);
  448. m_bDirty = true;
  449. Update_Verticies ();
  450. return ;
  451. }
  452. /////////////////////////////////////////////////////////////////////////////////////////
  453. //
  454. // Cast_Ray
  455. //
  456. /////////////////////////////////////////////////////////////////////////////////////////
  457. bool
  458. Box3DClass::Cast_Ray (RayCollisionTestClass & raytest)
  459. {
  460. if ((Get_Collision_Type() & raytest.CollisionType) == 0) return false;
  461. Matrix3D world_to_obj;
  462. Get_Transform().Get_Orthogonal_Inverse(world_to_obj);
  463. RayCollisionTestClass objray(raytest,world_to_obj);
  464. AABoxClass box;
  465. box.Center.Set (0, 0, 0);
  466. box.Extent = m_Dimensions * 0.5F;
  467. bool hit = CollisionMath::Collide (objray.Ray, box, raytest.Result);
  468. /*OBBoxClass obbox;
  469. obbox.Center = Get_Transform ().Get_Translation ();
  470. obbox.Extent = m_Dimensions * 0.5F;
  471. obbox.Basis = Matrix3 (Get_Transform ());
  472. CastResultStruct test_result = *raytest.Result;
  473. bool obb_hit = CollisionMath::Collide (raytest.Ray, obbox, &test_result);
  474. WWASSERT (hit == obb_hit);*/
  475. //
  476. // Transform result back into original coordinate system
  477. //
  478. if (hit) {
  479. raytest.CollidedRenderObj = this;
  480. if (raytest.Result->ComputeContactPoint) {
  481. Matrix3D::Transform_Vector (Get_Transform (), raytest.Result->ContactPoint, &(raytest.Result->ContactPoint));
  482. }
  483. }
  484. return hit;
  485. }
  486. /////////////////////////////////////////////////////////////////////////////////////////
  487. //
  488. // Get_Obj_Space_Bounding_Box
  489. //
  490. /////////////////////////////////////////////////////////////////////////////////////////
  491. void
  492. Box3DClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  493. {
  494. box.Center = Vector3 (0,0,0);
  495. box.Extent = m_Dimensions * 0.5F;
  496. return ;
  497. }
  498. /////////////////////////////////////////////////////////////////////////////////////////
  499. //
  500. // Set_Color
  501. //
  502. /////////////////////////////////////////////////////////////////////////////////////////
  503. void
  504. Box3DClass::Set_Color (const Vector3 &color)
  505. {
  506. for (int vertex = 0; vertex < VertCount; vertex ++) {
  507. Change_Vertex_Color (vertex, Vector4 (color.X, color.Y, color.Z, 0.5F), 0);
  508. }
  509. return ;
  510. }
  511. /////////////////////////////////////////////////////////////////////////////////////////
  512. //
  513. // Render
  514. //
  515. /////////////////////////////////////////////////////////////////////////////////////////
  516. void
  517. Box3DClass::Render (RenderInfoClass &rinfo)
  518. {
  519. // Only render if we if flagged visible
  520. if (Is_Not_Hidden_At_All ()) {
  521. DynamicMeshClass::Render (rinfo);
  522. }
  523. return ;
  524. }
  525. /////////////////////////////////////////////////////////////////////////////////////////
  526. //
  527. // Get_Vertex_Position
  528. //
  529. /////////////////////////////////////////////////////////////////////////////////////////
  530. Vector3
  531. Box3DClass::Get_Vertex_Position (int vertex)
  532. {
  533. // The vertex position is simply the box's world position + the vertex offset
  534. //Vector3 position = Get_Transform ().Get_Translation ();
  535. //position += m_Verticies[vertex];
  536. Vector3 position = Get_Transform () * m_Verticies[vertex];
  537. // Return the vertex position
  538. return position;
  539. }
  540. /////////////////////////////////////////////////////////////////////////////////////////
  541. //
  542. // Drag_VertexXY
  543. //
  544. /////////////////////////////////////////////////////////////////////////////////////////
  545. void
  546. Box3DClass::Drag_VertexXY (int vertex_index, POINT point, const Vector3 &locked_vertex)
  547. {
  548. //
  549. // The start of the ray is simply the camera's position
  550. //
  551. Vector3 ray_start = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ().Get_Translation ();
  552. //
  553. // Ensure the 'point' is correct for this mode (fullscreen/windowed)
  554. //
  555. float xpos = point.x;
  556. float ypos = point.y;
  557. ::Constrain_Point_To_Aspect_Ratio (xpos, ypos);
  558. //
  559. // The 'end' of the ray is the world coordinates of the supplied point
  560. //
  561. Vector3 ray_end;
  562. ::Get_Camera_Mgr ()->Get_Camera ()->Device_To_World_Space (Vector2 (xpos, ypos), &ray_end);
  563. ray_end = ray_start + ((ray_end-ray_start) * 1000.00F);
  564. //
  565. // If the ray isn't parallel to the z-axis, then move the corner vertex
  566. //
  567. if (fabs(ray_end.Z - ray_start.Z) > 1.0F) {
  568. Vector3 vertex_pos = Get_Vertex_Position (vertex_index);
  569. // Calculate the fraction of the distance along the ray where the
  570. // Z value of the ray is the same as the Z value of the vertex we are moving.
  571. // This simulates an intersection of the ray with the x-y plane at height 'z'.
  572. double fraction = double(vertex_pos.Z - ray_start.Z) / double(ray_end.Z - ray_start.Z);
  573. // Now calcuate the 2nd point based on this fraction.
  574. // To do this we use the parameterized form of a line equation:
  575. // P = P1 + (P2 - P1) * t
  576. // (Where t is a percentage between 0 and 1)
  577. Vector3 new_point = ray_start + ((ray_end - ray_start) * fraction);
  578. Make_Box (locked_vertex, new_point);
  579. }
  580. return ;
  581. }
  582. /////////////////////////////////////////////////////////////////////////////////////////
  583. //
  584. // Drag_VertexZ
  585. //
  586. /////////////////////////////////////////////////////////////////////////////////////////
  587. void
  588. Box3DClass::Drag_VertexZ (int vertex_index, POINT point, const Vector3 &locked_vertex)
  589. {
  590. //
  591. // The start of the ray is simply the camera's position
  592. //
  593. Vector3 ray_start = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ().Get_Translation ();
  594. //
  595. // Ensure the 'point' is correct for this mode (fullscreen/windowed)
  596. //
  597. float xpos = point.x;
  598. float ypos = point.y;
  599. ::Constrain_Point_To_Aspect_Ratio (xpos, ypos);
  600. //
  601. // The 'end' of the ray is the world coordinates of the supplied point
  602. //
  603. Vector3 ray_end;
  604. ::Get_Camera_Mgr ()->Get_Camera ()->Device_To_World_Space (Vector2 (xpos, ypos), &ray_end);
  605. ray_end = ray_start + ((ray_end-ray_start) * 1000.00F);
  606. //
  607. // Determine which plane (y-z or x-z) to base the movement on
  608. //
  609. float deltax = ::fabs (ray_end.X - ray_start.X);
  610. float deltay = ::fabs (ray_end.Y - ray_start.Y);
  611. //
  612. // Determine where the ray intersects this plane
  613. //
  614. double fraction = 0;
  615. Vector3 vertex_pos = Get_Vertex_Position (vertex_index);
  616. if ((deltax > deltay) && (deltax != 0.0F)) {
  617. // Calculate the fraction of the distance along the ray where the
  618. // X value of the ray is the same as the X value of the vertex.
  619. // This simulates an intersection of the ray with the y-z plane at depth 'x'.
  620. fraction = double(vertex_pos.X - ray_start.X) / double(ray_end.X - ray_start.X);
  621. } else if ((deltay > deltax) && (deltay != 0.0F)) {
  622. // Calculate the fraction of the distance along the ray where the
  623. // X value of the ray is the same as the X value of the vertex.
  624. // This simulates an intersection of the ray with the x-z plane at depth 'y'.
  625. fraction = double(vertex_pos.Y - ray_start.Y) / double(ray_end.Y - ray_start.Y);
  626. }
  627. // If we calculated a valid fraction, then use it
  628. // to determine the new vertex position.
  629. if (min (deltax, deltay) != 0.0F) {
  630. // Now calcuate the 2nd point based on this fraction.
  631. // To do this we use the parameterized form of a line equation:
  632. // P = P1 + (P2 - P1) * t
  633. // (Where t is a percentage between 0 and 1)
  634. Vector3 new_point = vertex_pos;
  635. new_point.Z = ray_start.Z + ((ray_end.Z - ray_start.Z) * fraction);
  636. Make_Box (locked_vertex, new_point);
  637. }
  638. return ;
  639. }
  640. //////////////////////////////////////////////////////////////////////////////////
  641. //
  642. // Find_Intersection_Point
  643. //
  644. //////////////////////////////////////////////////////////////////////////////////
  645. bool
  646. Find_Intersection_Point
  647. (
  648. const AABoxClass & box,
  649. const Vector3 & p0,
  650. const Vector3 & p1,
  651. float * percent,
  652. Vector3 * intersection_point
  653. )
  654. {
  655. bool retval = false;
  656. //
  657. // Find the locations of each of the 6 "planes"
  658. // we will be testing against
  659. //
  660. float x1 = box.Center.X - box.Extent.X;
  661. float x2 = box.Center.X + box.Extent.X;
  662. float y1 = box.Center.Y - box.Extent.Y;
  663. float y2 = box.Center.Y + box.Extent.Y;
  664. float z1 = box.Center.Z - box.Extent.Z;
  665. float z2 = box.Center.Z + box.Extent.Z;
  666. float t_values[6] = { -1, -1, -1, -1, -1, -1 };
  667. Vector3 delta = p1 - p0;
  668. //
  669. // Find the "t" values where the line intersects the
  670. // 2 "Y-Z" planes
  671. //
  672. if (delta.X != 0) {
  673. t_values[0] = (x1 - p0.X) / delta.X;
  674. t_values[1] = (x2 - p0.X) / delta.X;
  675. }
  676. //
  677. // Find the "t" values where the line intersects the
  678. // 2 "X-Z" planes
  679. //
  680. if (delta.Y != 0) {
  681. t_values[2] = (y1 - p0.Y) / delta.Y;
  682. t_values[3] = (y2 - p0.Y) / delta.Y;
  683. }
  684. //
  685. // Find the "t" values where the line intersects the
  686. // 2 "X-Y" planes
  687. //
  688. if (delta.Z != 0) {
  689. t_values[4] = (z1 - p0.Z) / delta.Z;
  690. t_values[5] = (z2 - p0.Z) / delta.Z;
  691. }
  692. //
  693. // Loop over all the "t" values we've calculated
  694. //
  695. (*percent) = 2.0F;
  696. for (int index = 0; index < 6; index ++) {
  697. //
  698. // Is this "t" value the smallest in-range value we've
  699. // found yet?
  700. //
  701. if ( t_values[index] >= 0 &&
  702. t_values[index] <= 1.0F &&
  703. t_values[index] < (*percent))
  704. {
  705. //
  706. // Find the point which exists at this "t" value along the line segment
  707. //
  708. Vector3 point = p0 + delta * t_values[index];
  709. //
  710. // If this point isn't outside the box, then we'll consider it good enough
  711. //
  712. if ( (WWMath::Fabs (point.X - box.Center.X) <= (box.Extent.X + WWMATH_EPSILON)) &&
  713. (WWMath::Fabs (point.Y - box.Center.Y) <= (box.Extent.Y + WWMATH_EPSILON)) &&
  714. (WWMath::Fabs (point.Z - box.Center.Z) <= (box.Extent.Z + WWMATH_EPSILON)))
  715. {
  716. (*percent) = t_values[index];
  717. (*intersection_point) = point;
  718. retval = true;
  719. }
  720. }
  721. }
  722. return retval;
  723. }