GraphicView.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792
  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 file
  19. //
  20. #include "stdafx.h"
  21. #include "w3dview.h"
  22. #include "graphicview.h"
  23. #include "ww3d.h"
  24. #include "globals.h"
  25. #include "w3dviewdoc.h"
  26. #include <process.h>
  27. #include "quat.h"
  28. #include "mainfrm.h"
  29. #include "utils.h"
  30. #include "mmsystem.h"
  31. #include "light.h"
  32. #include "viewerassetmgr.h"
  33. #include "rcfile.h"
  34. #include "part_emt.h"
  35. #include "part_buf.h"
  36. #include "hlod.h"
  37. #include "viewerscene.h"
  38. #include "screencursor.h"
  39. #include "mesh.h"
  40. #include "coltest.h"
  41. #include "mpu.h"
  42. #include "dazzle.h"
  43. #include "soundscene.h"
  44. #include "wwaudio.h"
  45. #include "metalmap.h"
  46. #include "dx8wrapper.h"
  47. #ifdef _DEBUG
  48. #define new DEBUG_NEW
  49. #undef THIS_FILE
  50. static char THIS_FILE[] = __FILE__;
  51. #endif
  52. /////////////////////////////////////////////////////////////////////////
  53. // Local Prototypes
  54. /////////////////////////////////////////////////////////////////////////
  55. void CALLBACK fnTimerCallback (UINT, UINT, DWORD, DWORD, DWORD);
  56. IMPLEMENT_DYNCREATE(CGraphicView, CView)
  57. ////////////////////////////////////////////////////////////////////////////
  58. //
  59. // CGraphicView
  60. //
  61. ////////////////////////////////////////////////////////////////////////////
  62. CGraphicView::CGraphicView (void)
  63. : m_bInitialized (FALSE),
  64. m_pCamera (NULL),
  65. m_TimerID (0),
  66. m_bMouseDown (FALSE),
  67. m_bRMouseDown (FALSE),
  68. m_bActive (TRUE),
  69. m_animationSpeed (1.0F),
  70. m_dwLastFrameUpdate (0),
  71. m_iWindowed (1),
  72. m_animationState (AnimInvalid),
  73. m_objectRotation (NoRotation),
  74. m_LightRotation (NoRotation),
  75. m_bLightMeshInScene (false),
  76. m_pLightMesh (NULL),
  77. m_ParticleCountUpdate (0),
  78. m_CameraBonePosX (false),
  79. m_UpdateCounter (0),
  80. m_allowedCameraRotation (FreeRotation),
  81. m_ObjectCenter (0.0f, 0.0f, 0.0f)
  82. {
  83. // Get the windowed mode from the registry
  84. CString string_windowed = theApp.GetProfileString ("Config", "Windowed", "1");
  85. m_iWindowed = ::atoi ((LPCTSTR)string_windowed);
  86. return ;
  87. }
  88. ////////////////////////////////////////////////////////////////////////////
  89. //
  90. // ~CGraphicView
  91. //
  92. ////////////////////////////////////////////////////////////////////////////
  93. CGraphicView::~CGraphicView ()
  94. {
  95. return ;
  96. }
  97. BEGIN_MESSAGE_MAP(CGraphicView, CView)
  98. //{{AFX_MSG_MAP(CGraphicView)
  99. ON_WM_CREATE()
  100. ON_WM_SIZE()
  101. ON_WM_DESTROY()
  102. ON_WM_LBUTTONDOWN()
  103. ON_WM_LBUTTONUP()
  104. ON_WM_MOUSEMOVE()
  105. ON_WM_RBUTTONUP()
  106. ON_WM_RBUTTONDOWN()
  107. ON_WM_GETMINMAXINFO()
  108. //}}AFX_MSG_MAP
  109. END_MESSAGE_MAP()
  110. ////////////////////////////////////////////////////////////////////////////
  111. //
  112. // OnDraw
  113. //
  114. ////////////////////////////////////////////////////////////////////////////
  115. void
  116. CGraphicView::OnDraw (CDC* pDC)
  117. {
  118. // Get the document to display
  119. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  120. // Are we in a valid state?
  121. if (!pDC->IsPrinting ())
  122. {
  123. }
  124. return ;
  125. }
  126. #ifdef _DEBUG
  127. void CGraphicView::AssertValid() const
  128. {
  129. CView::AssertValid();
  130. }
  131. void CGraphicView::Dump(CDumpContext& dc) const
  132. {
  133. CView::Dump(dc);
  134. }
  135. #endif //_DEBUG
  136. ////////////////////////////////////////////////////////////////////////////
  137. //
  138. // PreCreateWindow
  139. //
  140. ////////////////////////////////////////////////////////////////////////////
  141. int
  142. CGraphicView::OnCreate (LPCREATESTRUCT lpCreateStruct)
  143. {
  144. // Allow the base class to process this message
  145. if (CView::OnCreate(lpCreateStruct) == -1)
  146. return -1;
  147. m_dwLastFrameUpdate = timeGetTime ();//::GetTickCount ();
  148. return 0;
  149. }
  150. ////////////////////////////////////////////////////////////////////////////
  151. //
  152. // InitializeGraphicView
  153. //
  154. ////////////////////////////////////////////////////////////////////////////
  155. BOOL
  156. CGraphicView::InitializeGraphicView (void)
  157. {
  158. // Assume failure
  159. BOOL bReturn = FALSE;
  160. if (g_iDeviceIndex < 0) {
  161. return FALSE;
  162. }
  163. m_bInitialized = FALSE;
  164. // Initialize the rendering engine with the information from
  165. // this window.
  166. RECT rect;
  167. GetClientRect (&rect);
  168. int cx = rect.right-rect.left;
  169. int cy = rect.bottom-rect.top;
  170. if (m_iWindowed == 0) {
  171. cx = g_iWidth;
  172. cy = g_iHeight;
  173. ((CW3DViewDoc *)GetDocument())->Show_Cursor (true);
  174. } else {
  175. ((CW3DViewDoc *)GetDocument())->Show_Cursor (false);
  176. }
  177. bReturn = (WW3D::Set_Render_Device (g_iDeviceIndex,
  178. cx,
  179. cy,
  180. g_iBitsPerPixel,
  181. m_iWindowed) == WW3D_ERROR_OK);
  182. ASSERT (bReturn);
  183. if (bReturn && (m_pCamera == NULL))
  184. {
  185. // Instantiate a new camera class
  186. m_pCamera = new CameraClass ();
  187. bReturn = (m_pCamera != NULL);
  188. // Were we successful in creating a camera?
  189. ASSERT (m_pCamera);
  190. if (m_pCamera)
  191. {
  192. // Create a transformation matrix
  193. Matrix3D transform (1);
  194. transform.Translate (Vector3 (0.0F, 0.0F, 35.0F));
  195. // Point the camera in this direction (I think)
  196. m_pCamera->Set_Transform (transform);
  197. }
  198. //
  199. // Attach the 'listener' to the camera
  200. //
  201. WWAudioClass::Get_Instance ()->Get_Sound_Scene ()->Attach_Listener_To_Obj (m_pCamera);
  202. }
  203. Reset_FOV ();
  204. if (m_pLightMesh == NULL)
  205. {
  206. ResourceFileClass light_mesh_file (NULL, "Light.w3d");
  207. WW3DAssetManager::Get_Instance()->Load_3D_Assets (light_mesh_file);
  208. m_pLightMesh = WW3DAssetManager::Get_Instance()->Create_Render_Obj ("LIGHT");
  209. ASSERT (m_pLightMesh != NULL);
  210. m_bLightMeshInScene = false;
  211. }
  212. // Remember whether or not we are initialized
  213. m_bInitialized = bReturn;
  214. if (m_bInitialized && (m_TimerID == 0))
  215. {
  216. // Kick off a timer that we can use to update
  217. // the display (kinda like a game loop iterator)
  218. TIMECAPS caps = { 0 };
  219. ::timeGetDevCaps (&caps, sizeof (TIMECAPS));
  220. UINT freq = max (caps.wPeriodMin, 16U);
  221. m_TimerID = (UINT)::timeSetEvent (freq,
  222. freq,
  223. fnTimerCallback,
  224. (DWORD)m_hWnd,
  225. TIME_PERIODIC);
  226. }
  227. // Return the TRUE/FALSE result code
  228. return bReturn;
  229. }
  230. ////////////////////////////////////////////////////////////////////////////
  231. //
  232. // OnSize
  233. //
  234. ////////////////////////////////////////////////////////////////////////////
  235. void
  236. CGraphicView::OnSize
  237. (
  238. UINT nType,
  239. int cx,
  240. int cy
  241. )
  242. {
  243. // Allow the base class to process this message
  244. CView::OnSize (nType, cx, cy);
  245. if (m_bInitialized) {
  246. if (m_iWindowed == 0) {
  247. cx = g_iWidth;
  248. cy = g_iHeight;
  249. }
  250. // Change the resolution of the rendering device to
  251. // match that of the view's current dimensions
  252. if (m_iWindowed == 1) {
  253. WW3D::Set_Device_Resolution (cx, cy, g_iBitsPerPixel, m_iWindowed);
  254. }
  255. // Force a repaint of the screen
  256. Reset_FOV ();
  257. RepaintView ();
  258. }
  259. return ;
  260. }
  261. ////////////////////////////////////////////////////////////////////////////
  262. //
  263. // OnDestroy
  264. //
  265. ////////////////////////////////////////////////////////////////////////////
  266. void
  267. CGraphicView::OnDestroy (void)
  268. {
  269. // Allow the base class to process this message
  270. CView::OnDestroy ();
  271. //
  272. // Remove the listener from the camera
  273. //
  274. WWAudioClass::Get_Instance ()->Get_Sound_Scene ()->Attach_Listener_To_Obj (NULL);
  275. //
  276. // Free the camera object
  277. //
  278. MEMBER_RELEASE (m_pCamera);
  279. MEMBER_RELEASE (m_pLightMesh);
  280. // Is there an update thread running?
  281. if (m_TimerID == 0) {
  282. // Stop the timer
  283. ::timeKillEvent ((UINT)m_TimerID);
  284. m_TimerID = 0;
  285. }
  286. // Cache this information in the registry
  287. TCHAR temp_string[10];
  288. ::itoa (m_iWindowed, temp_string, 10);
  289. theApp.WriteProfileString ("Config", "Windowed", temp_string);
  290. // We are no longer initialized
  291. m_bInitialized = FALSE;
  292. return ;
  293. }
  294. ////////////////////////////////////////////////////////////////////////////
  295. //
  296. // OnInitialUpdate
  297. //
  298. ////////////////////////////////////////////////////////////////////////////
  299. void
  300. CGraphicView::OnInitialUpdate (void)
  301. {
  302. // Allow the base class to process this message
  303. CView::OnInitialUpdate ();
  304. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  305. if (doc)
  306. {
  307. // Ask the document to initialize the scene (if it hasn't
  308. // already done so)
  309. doc->InitScene ();
  310. }
  311. return ;
  312. }
  313. ////////////////////////////////////////////////////////////////////////////
  314. //
  315. // Set_Lowest_LOD
  316. //
  317. ////////////////////////////////////////////////////////////////////////////
  318. void
  319. Set_Lowest_LOD (RenderObjClass *render_obj)
  320. {
  321. if (render_obj != NULL) {
  322. for (int index = 0; index < render_obj->Get_Num_Sub_Objects (); index ++) {
  323. RenderObjClass *psub_obj = render_obj->Get_Sub_Object (index);
  324. if (psub_obj != NULL) {
  325. Set_Lowest_LOD (psub_obj);
  326. }
  327. MEMBER_RELEASE (psub_obj);
  328. }
  329. //
  330. // Switcht this LOD to its lowest level
  331. //
  332. if (render_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) {
  333. ((HLodClass *)render_obj)->Set_LOD_Level (0);
  334. }
  335. }
  336. return ;
  337. }
  338. ////////////////////////////////////////////////////////////////////////////
  339. //
  340. // Allow_Update
  341. //
  342. ////////////////////////////////////////////////////////////////////////////
  343. void
  344. CGraphicView::Allow_Update (bool onoff)
  345. {
  346. if (onoff) {
  347. m_UpdateCounter --;
  348. } else {
  349. m_UpdateCounter ++;
  350. }
  351. return ;
  352. }
  353. ////////////////////////////////////////////////////////////////////////////
  354. //
  355. // RepaintView
  356. //
  357. ////////////////////////////////////////////////////////////////////////////
  358. void
  359. CGraphicView::RepaintView
  360. (
  361. BOOL bUpdateAnimation,
  362. DWORD ticks_to_use
  363. )
  364. {
  365. //
  366. // Simple check to avoid re-entrance
  367. //
  368. static bool _already_painting = false;
  369. if (_already_painting) return;
  370. _already_painting = true;
  371. //
  372. // Are we in a valid state?
  373. //
  374. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  375. if (doc->Is_Initialized () && doc->GetScene () && m_UpdateCounter == 0) {
  376. // Only update the frame if the animation is
  377. // supposed to be playing
  378. int cur_ticks = timeGetTime();
  379. int ticks_elapsed = cur_ticks - m_dwLastFrameUpdate;
  380. m_dwLastFrameUpdate = cur_ticks;
  381. // Update the W3D frame times according to our elapsed tick count
  382. if (ticks_to_use == 0) {
  383. WW3D::Sync (WW3D::Get_Sync_Time() + (ticks_elapsed * m_animationSpeed));
  384. } else {
  385. WW3D::Sync (WW3D::Get_Sync_Time() + ticks_to_use);
  386. }
  387. // Do we need to update the current animation?
  388. if ((m_animationState == AnimPlaying) &&
  389. bUpdateAnimation)
  390. {
  391. float animationSpeed = ((float)ticks_elapsed) / 1000.00F;
  392. animationSpeed = (animationSpeed * m_animationSpeed);
  393. doc->UpdateFrame (animationSpeed);
  394. }
  395. // Perform the object rotation if necessary
  396. if ((m_objectRotation != NoRotation) &&
  397. (bUpdateAnimation == TRUE))
  398. {
  399. Rotate_Object ();
  400. }
  401. // Perform the light rotation if necessary
  402. if ((m_LightRotation != NoRotation) &&
  403. (bUpdateAnimation == TRUE))
  404. {
  405. Rotate_Light ();
  406. }
  407. // Reset the current lod to be the lowest possible LOD...
  408. RenderObjClass *prender_obj = doc->GetDisplayedObject ();
  409. if ((prender_obj != NULL) &&
  410. (doc->GetScene ()->Are_LODs_Switching ()))
  411. {
  412. Set_Lowest_LOD (prender_obj);
  413. }
  414. // Update the metal map
  415. // assuming object is at origin
  416. MetalMapManagerClass *metal=_TheAssetMgr->Peek_Metal_Map_Manager();
  417. if (metal)
  418. {
  419. LightClass *pscene_light = doc->GetSceneLight();
  420. Vector3 ambient,diffuse,l,v;
  421. ambient=doc->GetScene()->Get_Ambient_Light();
  422. pscene_light->Get_Diffuse(&diffuse);
  423. l=pscene_light->Get_Position();
  424. l.Normalize();
  425. v=m_pCamera->Get_Position();
  426. v.Normalize();
  427. metal->Update_Lighting(ambient,diffuse,l,v);
  428. metal->Update_Textures();
  429. }
  430. //
  431. // Render the background BMP
  432. //
  433. WW3D::Begin_Render (TRUE, TRUE, doc->GetBackgroundColor ());
  434. WW3D::Render (doc->Get2DScene (), doc->Get2DCamera (), FALSE, FALSE);
  435. //
  436. // Render the background scene
  437. //
  438. if (doc->GetBackgroundObjectName ().GetLength () > 0) {
  439. WW3D::Render (doc->GetBackObjectScene (), doc->GetBackObjectCamera (), FALSE, FALSE);
  440. }
  441. //
  442. // Render the main scene
  443. //
  444. DWORD pt_high = 0L;
  445. // Wait for all previous rendering to complete before starting benchmark.
  446. DWORD profile_time = ::Get_CPU_Clock (pt_high);
  447. WW3D::Render (doc->GetScene (), m_pCamera, FALSE, FALSE);
  448. // Wait for all rendering to complete before stopping benchmark.
  449. DWORD milliseconds = (::Get_CPU_Clock (pt_high) - profile_time) / 1000;
  450. //
  451. // Render the cursor
  452. //
  453. WW3D::Render (doc->GetCursorScene (), doc->Get2DCamera (), FALSE, FALSE);
  454. // Render the dazzles
  455. doc->Render_Dazzles(m_pCamera);
  456. // Finish out the rendering process
  457. WW3D::End_Render ();
  458. //
  459. // Let the audio class think
  460. //
  461. WWAudioClass::Get_Instance ()->On_Frame_Update ();
  462. //
  463. // Update the count of particles and polys in the status bar
  464. //
  465. if ((cur_ticks - m_ParticleCountUpdate > 250)) {
  466. m_ParticleCountUpdate = cur_ticks;
  467. doc->Update_Particle_Count ();
  468. int polys = (prender_obj != NULL) ? prender_obj->Get_Num_Polys () : 0;
  469. ((CMainFrame *)::AfxGetMainWnd ())->UpdatePolygonCount (polys);
  470. }
  471. //
  472. // Update the frame time in the status bar
  473. //
  474. ((CMainFrame *)::AfxGetMainWnd ())->Update_Frame_Time (milliseconds);
  475. }
  476. _already_painting = false;
  477. return ;
  478. }
  479. ////////////////////////////////////////////////////////////////////////////
  480. //
  481. // UpdateDisplay
  482. //
  483. ////////////////////////////////////////////////////////////////////////////
  484. void
  485. CGraphicView::UpdateDisplay (void)
  486. {
  487. // Get the document to display
  488. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  489. // Are we in a valid state?
  490. /*if (m_bInitialized && doc->GetScene ())
  491. {
  492. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  493. if (pCRenderObj)
  494. {
  495. Matrix3D transform = pCRenderObj->Get_Transform ();
  496. transform.Rotate_X (0.05F);
  497. transform.Rotate_Y (0.05F);
  498. transform.Rotate_Z (0.05F);
  499. pCRenderObj->Set_Transform (transform);
  500. }
  501. // Render the current view inside the frame
  502. WW3D::Begin_Render (TRUE, TRUE, Vector3 (0.2,0.4,0.6));
  503. WW3D::Render (doc->GetScene (), m_pCamera, FALSE, FALSE);
  504. WW3D::End_Render ();
  505. } */
  506. return ;
  507. }
  508. ////////////////////////////////////////////////////////////////////////////
  509. //
  510. // WindowProc
  511. //
  512. ////////////////////////////////////////////////////////////////////////////
  513. LRESULT
  514. CGraphicView::WindowProc
  515. (
  516. UINT message,
  517. WPARAM wParam,
  518. LPARAM lParam
  519. )
  520. {
  521. // Is this the repaint message we are expecting?
  522. if (message == WM_USER+101) {
  523. //
  524. // Force the repaint...
  525. //
  526. RepaintView ();
  527. RemoveProp (m_hWnd, "WaitingToProcess");
  528. } else if (message == WM_PAINT) {
  529. // If we are in fullscreen mode, then erase the window background
  530. if (m_iWindowed == 0) {
  531. // Get the client rectangle of the window
  532. RECT rect;
  533. GetClientRect (&rect);
  534. // Get the window's DC
  535. HDC hDC = ::GetDC (m_hWnd);
  536. if (hDC) {
  537. // Erase the background
  538. ::FillRect (hDC, &rect, (HBRUSH)(COLOR_WINDOW + 1));
  539. ::ReleaseDC (m_hWnd, hDC);
  540. }
  541. }
  542. RepaintView (FALSE);
  543. ValidateRect (NULL);
  544. return 0;
  545. } else if (message == WM_KEYDOWN) {
  546. if ((wParam == VK_CONTROL) && (m_bLightMeshInScene == false)) {
  547. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  548. m_pLightMesh->Add (doc->GetScene ());
  549. m_bLightMeshInScene = true;
  550. }
  551. } else if (message == WM_KEYUP) {
  552. if ((wParam == VK_CONTROL) && (m_bLightMeshInScene == true)) {
  553. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  554. m_pLightMesh->Remove ();
  555. m_bLightMeshInScene = false;
  556. }
  557. }
  558. // Allow the base class to process this message
  559. return CView::WindowProc(message, wParam, lParam);
  560. }
  561. ////////////////////////////////////////////////////////////////////////////
  562. //
  563. // fnTimerCallback
  564. //
  565. ////////////////////////////////////////////////////////////////////////////
  566. void CALLBACK
  567. fnTimerCallback
  568. (
  569. UINT uID,
  570. UINT uMsg,
  571. DWORD dwUser,
  572. DWORD dw1,
  573. DWORD dw2
  574. )
  575. {
  576. HWND hwnd = (HWND)dwUser;
  577. if (hwnd != NULL) {
  578. // Send this event off to the view to process (hackish, but fine for now)
  579. if ((GetProp (hwnd, "WaitingToProcess") == NULL) &&
  580. (GetProp (hwnd, "Inactive") == NULL)) {
  581. SetProp (hwnd, "WaitingToProcess", (HANDLE)1);
  582. // Send the message to the view so it will be in the
  583. // same thread (Surrender doesn't seem to be thread-safe)
  584. ::PostMessage (hwnd, WM_USER + 101, 0, 0L);
  585. }
  586. }
  587. return ;
  588. }
  589. ////////////////////////////////////////////////////////////////////////////
  590. //
  591. // OnLButtonDown
  592. //
  593. ////////////////////////////////////////////////////////////////////////////
  594. void
  595. CGraphicView::OnLButtonDown
  596. (
  597. UINT nFlags,
  598. CPoint point
  599. )
  600. {
  601. // Capture all mouse messages
  602. SetCapture ();
  603. // Mouse button is down
  604. m_bMouseDown = TRUE;
  605. m_lastPoint = point;
  606. if (m_bRMouseDown) {
  607. ::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_GRAB)));
  608. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("grab.tga");
  609. } else {
  610. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("orbit.tga");
  611. }
  612. CView::OnLButtonDown (nFlags, point);
  613. return ;
  614. }
  615. ////////////////////////////////////////////////////////////////////////////
  616. //
  617. // OnLButtonUp
  618. //
  619. ////////////////////////////////////////////////////////////////////////////
  620. void
  621. CGraphicView::OnLButtonUp
  622. (
  623. UINT nFlags,
  624. CPoint point
  625. )
  626. {
  627. if (!m_bRMouseDown)
  628. {
  629. // Release the mouse capture
  630. ReleaseCapture ();
  631. }
  632. // Mouse button is up
  633. m_bMouseDown = FALSE;
  634. if (m_bRMouseDown == TRUE)
  635. {
  636. ::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_ZOOM)));
  637. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("zoom.tga");
  638. }
  639. else
  640. {
  641. ::SetCursor (::LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)));
  642. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("cursor.tga");
  643. }
  644. // Allow the base class to process this message
  645. CView::OnLButtonUp (nFlags, point);
  646. return ;
  647. }
  648. float minZoomAdjust = 0.0F;
  649. Vector3 sphereCenter;
  650. Quaternion rotation;
  651. ////////////////////////////////////////////////////////////////////////////
  652. //
  653. // OnMouseMove
  654. //
  655. ////////////////////////////////////////////////////////////////////////////
  656. void
  657. CGraphicView::OnMouseMove
  658. (
  659. UINT nFlags,
  660. CPoint point
  661. )
  662. {
  663. int iDeltaX = m_lastPoint.x-point.x;
  664. int iDeltaY = m_lastPoint.y-point.y;
  665. // Get the document to display
  666. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  667. if (!(nFlags & MK_CONTROL) && m_bLightMeshInScene) {
  668. m_pLightMesh->Remove ();
  669. m_bLightMeshInScene = false;
  670. } else if ((nFlags & MK_CONTROL) && (m_bLightMeshInScene == false)) {
  671. m_pLightMesh->Add (doc->GetScene ());
  672. m_bLightMeshInScene = true;
  673. }
  674. // Is the mouse button down?
  675. if (m_bMouseDown && m_bRMouseDown)
  676. {
  677. // Get the transformation matrix for the camera and its inverse
  678. Matrix3D transform = m_pCamera->Get_Transform ();
  679. RECT rect;
  680. GetClientRect (&rect);
  681. float midPointX = float(rect.right >> 1);
  682. float midPointY = float(rect.bottom >> 1);
  683. float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
  684. float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
  685. float pointX = ((float)point.x - midPointX) / midPointX;
  686. float pointY = (midPointY - (float)point.y) / midPointY;
  687. Vector3 cameraPan = Vector3(-1.00F*m_CameraDistance*(pointX - lastPointX), -1.00F*m_CameraDistance*(pointY - lastPointY), 0.00F);
  688. transform.Translate (cameraPan);
  689. Matrix3 view = Build_Matrix3 (rotation);
  690. Vector3 move = view * cameraPan;
  691. sphereCenter += move;
  692. // Move the camera back to get a good view of the object
  693. m_pCamera->Set_Transform (transform);
  694. m_lastPoint = point;
  695. }
  696. // Is the mouse button down?
  697. else if ((nFlags & MK_CONTROL) && m_bMouseDown)
  698. {
  699. LightClass *pSceneLight = doc->GetSceneLight ();
  700. if ((pSceneLight != NULL) && (m_pLightMesh != NULL))
  701. {
  702. RECT rect;
  703. GetClientRect (&rect);
  704. Vector3 point_in_view;
  705. Vector3 lastpoint_in_view;
  706. float midPointX = float(rect.right >> 1);
  707. float midPointY = float(rect.bottom >> 1);
  708. float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
  709. float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
  710. float pointX = ((float)point.x - midPointX) / midPointX;
  711. float pointY = (midPointY - (float)point.y) / midPointY;
  712. Quaternion mouse_motion = Inverse(::Trackball(lastPointX, lastPointY, pointX, pointY, 0.8F));
  713. Quaternion light_orientation;
  714. Quaternion camera = Build_Quaternion(m_pCamera->Get_Transform());
  715. Quaternion cur_light = Build_Quaternion(pSceneLight->Get_Transform());
  716. light_orientation = camera;
  717. light_orientation = light_orientation * mouse_motion;
  718. light_orientation = light_orientation * Inverse(camera);
  719. light_orientation = light_orientation * cur_light;
  720. light_orientation.Normalize();
  721. Vector3 to_center;
  722. Matrix3D matrix = pSceneLight->Get_Transform();
  723. Matrix3D::Inverse_Transform_Vector(matrix,sphereCenter,&to_center);
  724. Matrix3D light_tm(light_orientation, sphereCenter);
  725. light_tm.Translate(-to_center);
  726. m_pLightMesh->Set_Transform(light_tm);
  727. pSceneLight->Set_Transform(light_tm);
  728. }
  729. m_lastPoint = point;
  730. }
  731. // Is the mouse button down?
  732. else if ((nFlags & MK_CONTROL) && m_bRMouseDown)
  733. {
  734. // Get the currently displayed object
  735. CW3DViewDoc *doc= (CW3DViewDoc *)GetDocument();
  736. LightClass *pscene_light = doc->GetSceneLight ();
  737. RenderObjClass *prender_obj = doc->GetDisplayedObject ();
  738. if ((pscene_light != NULL) && (prender_obj != NULL)) {
  739. // Calculate a light adjustment factor
  740. CRect rect;
  741. GetClientRect (&rect);
  742. float deltay = (float(iDeltaY))/(float(rect.bottom - rect.top));
  743. float adjustment = deltay * (m_ViewedSphere.Radius * 3.0F);
  744. // Determine the light's new position based on this factor
  745. Matrix3D transform = pscene_light->Get_Transform ();
  746. transform.Translate (Vector3 (0, 0, adjustment));
  747. // Determine what the distance from the light to the object
  748. // would be with this new position
  749. Vector3 light_pos = transform.Get_Translation ();
  750. Vector3 obj_pos = prender_obj->Get_Position ();
  751. float distance = (light_pos - obj_pos).Length ();
  752. // If the new position is acceptable, move the light
  753. if (distance > m_ViewedSphere.Radius) {
  754. m_pLightMesh->Set_Transform (transform);
  755. pscene_light->Set_Transform (transform);
  756. }
  757. }
  758. m_lastPoint = point;
  759. }
  760. // Is the mouse button down?
  761. else if (m_bMouseDown)
  762. {
  763. // Get the document to display
  764. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  765. // Are we in a valid state?
  766. if (m_bInitialized && doc->GetScene ())
  767. {
  768. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  769. if (pCRenderObj)
  770. {
  771. RECT rect;
  772. GetClientRect (&rect);
  773. float midPointX = float(rect.right >> 1);
  774. float midPointY = float(rect.bottom >> 1);
  775. float lastPointX = ((float)m_lastPoint.x - midPointX) / midPointX;
  776. float lastPointY = (midPointY - (float)m_lastPoint.y) / midPointY;
  777. float pointX = ((float)point.x - midPointX) / midPointX;
  778. float pointY = (midPointY - (float)point.y) / midPointY;
  779. // Rotate around the object (orbit) using a 0.00F - 1.00F percentage of
  780. // the mouse coordinates
  781. rotation = ::Trackball (lastPointX, lastPointY, pointX, pointY, 0.8F);
  782. // Do we want to 'lock-out' all rotation except X?
  783. if (m_allowedCameraRotation == OnlyRotateX)
  784. {
  785. Matrix3D tempMatrix = Build_Matrix3D (rotation);
  786. Matrix3D tempMatrix2 (1);
  787. tempMatrix2.Rotate_X (tempMatrix.Get_X_Rotation ());
  788. tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
  789. rotation = Build_Quaternion (tempMatrix2);
  790. }
  791. // Do we want to 'lock-out' all rotation except Y?
  792. else if (m_allowedCameraRotation == OnlyRotateY)
  793. {
  794. Matrix3D tempMatrix = Build_Matrix3D (rotation);
  795. Matrix3D tempMatrix2 (1);
  796. tempMatrix2.Rotate_Y (tempMatrix.Get_Y_Rotation ());
  797. tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
  798. rotation = Build_Quaternion (tempMatrix2);
  799. }
  800. // Do we want to 'lock-out' all rotation except Z?
  801. else if (m_allowedCameraRotation == OnlyRotateZ)
  802. {
  803. Matrix3D tempMatrix = Build_Matrix3D (rotation);
  804. Matrix3D tempMatrix2 (1);
  805. tempMatrix2.Rotate_Z (tempMatrix.Get_Z_Rotation ());
  806. tempMatrix2.Set_Translation (tempMatrix.Get_Translation ());
  807. rotation = Build_Quaternion (tempMatrix2);
  808. }
  809. // Get the transformation matrix for the camera and its inverse
  810. Matrix3D transform = m_pCamera->Get_Transform ();
  811. Matrix3D inverseMatrix;
  812. transform.Get_Orthogonal_Inverse (inverseMatrix);
  813. Vector3 to_object = inverseMatrix * sphereCenter;
  814. transform.Translate (to_object);
  815. Matrix3D::Multiply (transform, Build_Matrix3D (rotation), &transform);
  816. transform.Translate (-to_object);
  817. // Rotate and translate the camera
  818. m_pCamera->Set_Transform (transform);
  819. doc->GetBackObjectCamera ()->Set_Transform (transform);
  820. doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
  821. }
  822. }
  823. m_lastPoint = point;
  824. }
  825. else if (m_bRMouseDown)
  826. {
  827. m_lastPoint = point;
  828. // Get the transformation matrix for the camera and its inverse
  829. Matrix3D transform = m_pCamera->Get_Transform ();
  830. Vector3 distanceVectorZ = transform.Get_Z_Vector ();
  831. if (iDeltaY != 0)
  832. {
  833. // Get the bouding rectangle of the main view
  834. CRect rect;
  835. GetClientRect (&rect);
  836. float deltay = (float(iDeltaY))/(float(rect.bottom - rect.top));
  837. float adjustment = deltay * m_CameraDistance * 3.0F;
  838. if ((adjustment < minZoomAdjust) && (adjustment >= 0.00F))
  839. {
  840. adjustment = minZoomAdjust;
  841. }
  842. if ((adjustment > -minZoomAdjust) && (adjustment <= 0.00F))
  843. {
  844. adjustment = -minZoomAdjust;
  845. }
  846. if ((m_CameraDistance + adjustment) > 0.00F)
  847. {
  848. m_CameraDistance += adjustment;
  849. transform.Translate (Vector3 (0.0F, 0.0F, adjustment));
  850. // Move the camera back to get a good view of the object
  851. m_pCamera->Set_Transform (transform);
  852. // Get the main window of our app
  853. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  854. if (pCMainWnd != NULL)
  855. {
  856. // Ensure the background camera matches the main camera
  857. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  858. doc->GetBackObjectCamera ()->Set_Transform (transform);
  859. doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
  860. // Update the current object if necessary
  861. RenderObjClass *prender_obj = doc->GetDisplayedObject ();
  862. if (prender_obj != NULL) {
  863. // Ensure the status bar is updated with the correct poly count
  864. pCMainWnd->UpdatePolygonCount (prender_obj->Get_Num_Polys ());
  865. }
  866. // Ensure the status bar is updated with the correct camera distance
  867. pCMainWnd->UpdateCameraDistance (m_CameraDistance);
  868. }
  869. }
  870. }
  871. m_lastPoint = point;
  872. }
  873. // Allow the base class to process this message
  874. CView::OnMouseMove (nFlags, point);
  875. return ;
  876. }
  877. ////////////////////////////////////////////////////////////////////////////
  878. //
  879. // Reset_Camera_To_Display_Emitter
  880. //
  881. ////////////////////////////////////////////////////////////////////////////
  882. void
  883. CGraphicView::Reset_Camera_To_Display_Emitter (ParticleEmitterClass &emitter)
  884. {
  885. // Get some of the emitter settings
  886. Vector3 velocity = emitter.Get_Start_Velocity ();
  887. const Vector3 &acceleration = emitter.Get_Acceleration ();
  888. float lifetime = emitter.Get_Lifetime ();
  889. // If the velocity is 0, then use the randomizer as the default velocity
  890. bool use_vel_rand = false;
  891. if ((velocity.X == 0) && (velocity.Y == 0) && (velocity.Z == 0)) {
  892. //velocity.Set (emitter.Get_Velocity_Random (), emitter.Get_Velocity_Random (), emitter.Get_Velocity_Random ());
  893. //use_vel_rand = true;
  894. }
  895. // Determine what the max extent covered by a particle will be.
  896. Vector3 distance = (velocity * lifetime) + ((acceleration * (lifetime * lifetime)) / 2.0F);
  897. // Do we need to take into account acceleration?
  898. Vector3 distance_maxima (0, 0, 0);
  899. if ((acceleration.X != 0) || (acceleration.Y != 0) || (acceleration.Z != 0)) {
  900. // Determine at what time (for each x,y,z) a maxima will occur.
  901. Vector3 time_max (0, 0, 0);
  902. time_max.X = (acceleration.X != 0) ? ((-velocity.X) / acceleration.X) : 0.00F;
  903. time_max.Y = (acceleration.Y != 0) ? ((-velocity.Y) / acceleration.Y) : 0.00F;
  904. time_max.Z = (acceleration.Z != 0) ? ((-velocity.Z) / acceleration.Z) : 0.00F;
  905. // Is there a maxima for the X direction?
  906. if ((time_max.X >= 0.0F) && (time_max.X < lifetime)) {
  907. distance_maxima.X = (velocity.X * time_max.X) + ((acceleration.X * (time_max.X * time_max.X)) / 2.0F);
  908. distance_maxima.X = fabs (distance_maxima.X);
  909. }
  910. // Is there a maxima for the Y direction?
  911. if ((time_max.Y >= 0.0F) && (time_max.Y < lifetime)) {
  912. distance_maxima.Y = (velocity.Y * time_max.Y) + ((acceleration.Y * (time_max.Y * time_max.Y)) / 2.0F);
  913. distance_maxima.Y = fabs (distance_maxima.Y);
  914. }
  915. // Is there a maxima for the Z direction?
  916. if ((time_max.Z >= 0.0F) && (time_max.Z < lifetime)) {
  917. distance_maxima.Z = (velocity.Z * time_max.Z) + ((acceleration.Z * (time_max.Z * time_max.Z)) / 2.0F);
  918. distance_maxima.Z = fabs (distance_maxima.Z);
  919. }
  920. }
  921. distance.X = fabs (distance.X);
  922. distance.Y = fabs (distance.Y);
  923. distance.Z = fabs (distance.Z);
  924. // Determine what the maximum distance convered in a single direction is
  925. float max_dist = max (distance.X, distance.Y);
  926. max_dist = max (max_dist, distance.Z);
  927. max_dist = max (max_dist, distance_maxima.X);
  928. max_dist = max (max_dist, distance_maxima.Y);
  929. max_dist = max (max_dist, distance_maxima.Z);
  930. Vector3 center = distance / 2.00F;
  931. center.X = max (center.X, distance_maxima.X / 2.00F);
  932. center.Y = max (center.Y, distance_maxima.Y / 2.00F);
  933. center.Z = max (center.Z, distance_maxima.Z / 2.00F);
  934. if (use_vel_rand) {
  935. center.Set (0, 0, 0);
  936. }
  937. // Build a logical sphere from the emitters settings
  938. // that should provide a good viewing distance for the emitter.
  939. SphereClass sphere;
  940. sphere.Center = center;
  941. sphere.Radius = max (emitter.Get_Particle_Size () * 5, (max_dist * 3.0F) / 5.0F);
  942. // View this sphere
  943. Reset_Camera_To_Display_Sphere (sphere);
  944. return ;
  945. }
  946. ////////////////////////////////////////////////////////////////////////////
  947. //
  948. // Reset_Camera_To_Display_Sphere
  949. //
  950. ////////////////////////////////////////////////////////////////////////////
  951. void
  952. CGraphicView::Reset_Camera_To_Display_Sphere (SphereClass &sphere)
  953. {
  954. // Calculate a default camera distance to view this sphere
  955. m_CameraDistance = sphere.Radius * 3.00F;
  956. m_CameraDistance = (m_CameraDistance < 1.0F) ? 1.0F : m_CameraDistance;
  957. // Calculate a transform that is the appropriate distance
  958. // from the sphere center and is looking at the center
  959. Matrix3D transform (1);
  960. transform.Look_At (sphere.Center + Vector3 (m_CameraDistance, 0, 0), sphere.Center, 0);
  961. // Record some variables for later use
  962. sphereCenter = sphere.Center;
  963. m_ObjectCenter = sphereCenter;
  964. minZoomAdjust = m_CameraDistance / 190.0F;
  965. rotation = Build_Quaternion (transform);
  966. // Move the camera back to get a good view of the object
  967. m_pCamera->Set_Transform (transform);
  968. // Make the same adjustment for the scene light
  969. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  970. LightClass *pSceneLight = doc->GetSceneLight ();
  971. if ((m_pLightMesh != NULL) && (pSceneLight != NULL)) {
  972. // Reposition the light and its 'mesh' as appropriate
  973. transform.Make_Identity ();
  974. transform.Set_Translation (sphereCenter);
  975. transform.Translate (0, 0, 0.7F * m_CameraDistance);
  976. pSceneLight->Set_Transform (transform);
  977. m_pLightMesh->Set_Transform (transform);
  978. // Scale the light's mesh appropriately
  979. static float last_scale = 1.0F;
  980. m_pLightMesh->Scale (m_CameraDistance / (14 * last_scale));
  981. last_scale = m_CameraDistance / 14;
  982. }
  983. float max_dist = m_CameraDistance * 60.0F;
  984. float min_dist = max (0.2F, minZoomAdjust / 2);
  985. // Set the clipping planes so objects are clipped correctly
  986. if (doc->Are_Clip_Planes_Manual () == false) {
  987. m_pCamera->Set_Clip_Planes (min_dist, max_dist);
  988. // Adjust the fog near clipping plane to the new value, but
  989. // leave the far clip plane alone (since it is scene dependant
  990. // not camera dependant).
  991. float fog_near, fog_far;
  992. doc->GetScene()->Get_Fog_Range(&fog_near, &fog_far);
  993. doc->GetScene()->Set_Fog_Range(min_dist, fog_far);
  994. doc->GetScene()->Recalculate_Fog_Planes();
  995. }
  996. // Reset the background camera to match the main camera
  997. doc->GetBackObjectCamera ()->Set_Transform (transform);
  998. doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
  999. // Update the camera distance in the status bar
  1000. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  1001. if (pCMainWnd != NULL) {
  1002. pCMainWnd->UpdateCameraDistance (m_CameraDistance);
  1003. pCMainWnd->UpdateFrameCount (0, 0, 0);
  1004. }
  1005. // Record the sphere we are viewing for later
  1006. m_ViewedSphere = sphere;
  1007. return ;
  1008. }
  1009. ////////////////////////////////////////////////////////////////////////////
  1010. //
  1011. // Reset_Camera_To_Display_Object
  1012. //
  1013. ////////////////////////////////////////////////////////////////////////////
  1014. void
  1015. CGraphicView::Reset_Camera_To_Display_Object (RenderObjClass &render_object)
  1016. {
  1017. // Reset the camera to get a good look at this object's bounding sphere
  1018. SphereClass sp = render_object.Get_Bounding_Sphere ();
  1019. Reset_Camera_To_Display_Sphere (sp);
  1020. // Should we update the camera's position as well?
  1021. int index = render_object.Get_Bone_Index ("CAMERA");
  1022. if (index > 0) {
  1023. // Convert the bone's transform into a camera transform
  1024. Matrix3D transform = render_object.Get_Bone_Transform (index);
  1025. if (m_CameraBonePosX) {
  1026. Matrix3D tmp = transform;
  1027. Matrix3D cam_transform (Vector3 (0, -1, 0), Vector3 (0, 0, 1), Vector3 (-1, 0, 0), Vector3 (0, 0, 0));
  1028. transform = tmp * cam_transform;
  1029. }
  1030. // Pass the new transform onto the camera
  1031. CameraClass *camera = GetCamera ();
  1032. camera->Set_Transform (transform);
  1033. }
  1034. // Update the polygon count in the main window
  1035. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  1036. if (pCMainWnd != NULL) {
  1037. pCMainWnd->UpdatePolygonCount (render_object.Get_Num_Polys ());
  1038. }
  1039. // Load the settings in the default.dat if its in the local directory.
  1040. Load_Default_Dat ();
  1041. return ;
  1042. }
  1043. ////////////////////////////////////////////////////////////////////////////
  1044. //
  1045. // Load_Default_Dat
  1046. //
  1047. ////////////////////////////////////////////////////////////////////////////
  1048. void
  1049. CGraphicView::Load_Default_Dat (void)
  1050. {
  1051. // Get the directory where this executable was run from
  1052. TCHAR filename[MAX_PATH];
  1053. ::GetModuleFileName (NULL, filename, sizeof (filename));
  1054. // Strip the filename from the path
  1055. LPTSTR ppath = ::strrchr (filename, '\\');
  1056. if (ppath != NULL) {
  1057. ppath[0] = 0;
  1058. }
  1059. // Concat the default.dat filename onto the path
  1060. ::strcat (filename, "\\default.dat");
  1061. // Does the file exist in the directory?
  1062. if (::GetFileAttributes (filename) != 0xFFFFFFFF) {
  1063. // Ask the document to load the settings from this data file
  1064. CW3DViewDoc *pCDoc = (CW3DViewDoc *)GetDocument ();
  1065. if (pCDoc != NULL) {
  1066. pCDoc->LoadSettings (filename);
  1067. }
  1068. }
  1069. return ;
  1070. }
  1071. ////////////////////////////////////////////////////////////////////////////
  1072. //
  1073. // OnRButtonUp
  1074. //
  1075. ////////////////////////////////////////////////////////////////////////////
  1076. void
  1077. CGraphicView::OnRButtonUp
  1078. (
  1079. UINT nFlags,
  1080. CPoint point
  1081. )
  1082. {
  1083. // Mouse button is up
  1084. m_bRMouseDown = FALSE;
  1085. if (m_bMouseDown) {
  1086. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("orbit.tga");
  1087. } else {
  1088. ::SetCursor (::LoadCursor (NULL, MAKEINTRESOURCE (IDC_ARROW)));
  1089. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("cursor.tga");
  1090. ReleaseCapture ();
  1091. }
  1092. // Allow the base class to process this message
  1093. CView::OnRButtonUp(nFlags, point);
  1094. return ;
  1095. }
  1096. ////////////////////////////////////////////////////////////////////////////
  1097. //
  1098. // OnRButtonDown
  1099. //
  1100. ////////////////////////////////////////////////////////////////////////////
  1101. void
  1102. CGraphicView::OnRButtonDown
  1103. (
  1104. UINT nFlags,
  1105. CPoint point
  1106. )
  1107. {
  1108. // Capture all mouse messages
  1109. SetCapture ();
  1110. // Mouse button is down
  1111. m_bRMouseDown = TRUE;
  1112. m_lastPoint = point;
  1113. if (m_bMouseDown)
  1114. {
  1115. ::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_GRAB)));
  1116. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("grab.tga");
  1117. }
  1118. else
  1119. {
  1120. ::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_CURSOR_ZOOM)));
  1121. ((CW3DViewDoc *)GetDocument())->Set_Cursor ("zoom.tga");
  1122. }
  1123. // Allow the base class to process this message
  1124. CView::OnRButtonDown(nFlags, point);
  1125. return ;
  1126. }
  1127. ////////////////////////////////////////////////////////////////////////////
  1128. //
  1129. // SetAnimationState
  1130. //
  1131. ////////////////////////////////////////////////////////////////////////////
  1132. void
  1133. CGraphicView::SetAnimationState (ANIMATION_STATE animationState)
  1134. {
  1135. // Has the state changed?
  1136. if (m_animationState != animationState)
  1137. {
  1138. switch (animationState)
  1139. {
  1140. // We want to stop the animation
  1141. case AnimStopped:
  1142. {
  1143. // Get the document so we can get our current object
  1144. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  1145. ASSERT_VALID (doc);
  1146. // Get the currently displayed object
  1147. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  1148. if (pCRenderObj)
  1149. {
  1150. // Reset the animation to frame 0
  1151. if (doc->GetCurrentAnimation()) {
  1152. pCRenderObj->Set_Animation (doc->GetCurrentAnimation (), 0);
  1153. }
  1154. }
  1155. // Reset the animation to frame 0
  1156. doc->ResetAnimation ();
  1157. }
  1158. break;
  1159. case AnimPlaying:
  1160. {
  1161. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument ();
  1162. doc->Play_Animation_Sound ();
  1163. // Reset the frame timer
  1164. m_dwLastFrameUpdate = timeGetTime ();
  1165. }
  1166. break;
  1167. }
  1168. // Save the new state
  1169. m_animationState = animationState;
  1170. }
  1171. return ;
  1172. }
  1173. ////////////////////////////////////////////////////////////////////////////
  1174. //
  1175. // SetCameraPos
  1176. //
  1177. ////////////////////////////////////////////////////////////////////////////
  1178. void
  1179. CGraphicView::SetCameraPos (CAMERA_POS cameraPos)
  1180. {
  1181. // Get the document so we can get our current object
  1182. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  1183. ASSERT_VALID (doc);
  1184. // Get the currently displayed object
  1185. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  1186. if (pCRenderObj)
  1187. {
  1188. SphereClass sphere = m_ViewedSphere;
  1189. m_CameraDistance = sphere.Radius * 3.00F;
  1190. m_CameraDistance = (m_CameraDistance < 1.0F) ? 1.0F : m_CameraDistance;
  1191. m_CameraDistance = (m_CameraDistance > 400.0F) ? 400.0F : m_CameraDistance;
  1192. Matrix3D transform (1);
  1193. switch (cameraPos)
  1194. {
  1195. case CameraFront:
  1196. {
  1197. transform.Look_At (sphere.Center + Vector3 (m_CameraDistance, 0.00F, 0.00F), sphere.Center, 0);
  1198. }
  1199. break;
  1200. case CameraBack:
  1201. {
  1202. transform.Look_At (sphere.Center + Vector3 (-m_CameraDistance, 0.00F, 0.00F), sphere.Center, 0);
  1203. }
  1204. break;
  1205. case CameraLeft:
  1206. {
  1207. transform.Look_At (sphere.Center + Vector3 (0.00F, -m_CameraDistance, 0.00F), sphere.Center, 0);
  1208. }
  1209. break;
  1210. case CameraRight:
  1211. {
  1212. transform.Look_At (sphere.Center + Vector3 (0.00F, m_CameraDistance, 0.00F), sphere.Center, 0);
  1213. }
  1214. break;
  1215. case CameraTop:
  1216. {
  1217. transform.Look_At (sphere.Center + Vector3 (0.00F, 0.00F, m_CameraDistance), sphere.Center, 3.1415926535F);
  1218. }
  1219. break;
  1220. case CameraBottom:
  1221. {
  1222. transform.Look_At (sphere.Center + Vector3 (0.00F, 0.00F, -m_CameraDistance), sphere.Center, 3.1415926535F);
  1223. }
  1224. break;
  1225. }
  1226. // Move the camera back to get a good view of the object
  1227. m_pCamera->Set_Transform (transform);
  1228. // Get the main window of our app
  1229. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  1230. if (pCMainWnd != NULL)
  1231. {
  1232. CW3DViewDoc* doc = (CW3DViewDoc *)GetDocument();
  1233. doc->GetBackObjectCamera ()->Set_Transform (transform);
  1234. doc->GetBackObjectCamera ()->Set_Position (Vector3 (0.00F, 0.00F, 0.00F));
  1235. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  1236. if (pCRenderObj)
  1237. {
  1238. pCMainWnd->UpdatePolygonCount (pCRenderObj->Get_Num_Polys ());
  1239. }
  1240. pCMainWnd->UpdateCameraDistance(m_CameraDistance);
  1241. }
  1242. }
  1243. return ;
  1244. }
  1245. ////////////////////////////////////////////////////////////////////////////
  1246. //
  1247. // RotateObject
  1248. //
  1249. ////////////////////////////////////////////////////////////////////////////
  1250. void
  1251. CGraphicView::RotateObject (OBJECT_ROTATION rotation)
  1252. {
  1253. // Is this rotation different?
  1254. if (m_objectRotation != rotation)
  1255. {
  1256. // Save the rotation state
  1257. m_objectRotation = rotation;
  1258. }
  1259. return ;
  1260. }
  1261. ////////////////////////////////////////////////////////////////////////////
  1262. //
  1263. // SetAllowedCameraRotation
  1264. //
  1265. ////////////////////////////////////////////////////////////////////////////
  1266. void
  1267. CGraphicView::SetAllowedCameraRotation (CAMERA_ROTATION cameraRotation)
  1268. {
  1269. // Store this for later reference
  1270. m_allowedCameraRotation = cameraRotation;
  1271. return ;
  1272. }
  1273. ////////////////////////////////////////////////////////////////////////////
  1274. //
  1275. // ResetObject
  1276. //
  1277. ////////////////////////////////////////////////////////////////////////////
  1278. void
  1279. CGraphicView::ResetObject (void)
  1280. {
  1281. // Get the current document
  1282. CW3DViewDoc *doc = ::GetCurrentDocument ();
  1283. ASSERT (doc);
  1284. if (doc)
  1285. {
  1286. // Get the currently displayed object
  1287. RenderObjClass *pCRenderObj = doc->GetDisplayedObject ();
  1288. if (pCRenderObj)
  1289. {
  1290. // Reset the rotation of the object
  1291. pCRenderObj->Set_Transform (Matrix3D(1));
  1292. }
  1293. }
  1294. return ;
  1295. }
  1296. ////////////////////////////////////////////////////////////////////////////
  1297. //
  1298. // OnGetMinMaxInfo
  1299. //
  1300. ////////////////////////////////////////////////////////////////////////////
  1301. void
  1302. CGraphicView::OnGetMinMaxInfo (MINMAXINFO FAR* lpMMI)
  1303. {
  1304. CView::OnGetMinMaxInfo (lpMMI);
  1305. return ;
  1306. }
  1307. ////////////////////////////////////////////////////////////////////////////
  1308. //
  1309. // Rotate_Object
  1310. //
  1311. ////////////////////////////////////////////////////////////////////////////
  1312. void
  1313. CGraphicView::Rotate_Object (void)
  1314. {
  1315. // Get the document to display
  1316. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  1317. // Get the currently displayed object
  1318. RenderObjClass *prender_obj = doc->GetDisplayedObject ();
  1319. if (prender_obj != NULL)
  1320. {
  1321. // Get the current transform for the object
  1322. Matrix3D transform = prender_obj->Get_Transform ();
  1323. if ((m_objectRotation & RotateX) == RotateX) {
  1324. transform.Rotate_X (0.05F);
  1325. } else if ((m_objectRotation & RotateXBack) == RotateXBack) {
  1326. transform.Rotate_X (-0.05F);
  1327. }
  1328. if ((m_objectRotation & RotateY) == RotateY) {
  1329. transform.Rotate_Y (-0.05F);
  1330. } else if ((m_objectRotation & RotateYBack) == RotateYBack) {
  1331. transform.Rotate_Y (0.05F);
  1332. }
  1333. if ((m_objectRotation & RotateZ) == RotateZ) {
  1334. transform.Rotate_Z (0.05F);
  1335. } else if ((m_objectRotation & RotateZBack) == RotateZBack) {
  1336. transform.Rotate_Z (-0.05F);
  1337. }
  1338. if (!transform.Is_Orthogonal()) {
  1339. transform.Re_Orthogonalize();
  1340. }
  1341. // Set the new transform for the object
  1342. prender_obj->Set_Transform (transform);
  1343. }
  1344. return ;
  1345. }
  1346. ////////////////////////////////////////////////////////////////////////////
  1347. //
  1348. // Rotate_Light
  1349. //
  1350. ////////////////////////////////////////////////////////////////////////////
  1351. void
  1352. CGraphicView::Rotate_Light (void)
  1353. {
  1354. // Get the document to display
  1355. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  1356. // Get the currently displayed object
  1357. LightClass *pscene_light = doc->GetSceneLight ();
  1358. RenderObjClass *prender_obj = doc->GetDisplayedObject ();
  1359. if ((pscene_light != NULL) && (prender_obj != NULL)) {
  1360. Matrix3D rotation_matrix (1);
  1361. // Build a rotation matrix that contains the x,y,z
  1362. // rotations we want to apply to the light
  1363. if ((m_LightRotation & RotateX) == RotateX) {
  1364. rotation_matrix.Rotate_X (0.05F);
  1365. } else if ((m_LightRotation & RotateXBack) == RotateXBack) {
  1366. rotation_matrix.Rotate_X (-0.05F);
  1367. }
  1368. if ((m_LightRotation & RotateY) == RotateY) {
  1369. rotation_matrix.Rotate_Y (-0.05F);
  1370. } else if ((m_LightRotation & RotateYBack) == RotateYBack) {
  1371. rotation_matrix.Rotate_Y (0.05F);
  1372. }
  1373. if ((m_LightRotation & RotateZ) == RotateZ) {
  1374. rotation_matrix.Rotate_Z (0.05F);
  1375. } else if ((m_LightRotation & RotateZBack) == RotateZBack) {
  1376. rotation_matrix.Rotate_Z (-0.05F);
  1377. }
  1378. //
  1379. // Now, use the rotation matrix to rotate the
  1380. // light 'around' the displayed object (in its coordinate system)
  1381. //
  1382. Matrix3D coord_inv;
  1383. Matrix3D coord_to_obj;
  1384. Matrix3D coord_system = prender_obj->Get_Transform ();
  1385. coord_system.Get_Orthogonal_Inverse (coord_inv);
  1386. Matrix3D transform = pscene_light->Get_Transform ();
  1387. Matrix3D::Multiply (coord_inv, transform, &coord_to_obj);
  1388. Matrix3D::Multiply (coord_system, rotation_matrix, &transform);
  1389. Matrix3D::Multiply (transform, coord_to_obj, &transform);
  1390. // Ensure the matrix hasn't degenerated
  1391. if (!transform.Is_Orthogonal ()) {
  1392. transform.Re_Orthogonalize ();
  1393. }
  1394. // Pass the new transform onto the light
  1395. m_pLightMesh->Set_Transform (transform);
  1396. pscene_light->Set_Transform (transform);
  1397. }
  1398. return ;
  1399. }
  1400. ////////////////////////////////////////////////////////////////////////////
  1401. //
  1402. // Set_FOV
  1403. //
  1404. ////////////////////////////////////////////////////////////////////////////
  1405. void
  1406. CGraphicView::Set_FOV (double hfov, double vfov, bool force)
  1407. {
  1408. CW3DViewDoc *doc = (CW3DViewDoc *)GetDocument();
  1409. if (force || (doc->Is_FOV_Manual () == false)) {
  1410. m_pCamera->Set_View_Plane (hfov, vfov);
  1411. }
  1412. return ;
  1413. }
  1414. ////////////////////////////////////////////////////////////////////////////
  1415. //
  1416. // Reset_FOV
  1417. //
  1418. ////////////////////////////////////////////////////////////////////////////
  1419. void
  1420. CGraphicView::Reset_FOV (void)
  1421. {
  1422. int cx = 0;
  1423. int cy = 0;
  1424. if (m_iWindowed == 0) {
  1425. cx = g_iWidth;
  1426. cy = g_iHeight;
  1427. } else {
  1428. CRect rect;
  1429. GetClientRect (&rect);
  1430. cx = rect.Width ();
  1431. cy = rect.Height ();
  1432. }
  1433. // update the camera FOV settings
  1434. // take the larger of the two dimensions, give it the
  1435. // full desired FOV, then give the other dimension an
  1436. // FOV proportional to its relative size
  1437. double hfov,vfov;
  1438. if (cy > cx) {
  1439. vfov = (float)DEG_TO_RAD(45.0f);
  1440. hfov = (double)cx / (double)cy * vfov;
  1441. } else {
  1442. hfov = (float)DEG_TO_RAD(45.0f);
  1443. vfov = (double)cy / (double)cx * hfov;
  1444. }
  1445. // Reset the field of view
  1446. Set_FOV (hfov, vfov);
  1447. return ;
  1448. }
  1449. ////////////////////////////////////////////////////////////////////////////
  1450. //
  1451. // Set_Camera_Distance
  1452. //
  1453. ////////////////////////////////////////////////////////////////////////////
  1454. void
  1455. CGraphicView::Set_Camera_Distance (float dist)
  1456. {
  1457. m_CameraDistance = dist;
  1458. //
  1459. // Reposition the camera
  1460. //
  1461. Matrix3D new_tm(1);
  1462. new_tm.Look_At (m_ViewedSphere.Center + Vector3 (m_CameraDistance, 0.00F, 0.00F), m_ViewedSphere.Center, 0);
  1463. m_pCamera->Set_Transform (new_tm);
  1464. //
  1465. // Update the status bar
  1466. //
  1467. CMainFrame *main_wnd = (CMainFrame *)::AfxGetMainWnd ();
  1468. if (main_wnd != NULL) {
  1469. main_wnd->UpdateCameraDistance (m_CameraDistance);
  1470. }
  1471. return ;
  1472. }