VideoConfigDialog.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. // VideoConfigDialog.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "wwconfig.h"
  22. #include "videoconfigdialog.h"
  23. #include "ww3d.h"
  24. #include "assetmgr.h"
  25. #include "locale_api.h"
  26. #include "wwconfig_ids.h"
  27. #include "assetstatus.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. static VideoConfigDialogClass* VideoConfigDialogInstance;
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Globals
  36. /////////////////////////////////////////////////////////////////////////////
  37. WW3DAssetManager *_TheAssetMgr = NULL;;
  38. /////////////////////////////////////////////////////////////////////////////
  39. // Local prototypes
  40. /////////////////////////////////////////////////////////////////////////////
  41. int _cdecl ResolutionSortCallback (const void *elem1, const void *elem2);
  42. /////////////////////////////////////////////////////////////////////////////
  43. // Constants
  44. /////////////////////////////////////////////////////////////////////////////
  45. enum
  46. {
  47. COL_DEVICE_NAME = 0
  48. };
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // VideoConfigDialogClass
  52. //
  53. /////////////////////////////////////////////////////////////////////////////
  54. VideoConfigDialogClass::VideoConfigDialogClass (CWnd *pParent)
  55. : CurrentBitDepth (16),
  56. CurrentWidth (800),
  57. CurrentHeight (600),
  58. CurrentDriverIndex (0),
  59. CurrentIsWindowed (false),
  60. CDialog(VideoConfigDialogClass::IDD, pParent)
  61. {
  62. //{{AFX_DATA_INIT(VideoConfigDialogClass)
  63. // NOTE: the ClassWizard will add member initialization here
  64. //}}AFX_DATA_INIT
  65. WWASSERT(!VideoConfigDialogInstance); // Only one can exist at a time!
  66. VideoConfigDialogInstance=this;
  67. CDialog::Create (VideoConfigDialogClass::IDD, pParent);
  68. return ;
  69. }
  70. VideoConfigDialogClass::~VideoConfigDialogClass ()
  71. {
  72. VideoConfigDialogInstance=NULL;
  73. }
  74. VideoConfigDialogClass* VideoConfigDialogClass::Get_Instance ()
  75. {
  76. return VideoConfigDialogInstance;
  77. }
  78. /////////////////////////////////////////////////////////////////////////////
  79. //
  80. // DoDataExchange
  81. //
  82. /////////////////////////////////////////////////////////////////////////////
  83. void
  84. VideoConfigDialogClass::DoDataExchange (CDataExchange *pDX)
  85. {
  86. CDialog::DoDataExchange(pDX);
  87. //{{AFX_DATA_MAP(VideoConfigDialogClass)
  88. DDX_Control(pDX, IDC_RESOLUTION_SLIDER, m_ResSliderCtrl);
  89. DDX_Control(pDX, IDC_DRIVER_LIST, m_DriverListCtrl);
  90. //}}AFX_DATA_MAP
  91. return ;
  92. }
  93. BEGIN_MESSAGE_MAP(VideoConfigDialogClass, CDialog)
  94. //{{AFX_MSG_MAP(VideoConfigDialogClass)
  95. ON_WM_DESTROY()
  96. ON_NOTIFY(LVN_ITEMCHANGED, IDC_DRIVER_LIST, OnItemchangedDriverList)
  97. ON_CBN_SELCHANGE(IDC_BITDEPTH_COMBO, OnSelchangeBitdepthCombo)
  98. ON_WM_HSCROLL()
  99. ON_BN_CLICKED(IDC_WINDOWED_CHECK, OnWindowedCheck)
  100. //}}AFX_MSG_MAP
  101. END_MESSAGE_MAP()
  102. /////////////////////////////////////////////////////////////////////////////
  103. //
  104. // OnInitDialog
  105. //
  106. // Modified: 12/06/2001 by MML - Retrieving strings from Locomoto file.
  107. /////////////////////////////////////////////////////////////////////////////
  108. BOOL
  109. VideoConfigDialogClass::OnInitDialog (void)
  110. {
  111. char string [_MAX_PATH];
  112. CDialog::OnInitDialog ();
  113. //
  114. // Set all the static strings for this dialog.
  115. //
  116. Locale_GetString( IDS_DRIVER, string );
  117. SetDlgItemText( IDC_DRIVER, string );
  118. Locale_GetString( IDS_DISPLAY, string );
  119. SetDlgItemText( IDC_STATIC2, string );
  120. Locale_GetString( IDS_RESOLUTION, string );
  121. SetDlgItemText( IDC_RESOLUTION, string );
  122. Locale_GetString( IDS_COLOR_DEPTH, string );
  123. SetDlgItemText( IDC_BIT_DEPTH, string );
  124. Locale_GetString( IDS_WINDOWED_MODE, string );
  125. SetDlgItemText( IDC_WINDOWED_CHECK, string );
  126. //
  127. // Initialize the engine
  128. //
  129. _TheAssetMgr = new WW3DAssetManager;
  130. WW3D::Init (m_hWnd);
  131. AssetStatusClass::Peek_Instance()->Enable_Reporting (false);
  132. //
  133. // Load the render device settings from the registry
  134. //
  135. char device_name[256] = { 0 };
  136. int texture_depth = 0;
  137. int width = 0;
  138. int height = 0;
  139. int bit_depth = 0;
  140. int windowed = 0;
  141. if (WW3D::Registry_Load_Render_Device (RENEGADE_SUB_KEY_NAME_RENDER, device_name, 256,
  142. width, height, bit_depth, windowed, texture_depth))
  143. {
  144. if (width != -1) {
  145. CurrentWidth = width;
  146. }
  147. if (height != -1) {
  148. CurrentHeight = height;
  149. }
  150. if (bit_depth != -1) {
  151. CurrentBitDepth = bit_depth;
  152. }
  153. if (windowed != -1) {
  154. CurrentIsWindowed = bool(windowed == 1);
  155. }
  156. }
  157. //
  158. // Set the extended styles for the list control
  159. //
  160. m_DriverListCtrl.SetExtendedStyle (m_DriverListCtrl.GetExtendedStyle () | LVS_EX_FULLROWSELECT);
  161. //
  162. // Configure the columns
  163. //
  164. m_DriverListCtrl.InsertColumn (COL_DEVICE_NAME, "Device Name");
  165. //
  166. // Populate the render device list control
  167. //
  168. bool found_default_entry = false;
  169. int driver_count = WW3D::Get_Render_Device_Count ();
  170. for (int index = 0; index < driver_count; index ++) {
  171. const RenderDeviceDescClass &device_desc = WW3D::Get_Render_Device_Desc (index);
  172. //
  173. // Build a human readable name for this driver
  174. //
  175. CString driver_name;
  176. driver_name.Format ("%s - %s", device_desc.Get_Device_Name (), device_desc.Get_Hardware_Name ());
  177. //
  178. // Add this driver to the list control
  179. //
  180. int item_index = m_DriverListCtrl.InsertItem (0xFF, driver_name);
  181. if (item_index >= 0) {
  182. m_DriverListCtrl.SetItemData (item_index, index);
  183. }
  184. //
  185. // Check to see if this is the default entry
  186. //
  187. const char *render_device_name = WW3D::Get_Render_Device_Name (index);
  188. if (::lstrcmpi (device_name, render_device_name) == 0) {
  189. m_DriverListCtrl.SetItemState (item_index, LVIS_SELECTED, LVIS_SELECTED);
  190. found_default_entry = true;
  191. }
  192. }
  193. //
  194. // Set the "windowed mode" checkbox
  195. //
  196. SendDlgItemMessage (IDC_WINDOWED_CHECK, BM_SETCHECK, (WPARAM)CurrentIsWindowed);
  197. //
  198. // Select the first entry for deafult (if necessary)
  199. //
  200. if (found_default_entry == false) {
  201. m_DriverListCtrl.SetItemState (0, LVIS_SELECTED, LVIS_SELECTED);
  202. }
  203. //
  204. // Size the columns
  205. //
  206. CRect rect;
  207. m_DriverListCtrl.GetClientRect (&rect);
  208. int col_width = rect.Width () - ::GetSystemMetrics (SM_CXVSCROLL);
  209. m_DriverListCtrl.SetColumnWidth (0, col_width);
  210. //
  211. // Build the resolution list for the currently selected device
  212. //
  213. Update_Display_Settings ();
  214. return TRUE;
  215. }
  216. /////////////////////////////////////////////////////////////////////////////
  217. //
  218. // OnDestroy
  219. //
  220. /////////////////////////////////////////////////////////////////////////////
  221. void
  222. VideoConfigDialogClass::OnDestroy (void)
  223. {
  224. //
  225. // Shutdown the engine
  226. //
  227. WW3D::Shutdown ();
  228. delete _TheAssetMgr;
  229. _TheAssetMgr = NULL;
  230. CDialog::OnDestroy ();
  231. return ;
  232. }
  233. /////////////////////////////////////////////////////////////////////////////
  234. //
  235. // Update_Display_Settings
  236. //
  237. /////////////////////////////////////////////////////////////////////////////
  238. void
  239. VideoConfigDialogClass::Update_Display_Settings (void)
  240. {
  241. //
  242. // Get the selected device
  243. //
  244. int selected_index = m_DriverListCtrl.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED);
  245. if (selected_index < 0) {
  246. return ;
  247. }
  248. //
  249. // Lookup the device description for the selected device
  250. //
  251. CurrentDriverIndex = (int)m_DriverListCtrl.GetItemData (selected_index);
  252. const RenderDeviceDescClass &driver_info = WW3D::Get_Render_Device_Desc (CurrentDriverIndex);
  253. ResolutionList = driver_info.Enumerate_Resolutions ();
  254. CurrentCaps=driver_info.Get_Caps();
  255. CurrentAdapterIdentifier=driver_info.Get_Adapter_Identifier();
  256. //
  257. // Update the dialog controls
  258. //
  259. Update_Color_Combo ();
  260. Update_Resolution_Slider ();
  261. Select_Default_Resolution ();
  262. return ;
  263. }
  264. /////////////////////////////////////////////////////////////////////////////
  265. //
  266. // Update_Resolution_Slider
  267. //
  268. /////////////////////////////////////////////////////////////////////////////
  269. void
  270. VideoConfigDialogClass::Update_Resolution_Slider (void)
  271. {
  272. //
  273. // Lookup the device description for the selected device
  274. //
  275. const RenderDeviceDescClass &driver_info = WW3D::Get_Render_Device_Desc (CurrentDriverIndex);
  276. ResolutionList = driver_info.Enumerate_Resolutions ();
  277. //
  278. // Filter out any resolutions that don't fit the current
  279. // bit depth
  280. //
  281. for (int index = 0; index < ResolutionList.Count (); index ++) {
  282. const ResolutionDescClass &res_desc = ResolutionList[index];
  283. //
  284. // Remove this resolution if it doesn't fit the current
  285. // bit depth
  286. //
  287. if (res_desc.BitDepth != CurrentBitDepth || res_desc.Width < 640 || res_desc.Height < 480) {
  288. ResolutionList.Delete (index);
  289. index --;
  290. }
  291. }
  292. //
  293. // Sort the entries
  294. //
  295. if (ResolutionList.Count () > 0) {
  296. ::qsort (&ResolutionList[0], ResolutionList.Count (), sizeof (ResolutionList[0]), ResolutionSortCallback);
  297. }
  298. //
  299. // Configure the slider control
  300. //
  301. m_ResSliderCtrl.ClearTics ();
  302. m_ResSliderCtrl.SetRange (0, ResolutionList.Count () - 1);
  303. //
  304. // Setup the tick marks
  305. //
  306. for (index = 0; index < ResolutionList.Count (); index ++) {
  307. m_ResSliderCtrl.SetTic (index);
  308. }
  309. return ;
  310. }
  311. /////////////////////////////////////////////////////////////////////////////
  312. //
  313. // Update_Color_Combo
  314. //
  315. /////////////////////////////////////////////////////////////////////////////
  316. void
  317. VideoConfigDialogClass::Update_Color_Combo (void)
  318. {
  319. //
  320. // Start fresh
  321. //
  322. SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_RESETCONTENT);
  323. //
  324. // Loop over all the resolutions and add the different
  325. // bit-depths to the combo box
  326. //
  327. bool selected = false;
  328. for (int index = 0; index < ResolutionList.Count (); index ++) {
  329. const ResolutionDescClass &res_desc = ResolutionList[index];
  330. char string [_MAX_PATH];
  331. CString color_string;
  332. //
  333. // Make a display string out of the bit depth
  334. //
  335. Locale_GetString (IDS_BIT, string);
  336. color_string.Format ("%d %s", res_desc.BitDepth, string);
  337. //
  338. // Check to see if this string is already in the combobox
  339. //
  340. int item_index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_FINDSTRINGEXACT, 0, (LPARAM)(LPCTSTR)color_string);
  341. if (item_index == CB_ERR) {
  342. //
  343. // Add this entry to the combobox
  344. //
  345. int item_index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)color_string);
  346. if (item_index != CB_ERR) {
  347. SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETITEMDATA, (WPARAM)item_index, (LPARAM)res_desc.BitDepth);
  348. //
  349. // Select this entry if its the current bit depth
  350. //
  351. if (res_desc.BitDepth == CurrentBitDepth) {
  352. SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETCURSEL, (WPARAM)item_index);
  353. selected = true;
  354. }
  355. }
  356. }
  357. }
  358. //
  359. // Select the first entry by default
  360. //
  361. if (!selected) {
  362. SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETCURSEL, 0);
  363. CurrentBitDepth = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETITEMDATA, 0);
  364. if (CurrentBitDepth <= 0) {
  365. CurrentBitDepth = 16;
  366. }
  367. }
  368. return ;
  369. }
  370. /////////////////////////////////////////////////////////////////////////////
  371. //
  372. // Select_Default_Resolution
  373. //
  374. /////////////////////////////////////////////////////////////////////////////
  375. void
  376. VideoConfigDialogClass::Select_Default_Resolution (void)
  377. {
  378. int best_selection = 0;
  379. float best_width_err = 1000.0F;
  380. float best_height_err = 1000.0F;
  381. //
  382. // Loop over all the available resolutions and try to select
  383. // the one that most closely matches the desired resolution
  384. //
  385. for (int index = 0; index < ResolutionList.Count (); index ++) {
  386. const ResolutionDescClass &res_desc = ResolutionList[index];
  387. //
  388. // Calculate how far off this resolution is from the one
  389. // we want to select
  390. //
  391. float width_err = WWMath::Fabs(((float)CurrentWidth / (float)res_desc.Width) - 1.0F);
  392. float height_err = WWMath::Fabs(((float)CurrentHeight / (float)res_desc.Height) - 1.0F);
  393. //
  394. // Is this the closest match so far?
  395. //
  396. if (width_err <= best_width_err && height_err <= best_height_err) {
  397. best_width_err = width_err;
  398. best_height_err = height_err;
  399. best_selection = index;
  400. }
  401. }
  402. //
  403. // Select the closest match
  404. //
  405. m_ResSliderCtrl.SetPos (best_selection);
  406. Update_Resolution_Text ();
  407. return ;
  408. }
  409. /////////////////////////////////////////////////////////////////////////////
  410. //
  411. // Update_Resolution_Text
  412. //
  413. /////////////////////////////////////////////////////////////////////////////
  414. void
  415. VideoConfigDialogClass::Update_Resolution_Text (void)
  416. {
  417. int res_index = m_ResSliderCtrl.GetPos ();
  418. if (res_index >= 0) {
  419. //
  420. // Make a display string for the current resolution
  421. //
  422. const ResolutionDescClass &res_desc = ResolutionList[res_index];
  423. CString res_string;
  424. res_string.Format ("%d x %d", res_desc.Width, res_desc.Height);
  425. //
  426. // Set the text of the dialog control
  427. //
  428. SetDlgItemText (IDC_RESOLUTION_STATIC, res_string);
  429. //
  430. // Store the current width and height
  431. //
  432. CurrentWidth = res_desc.Width;
  433. CurrentHeight = res_desc.Height;
  434. }
  435. return ;
  436. }
  437. /////////////////////////////////////////////////////////////////////////////
  438. //
  439. // OnItemchangedDriverList
  440. //
  441. /////////////////////////////////////////////////////////////////////////////
  442. void
  443. VideoConfigDialogClass::OnItemchangedDriverList
  444. (
  445. NMHDR * pNMHDR,
  446. LRESULT * pResult
  447. )
  448. {
  449. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  450. (*pResult) = 0;
  451. //
  452. // If the selection state changed, then update the resolution
  453. // list for this device
  454. //
  455. if (pNMListView->uChanged & LVIF_STATE) {
  456. Update_Display_Settings ();
  457. }
  458. return ;
  459. }
  460. /////////////////////////////////////////////////////////////////////////////
  461. //
  462. // ResolutionSortCallback
  463. //
  464. /////////////////////////////////////////////////////////////////////////////
  465. int _cdecl
  466. ResolutionSortCallback (const void *elem1, const void *elem2)
  467. {
  468. const ResolutionDescClass *res1 = ((const ResolutionDescClass *)elem1);
  469. const ResolutionDescClass *res2 = ((const ResolutionDescClass *)elem2);
  470. int retval = 0;
  471. //
  472. // Sort based on bit-depth first
  473. //
  474. if (res1->BitDepth < res2->BitDepth) {
  475. retval = -1;
  476. } else if (res1->BitDepth > res2->BitDepth) {
  477. retval = 1;
  478. } else {
  479. //
  480. // Sort based on width next
  481. //
  482. if (res1->Width < res2->Width) {
  483. retval = -1;
  484. } else if (res1->Width > res2->Width) {
  485. retval = 1;
  486. } else {
  487. //
  488. // Sort based on height last
  489. //
  490. if (res1->Height < res2->Height) {
  491. retval = -1;
  492. } else if (res1->Height > res2->Height) {
  493. retval = 1;
  494. }
  495. }
  496. }
  497. return retval;
  498. }
  499. /////////////////////////////////////////////////////////////////////////////
  500. //
  501. // OnSelchangeBitdepthCombo
  502. //
  503. /////////////////////////////////////////////////////////////////////////////
  504. void
  505. VideoConfigDialogClass::OnSelchangeBitdepthCombo (void)
  506. {
  507. int index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETCURSEL);
  508. if (index != CB_ERR) {
  509. //
  510. // Update the current bit depth
  511. //
  512. CurrentBitDepth = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETITEMDATA, (WPARAM)index);
  513. if (CurrentBitDepth <= 0) {
  514. CurrentBitDepth = 16;
  515. }
  516. //
  517. // Update the dialog controls
  518. //
  519. Update_Resolution_Slider ();
  520. Select_Default_Resolution ();
  521. }
  522. return ;
  523. }
  524. /////////////////////////////////////////////////////////////////////////////
  525. //
  526. // OnHScroll
  527. //
  528. /////////////////////////////////////////////////////////////////////////////
  529. void
  530. VideoConfigDialogClass::OnHScroll (UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
  531. {
  532. CDialog::OnHScroll (nSBCode, nPos, pScrollBar);
  533. //
  534. // Simply update the display text on the dialog to reflect the new resolution
  535. //
  536. Update_Resolution_Text ();
  537. return ;
  538. }
  539. /////////////////////////////////////////////////////////////////////////////
  540. //
  541. // Apply_Changes
  542. //
  543. /////////////////////////////////////////////////////////////////////////////
  544. void
  545. VideoConfigDialogClass::Apply_Changes (void)
  546. {
  547. //
  548. // Save the changes to the registry
  549. //
  550. WW3D::Registry_Save_Render_Device (RENEGADE_SUB_KEY_NAME_RENDER, CurrentDriverIndex,
  551. CurrentWidth, CurrentHeight, CurrentBitDepth, CurrentIsWindowed, WW3D::Get_Texture_Bitdepth());
  552. return ;
  553. }
  554. /////////////////////////////////////////////////////////////////////////////
  555. //
  556. // WindowProc
  557. //
  558. /////////////////////////////////////////////////////////////////////////////
  559. LRESULT
  560. VideoConfigDialogClass::WindowProc
  561. (
  562. UINT message,
  563. WPARAM wParam,
  564. LPARAM lParam
  565. )
  566. {
  567. if (message == (WM_USER + 101)) {
  568. Apply_Changes ();
  569. }
  570. return CDialog::WindowProc(message, wParam, lParam);
  571. }
  572. /////////////////////////////////////////////////////////////////////////////
  573. //
  574. // OnWindowedCheck
  575. //
  576. /////////////////////////////////////////////////////////////////////////////
  577. void
  578. VideoConfigDialogClass::OnWindowedCheck (void)
  579. {
  580. CurrentIsWindowed = (SendDlgItemMessage (IDC_WINDOWED_CHECK, BM_GETCHECK) == 1);
  581. return ;
  582. }