ZoneEditDialog.cpp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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. // ZoneEditDialog.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "leveledit.h"
  22. #include "leveleditview.h"
  23. #include "zoneeditdialog.h"
  24. #include "ww3d.h"
  25. #include "scene.h"
  26. #include "camera.h"
  27. #include "utils.h"
  28. #include "mmsystem.h"
  29. #include "matrix3d.h"
  30. #include "rendobj.h"
  31. #include "sphere.h"
  32. #include "box3d.h"
  33. #include "cameramgr.h"
  34. #include "filemgr.h"
  35. #include "filelocations.h"
  36. #include "quat.h"
  37. #include "vector3.h"
  38. #include "obbox.h"
  39. #include "staticanimphys.h"
  40. #include "hanim.h"
  41. #ifdef _DEBUG
  42. #define new DEBUG_NEW
  43. #undef THIS_FILE
  44. static char THIS_FILE[] = __FILE__;
  45. #endif
  46. /////////////////////////////////////////////////////////////////////////////
  47. //
  48. // Local constants
  49. //
  50. /////////////////////////////////////////////////////////////////////////////
  51. const int TOOLBAR_HEIGHT = 36;
  52. const int TOOLBAR_V_SPACING = 5;
  53. const int TOOLBAR_V_BORDER = TOOLBAR_V_SPACING * 2;
  54. const int TOOLBAR_H_SPACING = 5;
  55. const int TOOLBAR_H_BORDER = TOOLBAR_H_SPACING * 2;
  56. /////////////////////////////////////////////////////////////////////////////
  57. //
  58. // Local prototypes
  59. //
  60. /////////////////////////////////////////////////////////////////////////////
  61. static void Trackball_Camera (HWND hwnd, CameraClass &camera, const Vector3 &center, POINT point, POINT last_point);
  62. /////////////////////////////////////////////////////////////////////////////
  63. //
  64. // ZoneEditDialogClass
  65. //
  66. /////////////////////////////////////////////////////////////////////////////
  67. ZoneEditDialogClass::ZoneEditDialogClass(CWnd* pParent /*=NULL*/)
  68. : m_LookAtDist (0),
  69. m_Camera (NULL),
  70. m_Scene (NULL),
  71. m_RenderObj (NULL),
  72. m_PhysObj (NULL),
  73. m_Zone (NULL),
  74. m_TimerID (0),
  75. m_IsEditingZone (true),
  76. m_IsSizingZone (false),
  77. m_SwapChain (NULL),
  78. m_Initialized (false),
  79. CDialog(ZoneEditDialogClass::IDD, pParent)
  80. {
  81. //{{AFX_DATA_INIT(ZoneEditDialogClass)
  82. // NOTE: the ClassWizard will add member initialization here
  83. //}}AFX_DATA_INIT
  84. return ;
  85. }
  86. /////////////////////////////////////////////////////////////////////////////
  87. //
  88. // DoDataExchange
  89. //
  90. /////////////////////////////////////////////////////////////////////////////
  91. void
  92. ZoneEditDialogClass::DoDataExchange (CDataExchange* pDX)
  93. {
  94. CDialog::DoDataExchange(pDX);
  95. //{{AFX_DATA_MAP(ZoneEditDialogClass)
  96. DDX_Control(pDX, IDC_EDIT_ZONE, m_MoveZoneCheck);
  97. DDX_Control(pDX, IDC_SIZE_ZONE, m_SizeZoneCheck);
  98. //}}AFX_DATA_MAP
  99. return ;
  100. }
  101. BEGIN_MESSAGE_MAP(ZoneEditDialogClass, CDialog)
  102. //{{AFX_MSG_MAP(ZoneEditDialogClass)
  103. ON_WM_DESTROY()
  104. ON_BN_CLICKED(IDC_TOP, OnTop)
  105. ON_BN_CLICKED(IDC_FRONT, OnFront)
  106. ON_BN_CLICKED(IDC_LEFT, OnLeft)
  107. ON_BN_CLICKED(IDC_RIGHT, OnRight)
  108. ON_BN_CLICKED(IDC_EDIT_ZONE, OnEditZone)
  109. ON_BN_CLICKED(IDC_SIZE_ZONE, OnSizeZone)
  110. ON_BN_CLICKED(IDC_LAST_FRAME, OnLastFrame)
  111. ON_BN_CLICKED(IDC_FIRST_FRAME, OnFirstFrame)
  112. //}}AFX_MSG_MAP
  113. END_MESSAGE_MAP()
  114. /////////////////////////////////////////////////////////////////////////////
  115. //
  116. // OnInitDialog
  117. //
  118. /////////////////////////////////////////////////////////////////////////////
  119. BOOL
  120. ZoneEditDialogClass::OnInitDialog (void)
  121. {
  122. CWaitCursor wait_cursor;
  123. CLevelEditView::Allow_Repaint (false);
  124. CDialog::OnInitDialog ();
  125. //
  126. // Subclass the 3D window for mouse-tracking
  127. //
  128. SetWindowLong (::GetDlgItem (m_hWnd, IDC_3D_WINDOW), GWL_WNDPROC, (LONG)fn3DWindow);
  129. ::SetProp (::GetDlgItem (m_hWnd, IDC_3D_WINDOW), "ZONE_DIALOG", (HANDLE)this);
  130. //
  131. // Get the dimensions of the client area of the window we'll be rendering in
  132. //
  133. CRect rect;
  134. ::GetClientRect (::GetDlgItem (m_hWnd, IDC_3D_WINDOW), &rect);
  135. int cx = rect.Width ();
  136. int cy = rect.Height ();
  137. //
  138. // Create a swap chain so we can render to this window as well
  139. //
  140. m_SwapChain = DX8Wrapper::Create_Additional_Swap_Chain (::GetDlgItem (m_hWnd, IDC_3D_WINDOW));
  141. //
  142. // Create the scene and camera we will use
  143. //
  144. m_Scene = new SimpleSceneClass;
  145. m_Camera = new CameraClass;
  146. m_Scene->Set_Ambient_Light (Vector3 (1, 1, 1));
  147. m_Camera->Set_Clip_Planes (0.1F, 400.0F);
  148. //
  149. // Configure the camera
  150. //
  151. double hfov = 0;
  152. double vfov = 0;
  153. if (cy > cx) {
  154. vfov = (float)DEG_TO_RAD(45.0f);
  155. hfov = (double)cx / (double)cy * vfov;
  156. } else {
  157. hfov = (float)DEG_TO_RAD(45.0f);
  158. vfov = (double)cy / (double)cx * hfov;
  159. }
  160. m_Camera->Set_View_Plane (hfov, vfov);
  161. //
  162. // Setup the scene
  163. //
  164. Load_Object ();
  165. Insert_Zone ();
  166. //
  167. // Select the default UI
  168. //
  169. SendDlgItemMessage (IDC_TOP, BM_SETCHECK, (WPARAM)TRUE);
  170. SendDlgItemMessage (IDC_EDIT_ZONE, BM_SETCHECK, (WPARAM)TRUE);
  171. OnTop ();
  172. OnEditZone ();
  173. Update_Status ();
  174. //
  175. // Enable/disable the animation controls
  176. //
  177. bool has_animation = false;
  178. if (m_PhysObj != NULL && m_PhysObj->As_StaticAnimPhysClass () != NULL) {
  179. has_animation = true;
  180. OnFirstFrame ();
  181. }
  182. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_FIRST_FRAME), has_animation);
  183. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_LAST_FRAME), has_animation);
  184. //
  185. // Kick off a timer that we can use to update
  186. // the display (kinda like a game loop iterator)
  187. //
  188. m_TimerID = ::timeSetEvent ( 50,
  189. 50,
  190. fnUpdateTimer,
  191. (DWORD)m_hWnd,
  192. TIME_PERIODIC);
  193. m_Initialized = true;
  194. return TRUE;
  195. }
  196. /////////////////////////////////////////////////////////////////////////////
  197. //
  198. // OnOK
  199. //
  200. /////////////////////////////////////////////////////////////////////////////
  201. void
  202. ZoneEditDialogClass::OnOK (void)
  203. {
  204. //
  205. // Create a matrix we can use to transform the zone into 'relative' space.
  206. //
  207. Matrix3D obj_tm = m_RenderObj->Get_Transform ();
  208. Matrix3D obj_inv;
  209. obj_tm.Get_Orthogonal_Inverse (obj_inv);
  210. //
  211. // Transform the zone from world space coords to relative coords
  212. //
  213. OBBoxClass zone_box (m_Zone->Get_Transform ().Get_Translation (), m_Zone->Get_Dimensions () * 0.5F);
  214. OBBoxClass::Transform (obj_inv, zone_box, &m_ZoneBox);
  215. CDialog::OnOK ();
  216. return ;
  217. }
  218. /////////////////////////////////////////////////////////////////////////////
  219. //
  220. // OnDestroy
  221. //
  222. /////////////////////////////////////////////////////////////////////////////
  223. void
  224. ZoneEditDialogClass::OnDestroy (void)
  225. {
  226. // Stop the timer
  227. if (m_TimerID != 0) {
  228. ::timeKillEvent (m_TimerID);
  229. m_TimerID = 0;
  230. }
  231. //
  232. // Free our swap chain
  233. //
  234. if (m_SwapChain != NULL) {
  235. m_SwapChain->Release ();
  236. m_SwapChain = NULL;
  237. }
  238. CLevelEditView::Allow_Repaint (true);
  239. //
  240. // Destroy the scene/camera/render-obj
  241. //
  242. m_Scene->Remove_Render_Object (m_RenderObj);
  243. m_Scene->Remove_Render_Object (m_Zone);
  244. MEMBER_RELEASE (m_Scene);
  245. MEMBER_RELEASE (m_Camera);
  246. MEMBER_RELEASE (m_RenderObj);
  247. MEMBER_RELEASE (m_Zone);
  248. MEMBER_RELEASE (m_PhysObj);
  249. CDialog::OnDestroy ();
  250. return ;
  251. }
  252. /////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Render_View
  255. //
  256. /////////////////////////////////////////////////////////////////////////////
  257. void
  258. ZoneEditDialogClass::Render_View (void)
  259. {
  260. static render_lock = false;
  261. if (!render_lock) {
  262. render_lock = true;
  263. //
  264. // Move the camera if the user is pressing
  265. // the camera-control keys.
  266. //
  267. Handle_Keypress ();
  268. //
  269. // Configure the render target
  270. //
  271. DX8Wrapper::Set_Render_Target (m_SwapChain);
  272. //
  273. // Render the scene
  274. //
  275. WW3D::Begin_Render (true, true, Vector3 (0.4F, 0.4F, 0.4F));
  276. WW3D::Render (m_Scene, m_Camera, FALSE, FALSE);
  277. WW3D::End_Render ();
  278. //
  279. // Blit the frame to the client area of the window
  280. //
  281. m_SwapChain->Present (NULL, NULL, NULL, NULL);
  282. //
  283. // Restore the render target
  284. //
  285. DX8Wrapper::Set_Render_Target ((LPDIRECT3DSURFACE8)NULL);
  286. //
  287. // Cleanup
  288. //
  289. RemoveProp (m_hWnd, "WaitingToProcess");
  290. render_lock = false;
  291. }
  292. return ;
  293. }
  294. ////////////////////////////////////////////////////////////////////////////
  295. //
  296. // fnUpdateTimer
  297. //
  298. /////////////////////////////////////////////////////////////////////////////
  299. void CALLBACK
  300. ZoneEditDialogClass::fnUpdateTimer
  301. (
  302. UINT uID,
  303. UINT uMsg,
  304. DWORD user_data,
  305. DWORD dw1,
  306. DWORD dw2
  307. )
  308. {
  309. HWND hwnd = (HWND)user_data;
  310. if (hwnd != NULL) {
  311. if ((GetProp (hwnd, "WaitingToProcess") == NULL)) {
  312. SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
  313. // Send the message to the view so it will be in the
  314. // same thread (We don't seem to be thread-safe)
  315. ::PostMessage (hwnd, WM_USER+101, 0, 0L);
  316. }
  317. }
  318. return ;
  319. }
  320. ////////////////////////////////////////////////////////////////////////////
  321. //
  322. // WindowProc
  323. //
  324. /////////////////////////////////////////////////////////////////////////////
  325. LRESULT
  326. ZoneEditDialogClass::WindowProc
  327. (
  328. UINT message,
  329. WPARAM wParam,
  330. LPARAM lParam
  331. )
  332. {
  333. if (message == (WM_USER + 101)) {
  334. Render_View ();
  335. } else if (message == WM_KEYDOWN || message == WM_KEYUP) {
  336. //
  337. // Eat the keyboard messages we 'special case'.
  338. //
  339. if (wParam == VK_NUMPAD8 || wParam == VK_NUMPAD2 ||
  340. wParam == VK_NUMPAD4 || wParam == VK_NUMPAD6 ||
  341. wParam == VK_NUMPAD7 || wParam == VK_NUMPAD1)
  342. {
  343. return 0;
  344. }
  345. }
  346. return CDialog::WindowProc (message, wParam, lParam);
  347. }
  348. ////////////////////////////////////////////////////////////////////////////
  349. //
  350. // OnTop
  351. //
  352. /////////////////////////////////////////////////////////////////////////////
  353. void
  354. ZoneEditDialogClass::OnTop (void)
  355. {
  356. Vector3 pos = m_RenderObj->Get_Position ();
  357. Matrix3D transform (1);
  358. transform.Look_At (pos + Vector3 (0, 0, m_LookAtDist), pos, 3.1415926535F);
  359. m_Camera->Set_Transform (transform);
  360. return ;
  361. }
  362. ////////////////////////////////////////////////////////////////////////////
  363. //
  364. // OnFront
  365. //
  366. /////////////////////////////////////////////////////////////////////////////
  367. void
  368. ZoneEditDialogClass::OnFront (void)
  369. {
  370. Vector3 pos = m_RenderObj->Get_Position ();
  371. Matrix3D transform (1);
  372. transform.Look_At (pos + Vector3 (m_LookAtDist, 0, 0), pos, 0);
  373. m_Camera->Set_Transform (transform);
  374. return ;
  375. }
  376. ////////////////////////////////////////////////////////////////////////////
  377. //
  378. // OnLeft
  379. //
  380. /////////////////////////////////////////////////////////////////////////////
  381. void
  382. ZoneEditDialogClass::OnLeft (void)
  383. {
  384. Vector3 pos = m_RenderObj->Get_Position ();
  385. Matrix3D transform (1);
  386. transform.Look_At (pos + Vector3 (0, -m_LookAtDist, 0), pos, 0);
  387. m_Camera->Set_Transform (transform);
  388. return ;
  389. }
  390. ////////////////////////////////////////////////////////////////////////////
  391. //
  392. // OnRight
  393. //
  394. /////////////////////////////////////////////////////////////////////////////
  395. void
  396. ZoneEditDialogClass::OnRight (void)
  397. {
  398. Vector3 pos = m_RenderObj->Get_Position ();
  399. Matrix3D transform (1);
  400. transform.Look_At (pos + Vector3 (0, m_LookAtDist, 0), pos, 0);
  401. m_Camera->Set_Transform (transform);
  402. return ;
  403. }
  404. ////////////////////////////////////////////////////////////////////////////
  405. //
  406. // Load_Object
  407. //
  408. /////////////////////////////////////////////////////////////////////////////
  409. void
  410. ZoneEditDialogClass::Load_Object (void)
  411. {
  412. //
  413. // Determine how big the object is
  414. //
  415. SphereClass sphere = m_RenderObj->Get_Bounding_Sphere ();
  416. m_LookAtDist = sphere.Radius * 1.5F;
  417. m_LookAtDist = max (m_LookAtDist, 4.0F);
  418. //
  419. // Add the render object to the world at 0, 0, 0
  420. //
  421. m_Scene->Add_Render_Object (m_RenderObj);
  422. m_RenderObj->Set_Transform (Matrix3D(Vector3(0, 0, 0)));
  423. //
  424. // Add a grid render object to the world to act as a floor
  425. //
  426. RenderObjClass *floor = ::Create_Render_Obj ("GRID");
  427. if (floor != NULL) {
  428. floor->Set_Transform (Matrix3D(1));
  429. m_Scene->Add_Render_Object (floor);
  430. floor->Release_Ref ();
  431. }
  432. return ;
  433. }
  434. ////////////////////////////////////////////////////////////////////////////
  435. //
  436. // Insert_Zone
  437. //
  438. /////////////////////////////////////////////////////////////////////////////
  439. void
  440. ZoneEditDialogClass::Insert_Zone (void)
  441. {
  442. //
  443. // Create the zone and add it to the scene
  444. //
  445. m_Zone = new Box3DClass (Vector3 (1, 1, 1));
  446. m_Zone->Set_Color (Vector3 (0, 0.7F, 0));
  447. //
  448. // Transform the zone from relative to world space coords
  449. //
  450. Matrix3D obj_tm = m_RenderObj->Get_Transform ();
  451. OBBoxClass zone_box;
  452. OBBoxClass::Transform (obj_tm, m_ZoneBox, &zone_box);
  453. m_Zone->Set_Position (zone_box.Center);
  454. if (zone_box.Extent.X > 0 || zone_box.Extent.Y > 0 || zone_box.Extent.Z > 0) {
  455. m_Zone->Set_Dimensions (zone_box.Extent * 2.0F);
  456. }
  457. m_Scene->Add_Render_Object (m_Zone);
  458. return ;
  459. }
  460. ////////////////////////////////////////////////////////////////////////////
  461. //
  462. // Set_Phys_Obj
  463. //
  464. /////////////////////////////////////////////////////////////////////////////
  465. void
  466. ZoneEditDialogClass::Set_Phys_Obj (PhysClass *phys_obj)
  467. {
  468. MEMBER_ADD (m_PhysObj, phys_obj);
  469. //
  470. // Extract the model from the physics object
  471. //
  472. MEMBER_RELEASE (m_RenderObj);
  473. if (m_PhysObj != NULL) {
  474. m_RenderObj = m_PhysObj->Peek_Model ();
  475. m_RenderObj->Add_Ref ();
  476. }
  477. return ;
  478. }
  479. ////////////////////////////////////////////////////////////////////////////
  480. //
  481. // Handle_Keypress
  482. //
  483. /////////////////////////////////////////////////////////////////////////////
  484. void
  485. ZoneEditDialogClass::Handle_Keypress (void)
  486. {
  487. //
  488. // Determine which speed modifier to use
  489. //
  490. float speed_mod = 1.0F;
  491. if (::GetAsyncKeyState (VK_CONTROL) < 0) {
  492. speed_mod = 3.0F;
  493. }
  494. //
  495. // Move the camera forward-backward (if necessary)
  496. //
  497. if ((::GetAsyncKeyState (VK_NUMPAD8) < 0) ||
  498. (::GetAsyncKeyState (VK_NUMPAD2) < 0)) {
  499. // Get the camera's current position
  500. Vector3 position = m_Camera->Get_Position ();
  501. float orig_z = position.Z;
  502. //
  503. // Determine how far to move the camera
  504. //
  505. float delta = (::GetAsyncKeyState (VK_NUMPAD8) < 0) ? -0.35F : 0.35F;
  506. delta *= speed_mod;
  507. //
  508. // Scale the position along the direction vector
  509. //
  510. Matrix3D transform = m_Camera->Get_Transform ();
  511. position += (delta * transform.Get_Z_Vector ());
  512. //
  513. // Should we lock the z-position?
  514. //
  515. if (::GetAsyncKeyState (VK_CAPITAL) < 0) {
  516. position.Z = orig_z;
  517. }
  518. // Set the camera's new position
  519. m_Camera->Set_Position (position);
  520. }
  521. //
  522. // Pan the camera left-right (if neccessary)
  523. //
  524. if ((::GetAsyncKeyState (VK_NUMPAD4) < 0) ||
  525. (::GetAsyncKeyState (VK_NUMPAD6) < 0)) {
  526. // Get the camera's current position
  527. Vector3 position = m_Camera->Get_Position ();
  528. //
  529. // Determine how far to move the camera
  530. //
  531. float delta = (::GetAsyncKeyState (VK_NUMPAD4) < 0) ? -0.35F : 0.35F;
  532. delta *= speed_mod;
  533. //
  534. // Scale the position along the x-vector
  535. //
  536. Matrix3D transform = m_Camera->Get_Transform ();
  537. position += (delta * transform.Get_X_Vector ());
  538. // Set the camera's new position
  539. m_Camera->Set_Position (position);
  540. }
  541. //
  542. // Elevate the camera up-down (if neccessary)
  543. //
  544. if ((::GetAsyncKeyState (VK_NUMPAD7) < 0) ||
  545. (::GetAsyncKeyState (VK_NUMPAD1) < 0)) {
  546. // Get the camera's current position
  547. Vector3 position = m_Camera->Get_Position ();
  548. //
  549. // Determine how far to move the camera
  550. //
  551. float delta = (::GetAsyncKeyState (VK_NUMPAD1) < 0) ? -0.35F : 0.35F;
  552. delta *= speed_mod;
  553. //
  554. // Scale the position along the x-vector
  555. //
  556. Matrix3D transform = m_Camera->Get_Transform ();
  557. position += (delta * transform.Get_Y_Vector ());
  558. // Set the camera's new position
  559. m_Camera->Set_Position (position);
  560. }
  561. if ((::GetAsyncKeyState (VK_UP) < 0) ||
  562. (::GetAsyncKeyState (VK_DOWN) < 0) ||
  563. (::GetAsyncKeyState (VK_LEFT) < 0) ||
  564. (::GetAsyncKeyState (VK_RIGHT) < 0))
  565. {
  566. float amount = 0.025F;
  567. if (::GetAsyncKeyState (VK_CONTROL) < 0) {
  568. amount *= 4.0F;
  569. }
  570. Vector3 translation(0,0,0);
  571. if (::GetAsyncKeyState (VK_UP) < 0) {
  572. if (::GetAsyncKeyState (VK_SHIFT) < 0) {
  573. translation.Z += amount;
  574. } else {
  575. translation.X += amount;
  576. }
  577. }
  578. if (::GetAsyncKeyState (VK_DOWN) < 0) {
  579. if (::GetAsyncKeyState (VK_SHIFT) < 0) {
  580. translation.Z -= amount;
  581. } else {
  582. translation.X -= amount;
  583. }
  584. }
  585. if (::GetAsyncKeyState (VK_RIGHT) < 0) {
  586. translation.Y += amount;
  587. }
  588. if (::GetAsyncKeyState (VK_LEFT) < 0) {
  589. translation.Y -= amount;
  590. }
  591. //
  592. // Move the zone
  593. //
  594. if (m_IsEditingZone) {
  595. Matrix3D tm = m_Zone->Get_Transform ();
  596. tm.Translate (translation);
  597. m_Zone->Set_Transform (tm);
  598. }
  599. //
  600. // Size the Zone
  601. //
  602. if (m_IsSizingZone) {
  603. Vector3 size = m_Zone->Get_Dimensions ();
  604. size += translation;
  605. m_Zone->Set_Dimensions (size);
  606. }
  607. Update_Status ();
  608. }
  609. return ;
  610. }
  611. ////////////////////////////////////////////////////////////////////////////
  612. //
  613. // Update_Status
  614. //
  615. /////////////////////////////////////////////////////////////////////////////
  616. void
  617. ZoneEditDialogClass::Update_Status (void)
  618. {
  619. //
  620. // Update the zone's status
  621. //
  622. Vector3 zone_pos = m_Zone->Get_Transform ().Get_Translation ();
  623. Vector3 zone_size = m_Zone->Get_Dimensions ();
  624. CString status;
  625. status.Format ("Zone Pos (%.2f, %.2f, %.2f)\nZone Size (%.2f, %.2f, %.2f)",
  626. zone_pos.X, zone_pos.Y, zone_pos.Z,
  627. zone_size.X, zone_size.Y, zone_size.Z);
  628. SetDlgItemText (IDC_ZONE_STATUS, status);
  629. return ;
  630. }
  631. ////////////////////////////////////////////////////////////////////////////
  632. //
  633. // OnEditZone
  634. //
  635. /////////////////////////////////////////////////////////////////////////////
  636. void
  637. ZoneEditDialogClass::OnEditZone (void)
  638. {
  639. m_IsEditingZone = (SendDlgItemMessage (IDC_EDIT_ZONE, BM_GETCHECK) == 1);
  640. return ;
  641. }
  642. ////////////////////////////////////////////////////////////////////////////
  643. //
  644. // fn3DWindow
  645. //
  646. /////////////////////////////////////////////////////////////////////////////
  647. LRESULT CALLBACK
  648. ZoneEditDialogClass::fn3DWindow
  649. (
  650. HWND hwnd,
  651. UINT message,
  652. WPARAM wparam,
  653. LPARAM lparam
  654. )
  655. {
  656. if (message == WM_LBUTTONDOWN) {
  657. ZoneEditDialogClass *dialog = NULL;
  658. dialog = (ZoneEditDialogClass *)::GetProp (hwnd, "ZONE_DIALOG");
  659. dialog->Handle_LBUTTON_DOWN (wparam, lparam);
  660. } else if (message == WM_LBUTTONUP) {
  661. ZoneEditDialogClass *dialog = NULL;
  662. dialog = (ZoneEditDialogClass *)::GetProp (hwnd, "ZONE_DIALOG");
  663. dialog->Handle_LBUTTON_UP (wparam, lparam);
  664. } else if (message == WM_MOUSEMOVE) {
  665. ZoneEditDialogClass *dialog = NULL;
  666. dialog = (ZoneEditDialogClass *)::GetProp (hwnd, "ZONE_DIALOG");
  667. dialog->Handle_MOUSEMOVE (wparam, lparam);
  668. }
  669. return ::DefWindowProc (hwnd, message, wparam, lparam);
  670. }
  671. ////////////////////////////////////////////////////////////////////////////
  672. //
  673. // Handle_LBUTTON_DOWN
  674. //
  675. /////////////////////////////////////////////////////////////////////////////
  676. void
  677. ZoneEditDialogClass::Handle_LBUTTON_DOWN (WPARAM wparam, LPARAM lparam)
  678. {
  679. if (m_Initialized == false) {
  680. return ;
  681. }
  682. ::SetCapture (::GetDlgItem (m_hWnd, IDC_3D_WINDOW));
  683. m_LastPoint.x = LOWORD (lparam);
  684. m_LastPoint.y = HIWORD (lparam);
  685. return ;
  686. }
  687. ////////////////////////////////////////////////////////////////////////////
  688. //
  689. // Handle_LBUTTON_UP
  690. //
  691. /////////////////////////////////////////////////////////////////////////////
  692. void
  693. ZoneEditDialogClass::Handle_LBUTTON_UP (WPARAM wparam, LPARAM lparam)
  694. {
  695. ::ReleaseCapture ();
  696. return ;
  697. }
  698. ////////////////////////////////////////////////////////////////////////////
  699. //
  700. // Handle_MOUSEMOVE
  701. //
  702. /////////////////////////////////////////////////////////////////////////////
  703. void
  704. ZoneEditDialogClass::Handle_MOUSEMOVE (WPARAM wparam, LPARAM lparam)
  705. {
  706. if (m_Initialized == false) {
  707. return ;
  708. }
  709. POINT point = { LOWORD (lparam), HIWORD (lparam) };
  710. WWASSERT (m_Camera != NULL);
  711. if ((wparam & MK_LBUTTON) && (wparam & MK_RBUTTON)) {
  712. float delta_x = float(m_LastPoint.x - point.x) / 32;
  713. float delta_y = float(point.y - m_LastPoint.y) / 32;
  714. //
  715. // Scale the position along the direction vector
  716. //
  717. Vector3 position = m_Camera->Get_Position ();
  718. Matrix3D transform = m_Camera->Get_Transform ();
  719. position += (delta_x * transform.Get_X_Vector ());
  720. position += (delta_y * transform.Get_Y_Vector ());
  721. // Set the camera's new position
  722. m_Camera->Set_Position (position);
  723. } else if (wparam & MK_LBUTTON) {
  724. //
  725. // Orbit the camera around the object
  726. //
  727. if (::GetCapture () == ::GetDlgItem (m_hWnd, IDC_3D_WINDOW)) {
  728. ::Trackball_Camera ( ::GetDlgItem (m_hWnd, IDC_3D_WINDOW),
  729. *m_Camera,
  730. Vector3 (0, 0, 0),
  731. point,
  732. m_LastPoint );
  733. }
  734. } else if (wparam & MK_RBUTTON) {
  735. float delta = float(m_LastPoint.y - point.y) / 12;
  736. //
  737. // Scale the position along the direction vector
  738. //
  739. Vector3 position = m_Camera->Get_Position ();
  740. Matrix3D transform = m_Camera->Get_Transform ();
  741. position += (delta * transform.Get_Z_Vector ());
  742. // Set the camera's new position
  743. m_Camera->Set_Position (position);
  744. }
  745. m_LastPoint = point;
  746. return ;
  747. }
  748. ////////////////////////////////////////////////////////////////////////////
  749. //
  750. // Trackball_Camera
  751. //
  752. /////////////////////////////////////////////////////////////////////////////
  753. void
  754. Trackball_Camera
  755. (
  756. HWND hwnd,
  757. CameraClass & camera,
  758. const Vector3 & center,
  759. POINT point,
  760. POINT last_point
  761. )
  762. {
  763. RECT rect;
  764. ::GetClientRect (hwnd, &rect);
  765. //
  766. // Convert the points to normalized units
  767. //
  768. float mid_point_x = float(rect.right >> 1);
  769. float mid_point_y = float(rect.bottom >> 1);
  770. float last_point_x = ((float)last_point.x - mid_point_x) / mid_point_x;
  771. float last_point_y = (mid_point_y - (float)last_point.y) / mid_point_y;
  772. float point_x = ((float)point.x - mid_point_x) / mid_point_x;
  773. float point_y = (mid_point_y - (float)point.y) / mid_point_y;
  774. //
  775. // Calculate the orbit
  776. //
  777. Quaternion rotation = ::Trackball (last_point_x, last_point_y, point_x, point_y, 0.8F);
  778. //
  779. // Get the transformation matrix for the camera and its inverse
  780. //
  781. Matrix3D transform = camera.Get_Transform ();
  782. Matrix3D inv_tm;
  783. transform.Get_Orthogonal_Inverse (inv_tm);
  784. //
  785. // Translate to the object's center, perform the rotation, then translate back out.
  786. //
  787. Vector3 to_object = inv_tm * center;
  788. transform.Translate (to_object);
  789. Matrix3D::Multiply (transform, Build_Matrix3D (rotation), &transform);
  790. transform.Translate (-to_object);
  791. // Pass the new trnasform onto the camera
  792. camera.Set_Transform (transform);
  793. return ;
  794. }
  795. ////////////////////////////////////////////////////////////////////////////
  796. //
  797. // PreTranslateMessage
  798. //
  799. /////////////////////////////////////////////////////////////////////////////
  800. BOOL
  801. ZoneEditDialogClass::PreTranslateMessage (MSG *pMsg)
  802. {
  803. if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) {
  804. if (pMsg->wParam == VK_NUMPAD8 || pMsg->wParam == VK_NUMPAD2 ||
  805. pMsg->wParam == VK_NUMPAD4 || pMsg->wParam == VK_NUMPAD6 ||
  806. pMsg->wParam == VK_NUMPAD7 || pMsg->wParam == VK_NUMPAD1 ||
  807. pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN ||
  808. pMsg->wParam == VK_LEFT || pMsg->wParam == VK_RIGHT)
  809. {
  810. return 1;
  811. }
  812. }
  813. return CDialog::PreTranslateMessage(pMsg);
  814. }
  815. ////////////////////////////////////////////////////////////////////////////
  816. //
  817. // OnSizeZone
  818. //
  819. /////////////////////////////////////////////////////////////////////////////
  820. void
  821. ZoneEditDialogClass::OnSizeZone (void)
  822. {
  823. m_IsSizingZone = (m_SizeZoneCheck.GetCheck () == 1);
  824. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_EDIT_ZONE), !m_IsSizingZone);
  825. if (m_IsSizingZone) {
  826. m_IsEditingZone = false;
  827. } else {
  828. OnEditZone ();
  829. }
  830. return ;
  831. }
  832. ////////////////////////////////////////////////////////////////////////////
  833. //
  834. // OnLastFrame
  835. //
  836. /////////////////////////////////////////////////////////////////////////////
  837. void
  838. ZoneEditDialogClass::OnLastFrame (void)
  839. {
  840. SendDlgItemMessage (IDC_FIRST_FRAME, BM_SETCHECK, (WPARAM)FALSE);
  841. SendDlgItemMessage (IDC_LAST_FRAME, BM_SETCHECK, (WPARAM)TRUE);
  842. if (m_PhysObj == NULL) {
  843. return ;
  844. }
  845. //
  846. // Make sure this object can be animated...
  847. //
  848. StaticAnimPhysClass *anim_obj = m_PhysObj->As_StaticAnimPhysClass ();
  849. if (anim_obj != NULL) {
  850. AnimCollisionManagerClass &anim_mgr = anim_obj->Get_Animation_Manager ();
  851. //
  852. // Pop the animation to its last frame
  853. //
  854. HAnimClass *animation = anim_mgr.Peek_Animation ();
  855. if (animation != NULL) {
  856. m_RenderObj->Set_Animation (animation, animation->Get_Num_Frames () - 1);
  857. }
  858. }
  859. return ;
  860. }
  861. ////////////////////////////////////////////////////////////////////////////
  862. //
  863. // OnFirstFrame
  864. //
  865. /////////////////////////////////////////////////////////////////////////////
  866. void
  867. ZoneEditDialogClass::OnFirstFrame (void)
  868. {
  869. SendDlgItemMessage (IDC_FIRST_FRAME, BM_SETCHECK, (WPARAM)TRUE);
  870. SendDlgItemMessage (IDC_LAST_FRAME, BM_SETCHECK, (WPARAM)FALSE);
  871. if (m_PhysObj == NULL) {
  872. return ;
  873. }
  874. //
  875. // Make sure this object can be animated...
  876. //
  877. StaticAnimPhysClass *anim_obj = m_PhysObj->As_StaticAnimPhysClass ();
  878. if (anim_obj != NULL) {
  879. AnimCollisionManagerClass &anim_mgr = anim_obj->Get_Animation_Manager ();
  880. //
  881. // Pop the animation to its first frame
  882. //
  883. HAnimClass *animation = anim_mgr.Peek_Animation ();
  884. if (animation != NULL) {
  885. m_RenderObj->Set_Animation (animation, 0);
  886. }
  887. }
  888. return ;
  889. }