This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/WWConfig/VideoConfigDialog.cpp

686 lines
17 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// VideoConfigDialog.cpp : implementation file
//
#include "stdafx.h"
#include "wwconfig.h"
#include "videoconfigdialog.h"
#include "ww3d.h"
#include "assetmgr.h"
#include "locale_api.h"
#include "wwconfig_ids.h"
#include "assetstatus.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static VideoConfigDialogClass* VideoConfigDialogInstance;
/////////////////////////////////////////////////////////////////////////////
// Globals
/////////////////////////////////////////////////////////////////////////////
WW3DAssetManager *_TheAssetMgr = NULL;;
/////////////////////////////////////////////////////////////////////////////
// Local prototypes
/////////////////////////////////////////////////////////////////////////////
int _cdecl ResolutionSortCallback (const void *elem1, const void *elem2);
/////////////////////////////////////////////////////////////////////////////
// Constants
/////////////////////////////////////////////////////////////////////////////
enum
{
COL_DEVICE_NAME = 0
};
/////////////////////////////////////////////////////////////////////////////
//
// VideoConfigDialogClass
//
/////////////////////////////////////////////////////////////////////////////
VideoConfigDialogClass::VideoConfigDialogClass (CWnd *pParent)
: CurrentBitDepth (16),
CurrentWidth (800),
CurrentHeight (600),
CurrentDriverIndex (0),
CurrentIsWindowed (false),
CDialog(VideoConfigDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(VideoConfigDialogClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
WWASSERT(!VideoConfigDialogInstance); // Only one can exist at a time!
VideoConfigDialogInstance=this;
CDialog::Create (VideoConfigDialogClass::IDD, pParent);
return ;
}
VideoConfigDialogClass::~VideoConfigDialogClass ()
{
VideoConfigDialogInstance=NULL;
}
VideoConfigDialogClass* VideoConfigDialogClass::Get_Instance ()
{
return VideoConfigDialogInstance;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::DoDataExchange (CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(VideoConfigDialogClass)
DDX_Control(pDX, IDC_RESOLUTION_SLIDER, m_ResSliderCtrl);
DDX_Control(pDX, IDC_DRIVER_LIST, m_DriverListCtrl);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(VideoConfigDialogClass, CDialog)
//{{AFX_MSG_MAP(VideoConfigDialogClass)
ON_WM_DESTROY()
ON_NOTIFY(LVN_ITEMCHANGED, IDC_DRIVER_LIST, OnItemchangedDriverList)
ON_CBN_SELCHANGE(IDC_BITDEPTH_COMBO, OnSelchangeBitdepthCombo)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_WINDOWED_CHECK, OnWindowedCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
// Modified: 12/06/2001 by MML - Retrieving strings from Locomoto file.
/////////////////////////////////////////////////////////////////////////////
BOOL
VideoConfigDialogClass::OnInitDialog (void)
{
char string [_MAX_PATH];
CDialog::OnInitDialog ();
//
// Set all the static strings for this dialog.
//
Locale_GetString( IDS_DRIVER, string );
SetDlgItemText( IDC_DRIVER, string );
Locale_GetString( IDS_DISPLAY, string );
SetDlgItemText( IDC_STATIC2, string );
Locale_GetString( IDS_RESOLUTION, string );
SetDlgItemText( IDC_RESOLUTION, string );
Locale_GetString( IDS_COLOR_DEPTH, string );
SetDlgItemText( IDC_BIT_DEPTH, string );
Locale_GetString( IDS_WINDOWED_MODE, string );
SetDlgItemText( IDC_WINDOWED_CHECK, string );
//
// Initialize the engine
//
_TheAssetMgr = new WW3DAssetManager;
WW3D::Init (m_hWnd);
AssetStatusClass::Peek_Instance()->Enable_Reporting (false);
//
// Load the render device settings from the registry
//
char device_name[256] = { 0 };
int texture_depth = 0;
int width = 0;
int height = 0;
int bit_depth = 0;
int windowed = 0;
if (WW3D::Registry_Load_Render_Device (RENEGADE_SUB_KEY_NAME_RENDER, device_name, 256,
width, height, bit_depth, windowed, texture_depth))
{
if (width != -1) {
CurrentWidth = width;
}
if (height != -1) {
CurrentHeight = height;
}
if (bit_depth != -1) {
CurrentBitDepth = bit_depth;
}
if (windowed != -1) {
CurrentIsWindowed = bool(windowed == 1);
}
}
//
// Set the extended styles for the list control
//
m_DriverListCtrl.SetExtendedStyle (m_DriverListCtrl.GetExtendedStyle () | LVS_EX_FULLROWSELECT);
//
// Configure the columns
//
m_DriverListCtrl.InsertColumn (COL_DEVICE_NAME, "Device Name");
//
// Populate the render device list control
//
bool found_default_entry = false;
int driver_count = WW3D::Get_Render_Device_Count ();
for (int index = 0; index < driver_count; index ++) {
const RenderDeviceDescClass &device_desc = WW3D::Get_Render_Device_Desc (index);
//
// Build a human readable name for this driver
//
CString driver_name;
driver_name.Format ("%s - %s", device_desc.Get_Device_Name (), device_desc.Get_Hardware_Name ());
//
// Add this driver to the list control
//
int item_index = m_DriverListCtrl.InsertItem (0xFF, driver_name);
if (item_index >= 0) {
m_DriverListCtrl.SetItemData (item_index, index);
}
//
// Check to see if this is the default entry
//
const char *render_device_name = WW3D::Get_Render_Device_Name (index);
if (::lstrcmpi (device_name, render_device_name) == 0) {
m_DriverListCtrl.SetItemState (item_index, LVIS_SELECTED, LVIS_SELECTED);
found_default_entry = true;
}
}
//
// Set the "windowed mode" checkbox
//
SendDlgItemMessage (IDC_WINDOWED_CHECK, BM_SETCHECK, (WPARAM)CurrentIsWindowed);
//
// Select the first entry for deafult (if necessary)
//
if (found_default_entry == false) {
m_DriverListCtrl.SetItemState (0, LVIS_SELECTED, LVIS_SELECTED);
}
//
// Size the columns
//
CRect rect;
m_DriverListCtrl.GetClientRect (&rect);
int col_width = rect.Width () - ::GetSystemMetrics (SM_CXVSCROLL);
m_DriverListCtrl.SetColumnWidth (0, col_width);
//
// Build the resolution list for the currently selected device
//
Update_Display_Settings ();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDestroy
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::OnDestroy (void)
{
//
// Shutdown the engine
//
WW3D::Shutdown ();
delete _TheAssetMgr;
_TheAssetMgr = NULL;
CDialog::OnDestroy ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Display_Settings
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Update_Display_Settings (void)
{
//
// Get the selected device
//
int selected_index = m_DriverListCtrl.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED);
if (selected_index < 0) {
return ;
}
//
// Lookup the device description for the selected device
//
CurrentDriverIndex = (int)m_DriverListCtrl.GetItemData (selected_index);
const RenderDeviceDescClass &driver_info = WW3D::Get_Render_Device_Desc (CurrentDriverIndex);
ResolutionList = driver_info.Enumerate_Resolutions ();
CurrentCaps=driver_info.Get_Caps();
CurrentAdapterIdentifier=driver_info.Get_Adapter_Identifier();
//
// Update the dialog controls
//
Update_Color_Combo ();
Update_Resolution_Slider ();
Select_Default_Resolution ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Resolution_Slider
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Update_Resolution_Slider (void)
{
//
// Lookup the device description for the selected device
//
const RenderDeviceDescClass &driver_info = WW3D::Get_Render_Device_Desc (CurrentDriverIndex);
ResolutionList = driver_info.Enumerate_Resolutions ();
//
// Filter out any resolutions that don't fit the current
// bit depth
//
for (int index = 0; index < ResolutionList.Count (); index ++) {
const ResolutionDescClass &res_desc = ResolutionList[index];
//
// Remove this resolution if it doesn't fit the current
// bit depth
//
if (res_desc.BitDepth != CurrentBitDepth || res_desc.Width < 640 || res_desc.Height < 480) {
ResolutionList.Delete (index);
index --;
}
}
//
// Sort the entries
//
if (ResolutionList.Count () > 0) {
::qsort (&ResolutionList[0], ResolutionList.Count (), sizeof (ResolutionList[0]), ResolutionSortCallback);
}
//
// Configure the slider control
//
m_ResSliderCtrl.ClearTics ();
m_ResSliderCtrl.SetRange (0, ResolutionList.Count () - 1);
//
// Setup the tick marks
//
for (index = 0; index < ResolutionList.Count (); index ++) {
m_ResSliderCtrl.SetTic (index);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Color_Combo
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Update_Color_Combo (void)
{
//
// Start fresh
//
SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_RESETCONTENT);
//
// Loop over all the resolutions and add the different
// bit-depths to the combo box
//
bool selected = false;
for (int index = 0; index < ResolutionList.Count (); index ++) {
const ResolutionDescClass &res_desc = ResolutionList[index];
char string [_MAX_PATH];
CString color_string;
//
// Make a display string out of the bit depth
//
Locale_GetString (IDS_BIT, string);
color_string.Format ("%d %s", res_desc.BitDepth, string);
//
// Check to see if this string is already in the combobox
//
int item_index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_FINDSTRINGEXACT, 0, (LPARAM)(LPCTSTR)color_string);
if (item_index == CB_ERR) {
//
// Add this entry to the combobox
//
int item_index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)color_string);
if (item_index != CB_ERR) {
SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETITEMDATA, (WPARAM)item_index, (LPARAM)res_desc.BitDepth);
//
// Select this entry if its the current bit depth
//
if (res_desc.BitDepth == CurrentBitDepth) {
SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETCURSEL, (WPARAM)item_index);
selected = true;
}
}
}
}
//
// Select the first entry by default
//
if (!selected) {
SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_SETCURSEL, 0);
CurrentBitDepth = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETITEMDATA, 0);
if (CurrentBitDepth <= 0) {
CurrentBitDepth = 16;
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Select_Default_Resolution
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Select_Default_Resolution (void)
{
int best_selection = 0;
float best_width_err = 1000.0F;
float best_height_err = 1000.0F;
//
// Loop over all the available resolutions and try to select
// the one that most closely matches the desired resolution
//
for (int index = 0; index < ResolutionList.Count (); index ++) {
const ResolutionDescClass &res_desc = ResolutionList[index];
//
// Calculate how far off this resolution is from the one
// we want to select
//
float width_err = WWMath::Fabs(((float)CurrentWidth / (float)res_desc.Width) - 1.0F);
float height_err = WWMath::Fabs(((float)CurrentHeight / (float)res_desc.Height) - 1.0F);
//
// Is this the closest match so far?
//
if (width_err <= best_width_err && height_err <= best_height_err) {
best_width_err = width_err;
best_height_err = height_err;
best_selection = index;
}
}
//
// Select the closest match
//
m_ResSliderCtrl.SetPos (best_selection);
Update_Resolution_Text ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Update_Resolution_Text
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Update_Resolution_Text (void)
{
int res_index = m_ResSliderCtrl.GetPos ();
if (res_index >= 0) {
//
// Make a display string for the current resolution
//
const ResolutionDescClass &res_desc = ResolutionList[res_index];
CString res_string;
res_string.Format ("%d x %d", res_desc.Width, res_desc.Height);
//
// Set the text of the dialog control
//
SetDlgItemText (IDC_RESOLUTION_STATIC, res_string);
//
// Store the current width and height
//
CurrentWidth = res_desc.Width;
CurrentHeight = res_desc.Height;
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnItemchangedDriverList
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::OnItemchangedDriverList
(
NMHDR * pNMHDR,
LRESULT * pResult
)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
(*pResult) = 0;
//
// If the selection state changed, then update the resolution
// list for this device
//
if (pNMListView->uChanged & LVIF_STATE) {
Update_Display_Settings ();
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// ResolutionSortCallback
//
/////////////////////////////////////////////////////////////////////////////
int _cdecl
ResolutionSortCallback (const void *elem1, const void *elem2)
{
const ResolutionDescClass *res1 = ((const ResolutionDescClass *)elem1);
const ResolutionDescClass *res2 = ((const ResolutionDescClass *)elem2);
int retval = 0;
//
// Sort based on bit-depth first
//
if (res1->BitDepth < res2->BitDepth) {
retval = -1;
} else if (res1->BitDepth > res2->BitDepth) {
retval = 1;
} else {
//
// Sort based on width next
//
if (res1->Width < res2->Width) {
retval = -1;
} else if (res1->Width > res2->Width) {
retval = 1;
} else {
//
// Sort based on height last
//
if (res1->Height < res2->Height) {
retval = -1;
} else if (res1->Height > res2->Height) {
retval = 1;
}
}
}
return retval;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnSelchangeBitdepthCombo
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::OnSelchangeBitdepthCombo (void)
{
int index = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETCURSEL);
if (index != CB_ERR) {
//
// Update the current bit depth
//
CurrentBitDepth = SendDlgItemMessage (IDC_BITDEPTH_COMBO, CB_GETITEMDATA, (WPARAM)index);
if (CurrentBitDepth <= 0) {
CurrentBitDepth = 16;
}
//
// Update the dialog controls
//
Update_Resolution_Slider ();
Select_Default_Resolution ();
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnHScroll
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::OnHScroll (UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
{
CDialog::OnHScroll (nSBCode, nPos, pScrollBar);
//
// Simply update the display text on the dialog to reflect the new resolution
//
Update_Resolution_Text ();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Apply_Changes
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::Apply_Changes (void)
{
//
// Save the changes to the registry
//
WW3D::Registry_Save_Render_Device (RENEGADE_SUB_KEY_NAME_RENDER, CurrentDriverIndex,
CurrentWidth, CurrentHeight, CurrentBitDepth, CurrentIsWindowed, WW3D::Get_Texture_Bitdepth());
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// WindowProc
//
/////////////////////////////////////////////////////////////////////////////
LRESULT
VideoConfigDialogClass::WindowProc
(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
if (message == (WM_USER + 101)) {
Apply_Changes ();
}
return CDialog::WindowProc(message, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnWindowedCheck
//
/////////////////////////////////////////////////////////////////////////////
void
VideoConfigDialogClass::OnWindowedCheck (void)
{
CurrentIsWindowed = (SendDlgItemMessage (IDC_WINDOWED_CHECK, BM_GETCHECK) == 1);
return ;
}