GraphicView.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  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. // GraphicView.cpp : implementation of the CGraphicView class
  19. //
  20. #include "stdafx.h"
  21. #include "PhysTest.h"
  22. #include "PhysTestDoc.h"
  23. #include "GraphicView.h"
  24. #include "MainFrm.h"
  25. #include "mmsystem.h"
  26. #include "pscene.h"
  27. #include "ww3d.h"
  28. #include "camera.h"
  29. #include "quat.h"
  30. #include "rcfile.h"
  31. #include "assetmgr.h"
  32. #include "rbody.h"
  33. #include "chunkio.h"
  34. #ifdef _DEBUG
  35. #define new DEBUG_NEW
  36. #undef THIS_FILE
  37. static char THIS_FILE[] = __FILE__;
  38. #endif
  39. #define ORTHO_CAMERA 0
  40. #define ORTHO_WIDTH 20
  41. ////////////////////////////////////////////////////////////////////////////
  42. //
  43. // CHUNK ID's used by GraphicView
  44. //
  45. enum
  46. {
  47. GRAPHICVIEW_CHUNK_VARIABLES = 0x00789931,
  48. GRAPHICVIEW_VARIABLE_CAMERAMODE = 0x00,
  49. GRAPHICVIEW_VARIABLE_DISPLAYBOXES,
  50. GRAPHICVIEW_VARIABLE_RUNSIMULATION,
  51. GRAPHICVIEW_VARIABLE_CAMERATM,
  52. };
  53. const float PIP_VIEW = 0.2f; // size of the pip viewport
  54. ////////////////////////////////////////////////////////////////////////////
  55. //
  56. // TimerCallback
  57. //
  58. void CALLBACK TimerCallback
  59. (
  60. UINT uID,
  61. UINT uMsg,
  62. DWORD dwUser,
  63. DWORD dw1,
  64. DWORD dw2
  65. )
  66. {
  67. HWND hwnd = (HWND)dwUser;
  68. if (IsWindow(hwnd)) {
  69. // Send this event off to the view to process (hackish, but fine for now)
  70. if ((GetProp (hwnd, "WaitingToProcess") == NULL) &&
  71. (GetProp (hwnd, "Inactive") == NULL)) {
  72. SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
  73. // Send the message to the view
  74. ::PostMessage (hwnd, WM_USER + 101, 0, 0L);
  75. }
  76. }
  77. }
  78. ////////////////////////////////////////////////////////////////////////////
  79. //
  80. // WindowProc
  81. //
  82. LRESULT CGraphicView::WindowProc
  83. (
  84. UINT message,
  85. WPARAM wParam,
  86. LPARAM lParam
  87. )
  88. {
  89. // Is this the repaint message we are expecting?
  90. if (message == WM_USER+101) {
  91. Timestep();
  92. Repaint_View();
  93. RemoveProp(m_hWnd,"WaitingToProcess");
  94. }
  95. // Allow the base class to process this message
  96. return CView::WindowProc(message, wParam, lParam);
  97. }
  98. /////////////////////////////////////////////////////////////////////////////
  99. // CGraphicView
  100. IMPLEMENT_DYNCREATE(CGraphicView, CView)
  101. BEGIN_MESSAGE_MAP(CGraphicView, CView)
  102. //{{AFX_MSG_MAP(CGraphicView)
  103. ON_WM_SIZE()
  104. ON_WM_DESTROY()
  105. ON_WM_LBUTTONDOWN()
  106. ON_WM_LBUTTONUP()
  107. ON_WM_RBUTTONDOWN()
  108. ON_WM_RBUTTONUP()
  109. ON_WM_MOUSEMOVE()
  110. //}}AFX_MSG_MAP
  111. END_MESSAGE_MAP()
  112. /////////////////////////////////////////////////////////////////////////////
  113. // CGraphicView construction/destruction
  114. CGraphicView::CGraphicView() :
  115. Initialized(false),
  116. Active(true),
  117. RunSimulation(false),
  118. DisplayBoxes(false),
  119. CameraMode(CAMERA_FLY),
  120. Camera(NULL),
  121. TimerID(0),
  122. LMouseDown(false),
  123. RMouseDown(false),
  124. LastPoint(0,0),
  125. PipCamera(NULL),
  126. PipScene(NULL),
  127. Axes(NULL)
  128. {
  129. }
  130. CGraphicView::~CGraphicView()
  131. {
  132. REF_PTR_RELEASE(Camera);
  133. REF_PTR_RELEASE(PipCamera);
  134. REF_PTR_RELEASE(PipScene);
  135. REF_PTR_RELEASE(Axes);
  136. }
  137. BOOL CGraphicView::PreCreateWindow(CREATESTRUCT& cs)
  138. {
  139. // TODO: Modify the Window class or styles here by modifying
  140. // the CREATESTRUCT cs
  141. return CView::PreCreateWindow(cs);
  142. }
  143. BOOL CGraphicView::Initialize_WW3D(int device,int bits)
  144. {
  145. // Assume failure
  146. BOOL ok = FALSE;
  147. if (device < 0) {
  148. return FALSE;
  149. }
  150. // Initialize the rendering engine with the information from
  151. // this window.
  152. RECT rect;
  153. GetClientRect (&rect);
  154. int cx = rect.right-rect.left;
  155. int cy = rect.bottom-rect.top;
  156. WW3DErrorType err = WW3D_ERROR_GENERIC;
  157. while (err != WW3D_ERROR_OK) {
  158. err = WW3D::Set_Render_Device(device,cx,cy,bits,true);
  159. if (err != WW3D_ERROR_OK) {
  160. device = (device + 1) % WW3D::Get_Render_Device_Count();
  161. }
  162. }
  163. // Load some models that we're going to need into the asset manager
  164. ResourceFileClass point_file(NULL, "Point.w3d");
  165. WW3DAssetManager::Get_Instance()->Load_3D_Assets(point_file);
  166. ResourceFileClass axes_file(NULL, "Axes.w3d");
  167. WW3DAssetManager::Get_Instance()->Load_3D_Assets(axes_file);
  168. if (Camera == NULL) {
  169. Camera = NEW_REF(CameraClass,());
  170. ASSERT(Camera);
  171. // Init the camera
  172. Matrix3D transform;
  173. transform.Look_At(Vector3(0.0f,-15.0f,5.0f),Vector3(0,0,0),0);
  174. Camera->Set_Transform(transform);
  175. // update the camera FOV settings
  176. // take the larger of the two dimensions, give it the
  177. // full desired FOV, then give the other dimension an
  178. // FOV proportional to its relative size
  179. double hfov,vfov;
  180. if (cy > cx) {
  181. vfov = (float)DEG_TO_RAD(45.0f);
  182. hfov = (double)cx / (double)cy * vfov;
  183. } else {
  184. hfov = (float)DEG_TO_RAD(45.0f);
  185. vfov = (double)cy / (double)cx * hfov;
  186. }
  187. // Reset the field of view
  188. Camera->Set_View_Plane(hfov,vfov);
  189. #if ORTHO_CAMERA
  190. Camera->Set_Projection_Type(CameraClass::ORTHO);
  191. Camera->Set_View_Plane(Vector2(-ORTHO_WIDTH,-ORTHO_WIDTH),Vector2(ORTHO_WIDTH,ORTHO_WIDTH));
  192. #endif
  193. }
  194. if (PipCamera == NULL) {
  195. PipCamera = NEW_REF(CameraClass,());
  196. ASSERT(PipCamera);
  197. PipCamera->Set_Viewport(Vector2(0.0f,1.0f - PIP_VIEW),Vector2(PIP_VIEW,1.0f));
  198. PipCamera->Set_View_Plane(Camera->Get_Horizontal_FOV(),Camera->Get_Vertical_FOV());
  199. Update_Pip_Camera();
  200. }
  201. if (PipScene == NULL) {
  202. PipScene = NEW_REF(SimpleSceneClass,());
  203. PipScene->Set_Ambient_Light(Vector3(1,1,1));
  204. ASSERT(PipScene);
  205. }
  206. if (Axes == NULL) {
  207. Axes = WW3DAssetManager::Get_Instance()->Create_Render_Obj("Axes");
  208. ASSERT(Axes);
  209. Axes->Set_Transform(Matrix3D(1));
  210. PipScene->Add_Render_Object(Axes);
  211. }
  212. // Kick off a timer that we can use to update
  213. // the display (kinda like a game loop iterator)
  214. if (TimerID == 0) {
  215. #if 0
  216. TimerID = (UINT)::timeSetEvent( 50,
  217. 50,
  218. TimerCallback,
  219. (DWORD)m_hWnd,
  220. TIME_PERIODIC);
  221. #else
  222. TimerID = (UINT)::timeSetEvent( 66, // only update 15 times a second
  223. 50,
  224. TimerCallback,
  225. (DWORD)m_hWnd,
  226. TIME_PERIODIC);
  227. #endif
  228. }
  229. Initialized = true;
  230. // Return the TRUE/FALSE result code
  231. return TRUE;
  232. }
  233. void CGraphicView::Save(ChunkSaveClass & csave)
  234. {
  235. Matrix3D cameratm = Camera->Get_Transform();
  236. csave.Begin_Chunk(GRAPHICVIEW_CHUNK_VARIABLES);
  237. WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_CAMERAMODE,CameraMode);
  238. WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_DISPLAYBOXES,DisplayBoxes);
  239. WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_RUNSIMULATION,RunSimulation);
  240. WRITE_MICRO_CHUNK(csave,GRAPHICVIEW_VARIABLE_CAMERATM,cameratm);
  241. csave.End_Chunk();
  242. }
  243. void CGraphicView::Load(ChunkLoadClass & cload)
  244. {
  245. Matrix3D cameratm(1);
  246. while (cload.Open_Chunk()) {
  247. switch(cload.Cur_Chunk_ID()) {
  248. case GRAPHICVIEW_CHUNK_VARIABLES:
  249. while(cload.Open_Micro_Chunk()) {
  250. switch(cload.Cur_Micro_Chunk_ID()) {
  251. READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_CAMERAMODE,CameraMode);
  252. READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_DISPLAYBOXES,DisplayBoxes);
  253. READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_RUNSIMULATION,RunSimulation);
  254. READ_MICRO_CHUNK(cload,GRAPHICVIEW_VARIABLE_CAMERATM,cameratm);
  255. }
  256. cload.Close_Micro_Chunk();
  257. }
  258. break;
  259. default:
  260. WWDEBUG_SAY(("Unhandled chunk: %d File: %s Line: %d\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  261. }
  262. cload.Close_Chunk();
  263. }
  264. Camera->Set_Transform(cameratm);
  265. }
  266. /////////////////////////////////////////////////////////////////////////////
  267. // CGraphicView drawing
  268. void CGraphicView::OnDraw(CDC* pDC)
  269. {
  270. Repaint_View();
  271. }
  272. /////////////////////////////////////////////////////////////////////////////
  273. // CGraphicView diagnostics
  274. #ifdef _DEBUG
  275. void CGraphicView::AssertValid() const
  276. {
  277. CView::AssertValid();
  278. }
  279. void CGraphicView::Dump(CDumpContext& dc) const
  280. {
  281. CView::Dump(dc);
  282. }
  283. CPhysTestDoc* CGraphicView::GetDocument() // non-debug version is inline
  284. {
  285. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPhysTestDoc)));
  286. return (CPhysTestDoc*)m_pDocument;
  287. }
  288. #endif //_DEBUG
  289. /////////////////////////////////////////////////////////////////////////////
  290. // CGraphicView message handlers
  291. void CGraphicView::OnSize(UINT nType, int cx, int cy)
  292. {
  293. CView::OnSize(nType, cx, cy);
  294. if (Initialized)
  295. {
  296. // Change the resolution of the rendering device to
  297. // match that of the view's current dimensions
  298. WW3D::Set_Resolution (cx, cy, -1, true);
  299. // update the camera FOV settings
  300. // take the larger of the two dimensions, give it the
  301. // full desired FOV, then give the other dimension an
  302. // FOV proportional to its relative size
  303. double hfov,vfov;
  304. if (cy > cx) {
  305. vfov = (float)DEG_TO_RAD(45.0f);
  306. hfov = (double)cx / (double)cy * vfov;
  307. } else {
  308. hfov = (float)DEG_TO_RAD(45.0f);
  309. vfov = (double)cy / (double)cx * hfov;
  310. }
  311. // Reset the field of view
  312. ASSERT(Camera);
  313. Camera->Set_View_Plane(hfov, vfov);
  314. #if ORTHO_CAMERA
  315. Camera->Set_View_Plane(Vector2(-ORTHO_WIDTH,-ORTHO_WIDTH),Vector2(ORTHO_WIDTH,ORTHO_WIDTH));
  316. #endif
  317. PipCamera->Set_View_Plane(hfov,vfov);
  318. // Force a repaint of the screen
  319. Repaint_View();
  320. }
  321. }
  322. void CGraphicView::OnInitialUpdate()
  323. {
  324. CView::OnInitialUpdate();
  325. CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
  326. if (doc) {
  327. // tell the document to create the scene
  328. doc->Init_Scene();
  329. }
  330. }
  331. void CGraphicView::Timestep(void)
  332. {
  333. const float FLY_VELOCITY = 10.0f;
  334. // Compute the amount of time elapsed for this frame.
  335. CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
  336. DWORD curtime = ::GetTickCount();
  337. DWORD elapsedtime = curtime - doc->LastTime;
  338. if (elapsedtime > 100) {
  339. elapsedtime = 100;
  340. }
  341. float dt = (float)elapsedtime / 1000.0f;
  342. doc->LastTime = curtime;
  343. // fly forward when control is held
  344. if (::GetAsyncKeyState('A') & 0x8000) {
  345. Matrix3D transform = Camera->Get_Transform();
  346. transform.Translate(Vector3(0,0,-FLY_VELOCITY * dt));
  347. Camera->Set_Transform(transform);
  348. }
  349. if (::GetAsyncKeyState('Z') & 0x8000) {
  350. Matrix3D transform = Camera->Get_Transform();
  351. transform.Translate(Vector3(0,0,FLY_VELOCITY * dt));
  352. Camera->Set_Transform(transform);
  353. }
  354. // if mode == follow and we have an object selected, look at it
  355. if (CameraMode == CAMERA_FOLLOW) {
  356. CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
  357. PhysClass * obj = wnd->Peek_Selected_Object();
  358. if (obj) {
  359. Vector3 target;
  360. obj->Get_Transform().Get_Translation(&target);
  361. Vector3 pos;
  362. Camera->Get_Transform().Get_Translation(&pos);
  363. Matrix3D tm;
  364. tm.Look_At(pos,target,0.0f);
  365. Camera->Set_Transform(tm);
  366. }
  367. }
  368. // if mode == tether and we have an object selected, tie the camera to it
  369. if ((CameraMode == CAMERA_TETHER) || (CameraMode == CAMERA_RIGID_TETHER)) {
  370. CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
  371. PhysClass * obj = wnd->Peek_Selected_Object();
  372. if (obj) {
  373. const float TETHER_DIST = 15.0f;
  374. const float TETHER_ANGLE = DEG_TO_RADF(-20.0f);
  375. Vector3 pos;
  376. float zrot = obj->Get_Transform().Get_Z_Rotation();
  377. obj->Get_Transform().Get_Translation(&pos);
  378. Matrix3D tm(1);
  379. if (CameraMode == CAMERA_RIGID_TETHER) {
  380. tm = obj->Get_Transform();
  381. } else {
  382. tm.Translate(pos);
  383. tm.Rotate_Z(zrot);
  384. }
  385. tm.Rotate_Y(DEG_TO_RADF(-90.0f));
  386. tm.Rotate_Z(DEG_TO_RADF(-90.0f));
  387. tm.Rotate_X(TETHER_ANGLE);
  388. tm.Translate(Vector3(0,0,TETHER_DIST));
  389. Camera->Set_Transform(tm);
  390. }
  391. }
  392. // update the PIP camera transform
  393. Update_Pip_Camera();
  394. // Allow the world to simulate (if enabled)
  395. if (RunSimulation) {
  396. doc->Scene->Update(1.0f/15.0f , 0); // 0.05f,0); //dt,0);
  397. }
  398. // DEBUG, print the contact point coordinates
  399. #if 0
  400. Vector3 pt = _LastContactPoint;
  401. CString string;
  402. string.Format("Contact Point: %10.5f %10.5f %10.5f StartBad: %d",pt.X,pt.Y,pt.Z,_StartBad);
  403. ((CMainFrame *)::AfxGetMainWnd())->Set_Status_Bar_Text(string);
  404. #endif
  405. }
  406. void CGraphicView::Repaint_View(void)
  407. {
  408. static bool _already_painting = false;
  409. if (_already_painting) return;
  410. _already_painting = true;
  411. // Get the document to display
  412. CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
  413. // Are we in a valid state?
  414. if (Initialized && doc->Scene) {
  415. // Update the W3D frame times according to our elapsed tick count
  416. //WW3D::Sync(WW3D::Get_Sync_Time() + (ticks_elapsed * m_animationSpeed));
  417. // Render the scenes
  418. WW3D::Begin_Render(TRUE, TRUE, Vector3(0,0,0));
  419. WW3D::Render(doc->Scene,Camera,FALSE,FALSE);
  420. WW3D::Render(PipScene,PipCamera,FALSE,TRUE);
  421. WW3D::End_Render();
  422. }
  423. _already_painting = false;
  424. }
  425. void CGraphicView::Set_Active(bool onoff)
  426. {
  427. Active = onoff;
  428. if (!Active) {
  429. ::SetProp(m_hWnd,"Inactive",(HANDLE)1);
  430. } else {
  431. RemoveProp(m_hWnd,"Inactive");
  432. CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
  433. doc->LastTime = ::GetTickCount();
  434. }
  435. }
  436. bool CGraphicView::Is_Collision_Box_Display_Enabled(void)
  437. {
  438. return DisplayBoxes;
  439. }
  440. void CGraphicView::Enable_Collision_Box_Display(bool onoff)
  441. {
  442. DisplayBoxes = onoff;
  443. if (DisplayBoxes) {
  444. WW3D::Set_Collision_Box_Display_Mask(COLLISION_TYPE_PHYSICAL);
  445. } else {
  446. WW3D::Set_Collision_Box_Display_Mask(0);
  447. }
  448. }
  449. void CGraphicView::OnDestroy()
  450. {
  451. // remove our properties
  452. ::RemoveProp(m_hWnd,"Inactive");
  453. ::RemoveProp(m_hWnd,"WaitingToProcess");
  454. CView::OnDestroy();
  455. // Free the camera object
  456. REF_PTR_RELEASE(Camera);
  457. REF_PTR_RELEASE(PipScene);
  458. REF_PTR_RELEASE(PipCamera);
  459. REF_PTR_RELEASE(Axes);
  460. // Is there an update thread running?
  461. if (TimerID == 0) {
  462. // Stop the timer
  463. ::timeKillEvent((UINT)TimerID);
  464. TimerID = 0;
  465. }
  466. Initialized = FALSE;
  467. }
  468. void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point)
  469. {
  470. // Capture all mouse messages
  471. SetCapture();
  472. // Left mouse button is down
  473. LMouseDown = TRUE;
  474. LastPoint = point;
  475. // Allow the base class to process this message
  476. CView::OnLButtonDown(nFlags, point);
  477. }
  478. void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
  479. {
  480. // if both buttons are now up, release the mouse
  481. if (!RMouseDown) {
  482. ReleaseCapture();
  483. }
  484. // Left mouse button is now up
  485. LMouseDown = false;
  486. CView::OnLButtonUp(nFlags, point);
  487. }
  488. void CGraphicView::OnRButtonDown(UINT nFlags, CPoint point)
  489. {
  490. // Capture all mouse messages
  491. SetCapture();
  492. // Right mouse button is down
  493. RMouseDown = TRUE;
  494. LastPoint = point;
  495. CView::OnRButtonDown(nFlags, point);
  496. }
  497. void CGraphicView::OnRButtonUp(UINT nFlags, CPoint point)
  498. {
  499. // if both buttons are now up, release the mouse
  500. if (!LMouseDown) {
  501. ReleaseCapture();
  502. }
  503. // Right mouse button is now up
  504. RMouseDown = false;
  505. CView::OnRButtonUp(nFlags, point);
  506. }
  507. void CGraphicView::OnMouseMove(UINT nFlags, CPoint point)
  508. {
  509. // Get the document to display
  510. CPhysTestDoc * doc = (CPhysTestDoc *)GetDocument();
  511. WWASSERT(doc);
  512. #if 0
  513. PhysicsSceneClass * scene = doc->Scene;
  514. WWASSERT(scene);
  515. #endif
  516. // When Only the Left mouse button is down, we "look-around" with
  517. // vertical locking (rotate about Z until Y points up)
  518. if ((LMouseDown) && (!RMouseDown)) {
  519. // Are we in a valid state?
  520. if (Initialized && doc->Scene) {
  521. RECT rect;
  522. GetClientRect (&rect);
  523. float mid_point_x = float(rect.right >> 1);
  524. float mid_point_y = float(rect.bottom >> 1);
  525. float last_point_x = ((float)LastPoint.x - mid_point_x) / mid_point_x;
  526. float last_point_y = (mid_point_y - (float)LastPoint.y) / mid_point_y;
  527. float point_x = ((float)point.x - mid_point_x) / mid_point_x;
  528. float point_y = (mid_point_y - (float)point.y) / mid_point_y;
  529. // invert the axes (being lazy here...)
  530. point_x = -point_x;
  531. point_y = -point_y;
  532. last_point_x = -last_point_x;
  533. last_point_y = -last_point_y;
  534. // Rotate around the object (orbit) using a 0.00F - 1.00F percentage of
  535. // the mouse coordinates
  536. Quaternion rotation = ::Trackball (last_point_x,last_point_y,point_x,point_y, 0.8F);
  537. // If we're not in CAMERA_FOLLOW mode, just rotate our view
  538. if (CameraMode != CAMERA_FOLLOW) {
  539. // Apply the rotation to the camera
  540. Matrix3D transform = Camera->Get_Transform ();
  541. Matrix3D::Multiply(transform,Build_Matrix3D(rotation),&transform);
  542. // Straighten out the Y axis
  543. Vector3 pos = transform.Get_Translation();
  544. Vector3 target = transform * Vector3(0,0,-1);
  545. transform.Look_At(pos,target,0.0f);
  546. // Rotate and translate the camera
  547. Camera->Set_Transform (transform);
  548. } else {
  549. // We're in camera follow mode, this means the camera is always going
  550. // to point right at the object. We want to orbit the camera's position
  551. // around the object.
  552. Matrix3D camera_tm = Camera->Get_Transform();
  553. Vector3 relative_obj_pos(0,0,-10);
  554. CMainFrame * wnd = (CMainFrame *)::AfxGetMainWnd();
  555. PhysClass * obj = wnd->Peek_Selected_Object();
  556. if (obj) {
  557. Vector3 obj_pos;
  558. obj->Get_Transform().Get_Translation(&obj_pos);
  559. Matrix3D::Inverse_Transform_Vector(camera_tm,obj_pos,&relative_obj_pos);
  560. }
  561. camera_tm.Translate(relative_obj_pos);
  562. Matrix3D rotation_tm;
  563. Build_Matrix3D(rotation).Get_Orthogonal_Inverse(rotation_tm);
  564. Matrix3D::Multiply(camera_tm,rotation_tm,&camera_tm);
  565. camera_tm.Translate(-relative_obj_pos);
  566. Camera->Set_Transform(camera_tm);
  567. }
  568. }
  569. }
  570. LastPoint = point;
  571. Update_Pip_Camera();
  572. CView::OnMouseMove(nFlags, point);
  573. }
  574. void CGraphicView::Update_Pip_Camera(void)
  575. {
  576. if (PipCamera && Camera) {
  577. Matrix3D transform = Camera->Get_Transform();
  578. transform.Set_Translation(Vector3(0,0,0));
  579. transform.Translate(Vector3(0,0,4));
  580. PipCamera->Set_Transform(transform);
  581. }
  582. }