Utils.cpp 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Utils.CPP
  21. //
  22. // Module containing usefull misc. utility functions
  23. //
  24. #include "StdAfx.H"
  25. #include "W3DViewDoc.H"
  26. #include "MainFrm.H"
  27. #include "DataTreeView.H"
  28. #include "Utils.H"
  29. #include "Texture.H"
  30. #include "AssetMgr.H"
  31. #include "Agg_Def.H"
  32. #include "HLod.H"
  33. #include <VFW.H>
  34. #include "RCFile.H"
  35. ////////////////////////////////////////////////////////////////////////////
  36. //
  37. // GetCurrentDocument
  38. //
  39. ////////////////////////////////////////////////////////////////////////////
  40. CW3DViewDoc *
  41. GetCurrentDocument (void)
  42. {
  43. // Assume failure
  44. CW3DViewDoc *pCDoc = NULL;
  45. // Get a pointer to the main window
  46. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  47. ASSERT (pCMainWnd);
  48. if (pCMainWnd)
  49. {
  50. // Use the main window pointer to get a pointer
  51. // to the current doc.
  52. pCDoc = (CW3DViewDoc *)pCMainWnd->GetActiveDocument ();
  53. ASSERT (pCDoc);
  54. }
  55. // Return the doc pointer
  56. return pCDoc;
  57. }
  58. /////////////////////////////////////////////////////////////
  59. //
  60. // CenterDialogAroundTreeView
  61. //
  62. void
  63. CenterDialogAroundTreeView (HWND hDlg)
  64. {
  65. // Params OK?
  66. if (::IsWindow (hDlg))
  67. {
  68. // Get a pointer to the main window
  69. CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
  70. ASSERT (pCMainWnd);
  71. if (pCMainWnd)
  72. {
  73. // Get the tree view pane so we can get its rectangle
  74. CDataTreeView *pCDataTreeView = (CDataTreeView *)pCMainWnd->GetPane (0, 0);
  75. ASSERT (pCDataTreeView);
  76. if (pCDataTreeView)
  77. {
  78. // Get the bounding rectangle of the data tree view
  79. RECT rect;
  80. pCDataTreeView->GetWindowRect (&rect);
  81. // Get the bounding rectangle of the dialog
  82. RECT dialogRect;
  83. ::GetWindowRect (hDlg, &dialogRect);
  84. // Move the dialog so its centered in the data tree view
  85. ::SetWindowPos (hDlg,
  86. NULL,
  87. rect.left + ((rect.right-rect.left) >> 1) - ((dialogRect.right-dialogRect.left) >> 1),
  88. rect.top + ((rect.bottom-rect.top) >> 1) - ((dialogRect.bottom-dialogRect.top) >> 1),
  89. 0,
  90. 0,
  91. SWP_NOSIZE | SWP_NOZORDER);
  92. }
  93. }
  94. }
  95. return ;
  96. }
  97. /////////////////////////////////////////////////////////////
  98. //
  99. // Paint_Gradient
  100. //
  101. void
  102. Paint_Gradient
  103. (
  104. HWND hWnd,
  105. BYTE baseRed,
  106. BYTE baseGreen,
  107. BYTE baseBlue
  108. )
  109. {
  110. // Get the bounding rectangle so we know how much to paint
  111. RECT rect;
  112. ::GetClientRect (hWnd, &rect);
  113. // Determine the width, height, and width per each shade
  114. int iWidth = rect.right-rect.left;
  115. int iHeight = rect.bottom-rect.top;
  116. float widthPerShade = ((float)iWidth) / 256.00F;
  117. // Pull a hack to get the CDC for the window
  118. HDC hDC = ::GetDC (hWnd);
  119. CDC cDC;
  120. cDC.Attach(hDC);
  121. // Loop through each shade and paint its sliver
  122. float posX = 0.00F;
  123. for (int iShade = 0; iShade < 256; iShade ++)
  124. {
  125. // Paint this sliver
  126. cDC.FillSolidRect ((int)posX,
  127. 0,
  128. (widthPerShade >= 1.00F) ? ((int)widthPerShade)+1 : 1,
  129. iHeight,
  130. RGB (iShade*baseRed, iShade*baseGreen, iShade*baseBlue));
  131. // Increment the current position
  132. posX += widthPerShade;
  133. }
  134. // Release the DC
  135. cDC.Detach ();
  136. ::ReleaseDC (hWnd, hDC);
  137. // Validate the contents of the window so the control won't paint itself
  138. ::ValidateRect (hWnd, NULL);
  139. return ;
  140. }
  141. ////////////////////////////////////////////////////////////////////////////
  142. //
  143. // SetDlgItemFloat
  144. //
  145. void
  146. SetDlgItemFloat
  147. (
  148. HWND hdlg,
  149. UINT child_id,
  150. float value
  151. )
  152. {
  153. // Convert the float to a string
  154. CString text;
  155. text.Format ("%.2f", value);
  156. // Pass the string onto the dialog control
  157. ::SetDlgItemText (hdlg, child_id, text);
  158. return ;
  159. }
  160. ////////////////////////////////////////////////////////////////////////////
  161. //
  162. // GetDlgItemFloat
  163. //
  164. float
  165. GetDlgItemFloat
  166. (
  167. HWND hdlg,
  168. UINT child_id
  169. )
  170. {
  171. // Get the string from the window
  172. TCHAR string_value[20];
  173. ::GetDlgItemText (hdlg, child_id, string_value, sizeof (string_value));
  174. // Convert the string to a float and return the value
  175. return ::atof (string_value);
  176. }
  177. ////////////////////////////////////////////////////////////////////////////
  178. //
  179. // Initialize_Spinner
  180. //
  181. void
  182. Initialize_Spinner
  183. (
  184. CSpinButtonCtrl &ctrl,
  185. float pos,
  186. float min,
  187. float max
  188. )
  189. {
  190. //
  191. // Convert the floats to ints and pass the settings onto the controls
  192. //
  193. ctrl.SetRange32 (int(min * 100), int(max * 100));
  194. ctrl.SetPos (int(pos * 100));
  195. //
  196. // Set the buddy's text accordingly
  197. //
  198. CWnd *buddy = ctrl.GetBuddy ();
  199. if (buddy != NULL) {
  200. ::SetWindowFloat (*buddy, pos);
  201. }
  202. return ;
  203. }
  204. ////////////////////////////////////////////////////////////////////////////
  205. //
  206. // Update_Spinner_Buddy
  207. //
  208. void
  209. Update_Spinner_Buddy (CSpinButtonCtrl &ctrl, int delta)
  210. {
  211. //
  212. // Only perform this service if the spinner isn't an auto buddy
  213. //
  214. if ((::GetWindowLong (ctrl, GWL_STYLE) & UDS_SETBUDDYINT) == 0) {
  215. CWnd *buddy = ctrl.GetBuddy ();
  216. if (buddy != NULL) {
  217. // Get the current value, increment it, and put it back into the control
  218. float value = ::GetWindowFloat (*buddy);
  219. value += (((float)(delta)) / 100.0F);
  220. //
  221. // Validate the new position
  222. //
  223. int int_min = 0;
  224. int int_max = 0;
  225. ctrl.GetRange32 (int_min, int_max);
  226. float float_min = ((float)int_min) / 100;
  227. float float_max = ((float)int_max) / 100;
  228. value = max (float_min, value);
  229. value = min (float_max, value);
  230. // Pass the value onto the buddy window
  231. ::SetWindowFloat (*buddy, value);
  232. }
  233. }
  234. return ;
  235. }
  236. ////////////////////////////////////////////////////////////////////////////
  237. //
  238. // Update_Spinner_Buddy
  239. //
  240. void
  241. Update_Spinner_Buddy (HWND hspinner, int delta)
  242. {
  243. //
  244. // Only perform this service if the spinner isn't an auto buddy
  245. //
  246. if ((::GetWindowLong (hspinner, GWL_STYLE) & UDS_SETBUDDYINT) == 0) {
  247. HWND hbuddy_wnd = (HWND)SendMessage (hspinner, UDM_GETBUDDY, 0, 0L);
  248. if (::IsWindow (hbuddy_wnd)) {
  249. // Get the current value, increment it, and put it back into the control
  250. float value = ::GetWindowFloat (hbuddy_wnd);
  251. value += (((float)(delta)) / 100.0F);
  252. //
  253. // Validate the new position
  254. //
  255. int int_min = 0;
  256. int int_max = 0;
  257. SendMessage (hspinner, UDM_GETRANGE32, (WPARAM)&int_min, (LPARAM)&int_max);
  258. float float_min = ((float)int_min) / 100;
  259. float float_max = ((float)int_max) / 100;
  260. value = max (float_min, value);
  261. value = min (float_max, value);
  262. // Pass the value onto the buddy window
  263. ::SetWindowFloat (hbuddy_wnd, value);
  264. }
  265. }
  266. return ;
  267. }
  268. ////////////////////////////////////////////////////////////////////////////
  269. //
  270. // Enable_Dialog_Controls
  271. //
  272. void
  273. Enable_Dialog_Controls (HWND dlg,bool onoff)
  274. {
  275. //
  276. // Loop over all sub-windows enable/disabling everything except for
  277. // the static text controls
  278. //
  279. for (HWND child = ::GetWindow(dlg,GW_CHILD) ; child != NULL ; child = ::GetWindow(child,GW_HWNDNEXT)) {
  280. char buf[64];
  281. ::GetClassName(child,buf,sizeof(buf));
  282. if (stricmp(buf,"STATIC") != 0) {
  283. ::EnableWindow(child,onoff);
  284. }
  285. }
  286. return ;
  287. }
  288. ////////////////////////////////////////////////////////////////////////////
  289. //
  290. // SetWindowFloat
  291. //
  292. void
  293. SetWindowFloat
  294. (
  295. HWND hwnd,
  296. float value
  297. )
  298. {
  299. // Convert the float to a string
  300. CString text;
  301. text.Format ("%.3f", value);
  302. // Pass the string onto the window
  303. ::SetWindowText (hwnd, text);
  304. return ;
  305. }
  306. ////////////////////////////////////////////////////////////////////////////
  307. //
  308. // GetWindowFloat
  309. //
  310. float
  311. GetWindowFloat (HWND hwnd)
  312. {
  313. // Get the string from the window
  314. TCHAR string_value[20];
  315. ::GetWindowText (hwnd, string_value, sizeof (string_value));
  316. // Convert the string to a float and return the value
  317. return ::atof (string_value);
  318. }
  319. ////////////////////////////////////////////////////////////////////////////
  320. //
  321. // Asset_Name_From_Filename
  322. //
  323. CString
  324. Asset_Name_From_Filename (LPCTSTR filename)
  325. {
  326. // Get the filename from this path
  327. CString asset_name = ::Get_Filename_From_Path (filename);
  328. // Find the index of the extension (if exists)
  329. int extension = asset_name.ReverseFind ('.');
  330. // Strip off the extension
  331. if (extension != -1) {
  332. asset_name = asset_name.Left (extension);
  333. }
  334. // Return the name of the asset
  335. return asset_name;
  336. }
  337. ////////////////////////////////////////////////////////////////////////////
  338. //
  339. // Filename_From_Asset_Name
  340. //
  341. CString
  342. Filename_From_Asset_Name (LPCTSTR asset_name)
  343. {
  344. // The filename is simply the asset name plus the .w3d extension
  345. CString filename = asset_name + CString (".w3d");
  346. // Return the filename
  347. return filename;
  348. }
  349. ////////////////////////////////////////////////////////////////////////////
  350. //
  351. // Get_Filename_From_Path
  352. //
  353. CString
  354. Get_Filename_From_Path (LPCTSTR path)
  355. {
  356. // Find the last occurance of the directory deliminator
  357. LPCTSTR filename = ::strrchr (path, '\\');
  358. if (filename != NULL) {
  359. // Increment past the directory deliminator
  360. filename ++;
  361. } else {
  362. filename = path;
  363. }
  364. // Return the filename part of the path
  365. return CString (filename);
  366. }
  367. ////////////////////////////////////////////////////////////////////////////
  368. //
  369. // Strip_Filename_From_Path
  370. //
  371. CString
  372. Strip_Filename_From_Path (LPCTSTR path)
  373. {
  374. // Copy the path to a buffer we can modify
  375. TCHAR temp_path[MAX_PATH];
  376. ::lstrcpy (temp_path, path);
  377. // Find the last occurance of the directory deliminator
  378. LPTSTR filename = ::strrchr (temp_path, '\\');
  379. if (filename != NULL) {
  380. // Strip off the filename
  381. filename[0] = 0;
  382. }
  383. // Return the path only
  384. return CString (temp_path);
  385. }
  386. ////////////////////////////////////////////////////////////////////////////
  387. //
  388. // Create_DIB_Section
  389. //
  390. HBITMAP
  391. Create_DIB_Section
  392. (
  393. UCHAR **pbits,
  394. int width,
  395. int height
  396. )
  397. {
  398. // Set-up the fields of the BITMAPINFOHEADER
  399. BITMAPINFOHEADER bitmap_info;
  400. bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
  401. bitmap_info.biWidth = width;
  402. bitmap_info.biHeight = -height; // Top-down DIB uses negative height
  403. bitmap_info.biPlanes = 1;
  404. bitmap_info.biBitCount = 24;
  405. bitmap_info.biCompression = BI_RGB;
  406. bitmap_info.biSizeImage = ((width * height) * 3);
  407. bitmap_info.biXPelsPerMeter = 0;
  408. bitmap_info.biYPelsPerMeter = 0;
  409. bitmap_info.biClrUsed = 0;
  410. bitmap_info.biClrImportant = 0;
  411. // Get a temporary screen DC
  412. HDC hscreen_dc = ::GetDC (NULL);
  413. // Create a bitmap that we can access the bits directly of
  414. HBITMAP hbitmap = ::CreateDIBSection (hscreen_dc,
  415. (const BITMAPINFO *)&bitmap_info,
  416. DIB_RGB_COLORS,
  417. (void **)pbits,
  418. NULL,
  419. 0L);
  420. // Release our temporary screen DC
  421. ::ReleaseDC (NULL, hscreen_dc);
  422. return hbitmap;
  423. }
  424. ////////////////////////////////////////////////////////////////////////////
  425. //
  426. // Make_Bitmap_From_Texture
  427. //
  428. HBITMAP
  429. Make_Bitmap_From_Texture (TextureClass &texture, int width, int height)
  430. {
  431. HBITMAP hbitmap = NULL;
  432. #ifdef WW3D_DX8
  433. srColorSurfaceIFace *surface = NULL;
  434. // What type of texture is this?
  435. switch (texture.getClassID ())
  436. {
  437. case srClass::ID_TEXTURE_FILE:
  438. {
  439. // Hopefully get the image data
  440. srTextureIFace::MultiRequest info = { 0 };
  441. info.levels[0] = new srColorSurface (srColorSurface::ARGB0444, width, height);
  442. texture.getMipmapData (info);
  443. surface = info.levels[0];
  444. }
  445. break;
  446. case ID_MANUAL_ANIM_TEXTURE_INSTANCE_CLASS:
  447. case ID_TIME_ANIM_TEXTURE_INSTANCE_CLASS:
  448. case ID_RESIZEABLE_TEXTURE_INSTANCE_CLASS:
  449. {
  450. VariableTextureClass *psource = ((ResizeableTextureInstanceClass &)texture).Peek_Source();
  451. if (psource != NULL) {
  452. // Hopefully get the image data
  453. srTextureIFace::MultiRequest info = { 0 };
  454. info.levels[0] = new srColorSurface (srColorSurface::ARGB0444, width, height);
  455. psource->Get_Mipmap_Data (0, info);
  456. surface = info.levels[0];
  457. }
  458. }
  459. break;
  460. case ID_INDIRECT_TEXTURE_CLASS:
  461. {
  462. srTextureIFace *preal_texture = ((IndirectTextureClass &)texture).Get_Texture ();
  463. hbitmap = ::Make_Bitmap_From_Texture (*preal_texture, width, height);
  464. SR_RELEASE (preal_texture);
  465. }
  466. break;
  467. // Unknown texture type
  468. default:
  469. ASSERT (0);
  470. break;
  471. }
  472. if (surface != NULL) {
  473. int src_width = surface->getWidth ();
  474. int src_height = surface->getHeight ();
  475. // Create a DIB section for fast 'blitting'
  476. UCHAR *pbits = NULL;
  477. hbitmap = ::Create_DIB_Section (&pbits, width, height);
  478. ASSERT (hbitmap != NULL);
  479. ASSERT (pbits != NULL);
  480. if (pbits != NULL) {
  481. float src_bits_per_pixel = (float)src_width / (float)width;
  482. float src_bits_per_scanline = (float)src_height / (float)height;
  483. float curr_src_pixel = 0;
  484. float curr_src_row = 0;
  485. // Window's bitmaps are DWORD aligned, so make sure
  486. // we take that into account.
  487. int alignment_offset = (width * 3) % 4;
  488. alignment_offset = (alignment_offset != 0) ? (4 - alignment_offset) : 0;
  489. // Copy the bits into the windows DIB section
  490. int index = 0;
  491. for (int y = 0; y < height; y ++) {
  492. for (int x = 0; x < width; x ++) {
  493. // Grab the pixel from the source buffer and stuff it into the dest
  494. srARGB pixel = surface->getPixel (curr_src_pixel, curr_src_row);
  495. pbits[index++] = pixel[srARGB::B];
  496. pbits[index++] = pixel[srARGB::G];
  497. pbits[index++] = pixel[srARGB::R];
  498. // Increment our source counter (the src size and dest don't have to match)
  499. curr_src_pixel += src_bits_per_pixel;
  500. }
  501. // Reset our src-to-dest conversion data
  502. curr_src_pixel = 0;
  503. curr_src_row += src_bits_per_scanline;
  504. // Skip past the padded bytes
  505. index += alignment_offset;
  506. }
  507. }
  508. surface->release ();
  509. }
  510. #endif
  511. // Return a handle to the bitmap
  512. return hbitmap;
  513. }
  514. ////////////////////////////////////////////////////////////////////////////
  515. //
  516. // Get_Texture_Name
  517. //
  518. CString
  519. Get_Texture_Name (TextureClass &texture)
  520. {
  521. CString name;
  522. // What type of texture is this?
  523. #ifdef WW3D_DX8
  524. switch (texture.getClassID ())
  525. {
  526. case srClass::ID_TEXTURE_FILE:
  527. name = texture.getName ();
  528. break;
  529. case ID_MANUAL_ANIM_TEXTURE_INSTANCE_CLASS:
  530. case ID_TIME_ANIM_TEXTURE_INSTANCE_CLASS:
  531. case ID_RESIZEABLE_TEXTURE_INSTANCE_CLASS:
  532. {
  533. VariableTextureClass *psource = ((ResizeableTextureInstanceClass &)texture).Peek_Source();
  534. if (psource != NULL) {
  535. name = psource->getName ();
  536. }
  537. }
  538. break;
  539. case ID_INDIRECT_TEXTURE_CLASS:
  540. {
  541. srTextureIFace *preal_texture = ((IndirectTextureClass &)texture).Get_Texture ();
  542. if (preal_texture != NULL) {
  543. name = ::Get_Texture_Name (*preal_texture);
  544. SR_RELEASE (preal_texture);
  545. }
  546. }
  547. break;
  548. // Unknown texture type
  549. default:
  550. ASSERT (0);
  551. break;
  552. }
  553. #else
  554. name = texture.Get_Texture_Name();
  555. #endif
  556. // Return the texture's name
  557. return name;
  558. }
  559. ////////////////////////////////////////////////////////////////////////////
  560. //
  561. // Build_Emitter_List
  562. //
  563. void
  564. Build_Emitter_List
  565. (
  566. RenderObjClass &render_obj,
  567. DynamicVectorClass<CString> &list
  568. )
  569. {
  570. // Loop through all this render obj's sub-obj's
  571. for (int index = 0; index < render_obj.Get_Num_Sub_Objects (); index ++) {
  572. RenderObjClass *psub_obj = render_obj.Get_Sub_Object (index);
  573. if (psub_obj != NULL) {
  574. // Is this sub-obj an emitter?
  575. if (psub_obj->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
  576. // Is this emitter already in the list?
  577. bool found = false;
  578. for (int list_index = 0; (list_index < list.Count ()) && !found; list_index++) {
  579. if (::lstrcmpi (list[list_index], psub_obj->Get_Name ()) == 0) {
  580. found = true;
  581. }
  582. }
  583. // Add this emitter to the list if necessary
  584. if (!found) {
  585. list.Add (psub_obj->Get_Name ());
  586. }
  587. }
  588. // Recursivly add emitters to the list
  589. Build_Emitter_List (*psub_obj, list);
  590. MEMBER_RELEASE (psub_obj);
  591. }
  592. }
  593. return ;
  594. }
  595. ////////////////////////////////////////////////////////////////////////////
  596. //
  597. // Is_Aggregate
  598. //
  599. bool
  600. Is_Aggregate (const char *asset_name)
  601. {
  602. // Assume that the asset isn't an aggregate
  603. bool retval = false;
  604. // Check to see if this object is an aggregate
  605. RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (asset_name);
  606. if ((prender_obj != NULL) &&
  607. (prender_obj->Get_Base_Model_Name () != NULL))
  608. {
  609. retval = true;
  610. }
  611. // Free our hold on the temporary render object
  612. MEMBER_RELEASE (prender_obj);
  613. // Return the true/false result code
  614. return retval;
  615. }
  616. ////////////////////////////////////////////////////////////////////////////
  617. //
  618. // Rename_Aggregate_Prototype
  619. //
  620. void
  621. Rename_Aggregate_Prototype
  622. (
  623. const char *old_name,
  624. const char *new_name
  625. )
  626. {
  627. // Params valid?
  628. if ((old_name != NULL) &&
  629. (new_name != NULL) &&
  630. (::lstrcmpi (old_name, new_name) != 0)) {
  631. // Get the prototype from the asset manager
  632. AggregatePrototypeClass *proto = NULL;
  633. proto = (AggregatePrototypeClass *)WW3DAssetManager::Get_Instance ()->Find_Prototype (old_name);
  634. if (proto != NULL) {
  635. // Copy the definition from the prototype and remove the prototype
  636. AggregateDefClass *pdefinition = proto->Get_Definition ();
  637. AggregateDefClass *pnew_definition = pdefinition->Clone ();
  638. WW3DAssetManager::Get_Instance ()->Remove_Prototype (old_name);
  639. // Rename the definition, create a new prototype, and add it to the asset manager
  640. pnew_definition->Set_Name (new_name);
  641. proto = new AggregatePrototypeClass (pnew_definition);
  642. WW3DAssetManager::Get_Instance ()->Add_Prototype (proto);
  643. }
  644. }
  645. return ;
  646. }
  647. ////////////////////////////////////////////////////////////////////////////
  648. //
  649. // Is_Real_LOD
  650. //
  651. bool
  652. Is_Real_LOD (const char *asset_name)
  653. {
  654. // Assume that the asset isn't a true LOD (HLOD w/ more than one
  655. bool retval = false;
  656. // Check to see if this object is an aggregate
  657. RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (asset_name);
  658. if ((prender_obj != NULL) &&
  659. (prender_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) &&
  660. (((HLodClass *)prender_obj)->Get_LOD_Count () > 1)) {
  661. retval = true;
  662. }
  663. // Free our hold on the temporary render object
  664. MEMBER_RELEASE (prender_obj);
  665. // Return the true/false result code
  666. return retval;
  667. }
  668. ////////////////////////////////////////////////////////////////////////////
  669. //
  670. // Get_File_Time
  671. //
  672. bool
  673. Get_File_Time
  674. (
  675. LPCTSTR path,
  676. LPFILETIME pcreation_time,
  677. LPFILETIME paccess_time,
  678. LPFILETIME pwrite_time
  679. )
  680. {
  681. // Assume failure
  682. bool retval = false;
  683. // Attempt to open the file
  684. HANDLE hfile = ::CreateFile (path,
  685. 0,
  686. 0,
  687. NULL,
  688. OPEN_EXISTING,
  689. 0L,
  690. NULL);
  691. ASSERT (hfile != INVALID_HANDLE_VALUE);
  692. if (hfile != INVALID_HANDLE_VALUE) {
  693. // Get the mod times for this file
  694. retval = (::GetFileTime (hfile, pcreation_time, paccess_time, pwrite_time) == TRUE);
  695. // Close the file
  696. SAFE_CLOSE (hfile);
  697. }
  698. // Return the true/false result code
  699. return retval;
  700. }
  701. ////////////////////////////////////////////////////////////////////////////
  702. //
  703. // Are_Glide_Drivers_Acceptable
  704. //
  705. bool
  706. Are_Glide_Drivers_Acceptable (void)
  707. {
  708. // Assume success
  709. bool retval = true;
  710. // Is this windows NT?
  711. OSVERSIONINFO version = { sizeof (OSVERSIONINFO), 0 };
  712. if (::GetVersionEx (&version) && (version.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
  713. // Now assume failure
  714. retval = false;
  715. // Get a path to the system directory
  716. TCHAR path[MAX_PATH];
  717. ::GetSystemDirectory (path, sizeof (path));
  718. ::Delimit_Path (path);
  719. // Build the full path of the 2 main drivers
  720. CString glide2x = CString (path) + "glide2x.dll";
  721. CString glide3x = CString (path) + "glide3x.dll";
  722. // Get the creation time of the glide2x driver
  723. FILETIME file_time = { 0 };
  724. if (::Get_File_Time (glide2x, NULL, NULL, &file_time)) {
  725. CTime time_obj (file_time);
  726. retval = ((time_obj.GetYear () == 1998) && (time_obj.GetMonth () == 12)) || (time_obj.GetYear () > 1998);
  727. }
  728. // Get the creation time of the glide3x driver
  729. if (::Get_File_Time (glide3x, NULL, NULL, &file_time)) {
  730. CTime time_obj (file_time);
  731. retval = ((time_obj.GetYear () == 1998) && (time_obj.GetMonth () == 12)) || (time_obj.GetYear () > 1998);
  732. }
  733. }
  734. // Return the true/false result code
  735. return retval;
  736. }
  737. ////////////////////////////////////////////////////////////////////////////
  738. //
  739. // Load_RC_Texture
  740. //
  741. TextureClass *
  742. Load_RC_Texture (LPCTSTR resource_name)
  743. {
  744. TextureClass *texture = NULL;
  745. //
  746. // Load the cursor file image from this binaries resources
  747. //
  748. ResourceFileClass resource_file (::AfxGetResourceHandle (), resource_name);
  749. unsigned char *res_data = resource_file.Peek_Data ();
  750. unsigned int data_size = resource_file.Size ();
  751. //
  752. // Create a texture from the raw image data
  753. //
  754. #ifdef WW3D_DX8
  755. srBinIMStream stream (res_data, data_size);
  756. srSurfaceIOManager::SurfaceImporter *importer = srCore.getSurfaceIOManager()->getImporter (".tga");
  757. if (importer != NULL) {
  758. srColorSurfaceIFace *surface = importer->importSurface (stream, srSurfaceIOManager::ImportInfo());
  759. if (surface != NULL) {
  760. texture = new srTextureMap (surface);
  761. }
  762. }
  763. #endif
  764. // Reutrn a pointer to the new texture
  765. return texture;
  766. }
  767. ////////////////////////////////////////////////////////////////////////////
  768. //
  769. // Resolve_Path
  770. //
  771. ////////////////////////////////////////////////////////////////////////////
  772. void
  773. Resolve_Path (CString &filename)
  774. {
  775. if (filename.Find ('\\') == -1) {
  776. char path[MAX_PATH];
  777. ::GetCurrentDirectory (MAX_PATH, path);
  778. ::Delimit_Path (path);
  779. filename = CString (path) + filename;
  780. }
  781. return ;
  782. }
  783. ////////////////////////////////////////////////////////////////////////////
  784. //
  785. // Find_Missing_Textures
  786. //
  787. ////////////////////////////////////////////////////////////////////////////
  788. void
  789. Find_Missing_Textures
  790. (
  791. DynamicVectorClass<CString> & list,
  792. LPCTSTR name,
  793. int frame_count
  794. )
  795. {
  796. //
  797. // If this file doesn't exist, then add it to our list
  798. //
  799. if (::GetFileAttributes (name) == 0xFFFFFFFF) {
  800. CString full_path = name;
  801. Resolve_Path (full_path);
  802. list.Add (full_path);
  803. }
  804. return ;
  805. }
  806. ////////////////////////////////////////////////////////////////////////////
  807. //
  808. // Copy_File
  809. //
  810. ////////////////////////////////////////////////////////////////////////////
  811. bool
  812. Copy_File
  813. (
  814. LPCTSTR existing_filename,
  815. LPCTSTR new_filename,
  816. bool force_copy
  817. )
  818. {
  819. SANITY_CHECK ((existing_filename != NULL && new_filename != NULL)) {
  820. return false;
  821. }
  822. // Assume failure
  823. bool retval = false;
  824. // Make sure we aren't copying over ourselves
  825. bool allow_copy = (::lstrcmpi (existing_filename, new_filename) != 0);
  826. // Strip the readonly bit off if necessary
  827. DWORD attributes = ::GetFileAttributes (new_filename);
  828. if (allow_copy &&
  829. (attributes != 0xFFFFFFFF) &&
  830. ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
  831. {
  832. if (force_copy) {
  833. ::SetFileAttributes (new_filename, attributes & (~FILE_ATTRIBUTE_READONLY));
  834. } else {
  835. allow_copy = false;
  836. }
  837. }
  838. // Perform the copy operation!
  839. if (allow_copy) {
  840. retval = (::CopyFile (existing_filename, new_filename, FALSE) == TRUE);
  841. }
  842. // Return the true/false result code
  843. return retval;
  844. }
  845. ////////////////////////////////////////////////////////////////////////////
  846. //
  847. // Get_Graphic_View
  848. //
  849. ////////////////////////////////////////////////////////////////////////////
  850. CGraphicView *
  851. Get_Graphic_View (void)
  852. {
  853. CGraphicView *view = NULL;
  854. //
  855. // Get the view from the current document
  856. //
  857. CW3DViewDoc *doc = GetCurrentDocument ();
  858. if (doc != NULL) {
  859. view = doc->GetGraphicView ();
  860. }
  861. return view;
  862. }