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/W3DView/SceneLightDialog.cpp

564 lines
15 KiB
C++
Raw Permalink Normal View History

/*
** 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/>.
*/
// SceneLightDialog.cpp : implementation file
//
#include "stdafx.h"
#include "W3DView.h"
#include "SceneLightDialog.h"
#include "Utils.H"
#include "MainFrm.H"
#include "W3DViewDoc.H"
#include "Scene.H"
#include "Light.H"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////
//
// CSceneLightDialog
//
CSceneLightDialog::CSceneLightDialog(CWnd* pParent /*=NULL*/)
: m_CurrentChannel (DIFFUSE),
m_InitialStartAtten (0),
m_InitialEndAtten (0),
m_InitialDistance (0),
m_InitialIntensity (0),
m_InitialAttenOn (TRUE),
CDialog(CSceneLightDialog::IDD, pParent)
{
//{{AFX_DATA_INIT(CSceneLightDialog)
//}}AFX_DATA_INIT
return ;
}
//////////////////////////////////////////////////////////////
//
// DoDataExchange
//
void
CSceneLightDialog::DoDataExchange (CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSceneLightDialog)
DDX_Control(pDX, IDC_START_ATTENUATION_SPIN, m_StartAttenSpin);
DDX_Control(pDX, IDC_END_ATTENUATION_SPIN, m_EndAttenSpin);
DDX_Control(pDX, IDC_DISTANCE_SPIN, m_DistanceSpin);
DDX_Control(pDX, IDC_INTENSITY_SLIDER, m_IntensitySlider);
DDX_Control(pDX, IDC_SLIDER_BLUE, m_blueSlider);
DDX_Control(pDX, IDC_SLIDER_GREEN, m_greenSlider);
DDX_Control(pDX, IDC_SLIDER_RED, m_redSlider);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(CSceneLightDialog, CDialog)
//{{AFX_MSG_MAP(CSceneLightDialog)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_GRAYSCALE_CHECK, OnGrayscaleCheck)
ON_BN_CLICKED(IDC_CHANNEL_BOTH_RADIO, OnChannelBothRadio)
ON_BN_CLICKED(IDC_CHANNEL_DIFFUSE_RADIO, OnChannelDiffuseRadio)
ON_BN_CLICKED(IDC_CHANNEL_SPECULAR_RADIO, OnChannelSpecularRadio)
ON_BN_CLICKED(IDC_ATTENUATION_CHECK, OnAttenuationCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////
//
// OnInitDialog
//
BOOL
CSceneLightDialog::OnInitDialog (void)
{
// Allow the base class to process this message
CDialog::OnInitDialog ();
// Center the dialog around the data tree view instead
// of the direct center of the screen
::CenterDialogAroundTreeView (m_hWnd);
// Set the initial ranges for the color sliders
m_redSlider.SetRange (0, 100);
m_greenSlider.SetRange (0, 100);
m_blueSlider.SetRange (0, 100);
// Get a pointer to the doc so we can get at the current scene
// pointer.
CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
if (pCDoc && pCDoc->GetScene ()) {
Vector3 diffuse;
Vector3 specular;
pCDoc->GetSceneLight ()->Get_Diffuse (&diffuse);
pCDoc->GetSceneLight ()->Get_Specular (&specular);
// Remember these initial settings so we can restore them
// if the user cancels
m_InitialRedDiffuse = int(diffuse.X * 100.00F);
m_InitialGreenDiffuse = int(diffuse.Y * 100.00F);
m_InitialBlueDiffuse = int(diffuse.Z * 100.00F);
m_InitialRedSpecular = int(specular.X * 100.00F);
m_InitialGreenSpecular = int(specular.Y * 100.00F);
m_InitialBlueSpecular = int(specular.Z * 100.00F);
Set_Color_Control_State (diffuse);
// Get the light's attenuation
double start = 0;
double end = 0;
pCDoc->GetSceneLight ()->Get_Far_Attenuation_Range (start, end);
BOOL atten_on = pCDoc->GetSceneLight ()->Get_Flag (LightClass::FAR_ATTENUATION);
SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_SETCHECK, (WPARAM)atten_on);
// Get the light's intensity
float intensity = pCDoc->GetSceneLight ()->Get_Intensity ();
// Attempt to calculate the light's distance from the object
float distance = 0;
if (pCDoc->GetDisplayedObject () != NULL) {
// Get the position of the light and the displayed object
Vector3 light_pos = pCDoc->GetSceneLight ()->Get_Position ();
Vector3 obj_pos = pCDoc->GetDisplayedObject ()->Get_Position ();
// Compute the distance of the 2 vectors
distance = (light_pos - obj_pos).Length ();
}
// Set-up the edit controls
::SetDlgItemFloat (m_hWnd, IDC_START_ATTENUATION_EDIT, start);
::SetDlgItemFloat (m_hWnd, IDC_END_ATTENUATION_EDIT, end);
::SetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT, distance);
// Set-up the spin controls
m_DistanceSpin.SetRange (0, 1000000L);
m_DistanceSpin.SetPos ((distance * 100));
m_StartAttenSpin.SetRange (0, 1000000L);
m_StartAttenSpin.SetPos ((start * 100));
m_EndAttenSpin.SetRange (0, 1000000L);
m_EndAttenSpin.SetPos ((end * 100));
// Setup the slider control
m_IntensitySlider.SetRange (0, 100);
m_IntensitySlider.SetPos (intensity * 100.0F);
// Record the initial settings so we can restore them on cancel
m_InitialStartAtten = start;
m_InitialEndAtten = end;
m_InitialDistance = distance;
m_InitialIntensity = intensity;
m_InitialAttenOn = atten_on;
}
// Check the 'Diffuse' channel by default
SendDlgItemMessage (IDC_CHANNEL_DIFFUSE_RADIO, BM_SETCHECK, (WPARAM)TRUE);
Update_Attenuation_Controls ();
return TRUE;
}
//////////////////////////////////////////////////////////////
//
// OnHScroll
//
void
CSceneLightDialog::OnHScroll
(
UINT nSBCode,
UINT nPos,
CScrollBar* pScrollBar
)
{
// Did the intensity slider send this message or did the color sliders?
if (pScrollBar == GetDlgItem (IDC_INTENSITY_SLIDER)) {
// Update the light's intensity settings
float intensity = ((float)m_IntensitySlider.GetPos ()) / 100.0F;
::GetCurrentDocument ()->GetSceneLight ()->Set_Intensity (intensity);
} else {
// Are the 3 colors locked together?
if (SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_GETCHECK)) {
// Which color sent this message?
int iCurrentPos = 0;
if (pScrollBar == GetDlgItem (IDC_SLIDER_RED)) {
// Use this color as default
iCurrentPos = m_redSlider.GetPos ();
}
else if (pScrollBar == GetDlgItem (IDC_SLIDER_GREEN)) {
// Use this color as default
iCurrentPos = m_greenSlider.GetPos ();
}
else {
// Use this color as default
iCurrentPos = m_blueSlider.GetPos ();
}
// Make all the sliders the same pos
m_redSlider.SetPos (iCurrentPos);
m_greenSlider.SetPos (iCurrentPos);
m_blueSlider.SetPos (iCurrentPos);
}
// Update the light to reflect the new settings
Vector3 color;
color.X = float(m_redSlider.GetPos ()) / 100.00F;
color.Y = float(m_greenSlider.GetPos ()) / 100.00F;
color.Z = float(m_blueSlider.GetPos ()) / 100.00F;
Update_Light (color);
}
// Allow the base class to process this message
CDialog::OnHScroll (nSBCode, nPos, pScrollBar);
return ;
}
//////////////////////////////////////////////////////////////
//
// OnCancel
//
void
CSceneLightDialog::OnCancel (void)
{
// Get a pointer to the document so we can change the scene light's
// settings and position
CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
if (pCDoc && pCDoc->GetScene ()) {
Vector3 diffuse;
diffuse.X = float(m_InitialRedDiffuse) / 100.00F;
diffuse.Y = float(m_InitialGreenDiffuse) / 100.00F;
diffuse.Z = float(m_InitialBlueDiffuse) / 100.00F;
Vector3 specular;
specular.X = float(m_InitialRedSpecular) / 100.00F;
specular.Y = float(m_InitialGreenSpecular) / 100.00F;
specular.Z = float(m_InitialBlueSpecular) / 100.00F;
// Restore the scene light's color
pCDoc->GetSceneLight ()->Set_Diffuse (diffuse);
pCDoc->GetSceneLight ()->Set_Specular (specular);
// Restore the intensity, attenuation, and distance settings
pCDoc->GetSceneLight ()->Set_Intensity (m_InitialIntensity);
pCDoc->GetSceneLight ()->Set_Far_Attenuation_Range (m_InitialStartAtten, m_InitialEndAtten);
pCDoc->GetSceneLight ()->Set_Flag (LightClass::FAR_ATTENUATION, (m_InitialAttenOn == TRUE));
Update_Distance (m_InitialDistance);
}
// Allow the base class to process this message
CDialog::OnCancel ();
return ;
}
//////////////////////////////////////////////////////////////
//
// WindowProc
//
LRESULT
CSceneLightDialog::WindowProc
(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch (message)
{
case WM_NOTIFY:
{
// Did this notification come from a spin control?
NMHDR *pheader = (NMHDR *)lParam;
if ((pheader != NULL) && (pheader->code == UDN_DELTAPOS)) {
LPNMUPDOWN pupdown = (LPNMUPDOWN)lParam;
// Get the buddy window associated with this spin control
HWND hbuddy_wnd = (HWND)SendDlgItemMessage ((int)wParam, UDM_GETBUDDY);
if (::IsWindow (hbuddy_wnd)) {
// Get the current value, increment it, and put it back into the control
float value = ::GetWindowFloat (hbuddy_wnd);
value += (((float)(pupdown->iDelta)) / 100.0F);
::SetWindowFloat (hbuddy_wnd, value);
// Force update the light
Update_Distance (::GetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT));
Update_Attenuation ();
}
}
}
break;
case WM_COMMAND:
{
if (HIWORD (wParam) == EN_KILLFOCUS) {
switch (LOWORD (wParam))
{
case IDC_DISTANCE_EDIT:
{
Update_Distance (::GetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT));
}
break;
case IDC_START_ATTENUATION_EDIT:
case IDC_END_ATTENUATION_EDIT:
{
Update_Attenuation ();
}
break;
}
}
}
break;
case WM_PAINT:
{
// Paint the gradients for each color
::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_RED_GRADIENT), 1, 0, 0);
::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_GREEN_GRADIENT), 0, 1, 0);
::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_BLUE_GRADIENT), 0, 0, 1);
}
break;
}
// Allow the base class to process this message
return CDialog::WindowProc (message, wParam, lParam);
}
//////////////////////////////////////////////////////////////
//
// OnGrayscaleCheck
//
void
CSceneLightDialog::OnGrayscaleCheck (void)
{
if (SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_GETCHECK)) {
// Make the green and blue sliders the same as red
m_greenSlider.SetPos (m_redSlider.GetPos ());
m_blueSlider.SetPos (m_redSlider.GetPos ());
Vector3 color;
color.X = float(m_redSlider.GetPos ()) / 100.00F;
color.Y = float(m_greenSlider.GetPos ()) / 100.00F;
color.Z = float(m_blueSlider.GetPos ()) / 100.00F;
Update_Light (color);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// OnChannelBothRadio
//
void
CSceneLightDialog::OnChannelBothRadio (void)
{
m_CurrentChannel = BOTH;
return ;
}
//////////////////////////////////////////////////////////////
//
// OnChannelDiffuseRadio
//
void
CSceneLightDialog::OnChannelDiffuseRadio (void)
{
// Reset the UI to reflect the current diffuse color
Vector3 color;
::GetCurrentDocument ()->GetSceneLight ()->Get_Diffuse (&color);
Set_Color_Control_State (color);
m_CurrentChannel = DIFFUSE;
return ;
}
//////////////////////////////////////////////////////////////
//
// OnChannelSpecularRadio
//
void
CSceneLightDialog::OnChannelSpecularRadio (void)
{
// Reset the UI to reflect the current specular color
Vector3 color;
::GetCurrentDocument ()->GetSceneLight ()->Get_Specular (&color);
Set_Color_Control_State (color);
m_CurrentChannel = SPECULAR;
return ;
}
//////////////////////////////////////////////////////////////
//
// Update_Light
//
void
CSceneLightDialog::Update_Light (const Vector3 &color)
{
// Get a pointer to the document so we can change the scene light's
// settings
CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
if (pCDoc && pCDoc->GetScene ()) {
// Update the diffuse setting of the scene light if necessary
if (m_CurrentChannel & DIFFUSE) {
pCDoc->GetSceneLight ()->Set_Diffuse (color);
}
// Update the specular setting of the scene light if necessary
if (m_CurrentChannel & SPECULAR) {
pCDoc->GetSceneLight ()->Set_Specular (color);
}
}
return ;
}
//////////////////////////////////////////////////////////////
//
// Set_Color_Control_State
//
void
CSceneLightDialog::Set_Color_Control_State (const Vector3 &color)
{
// Should we 'lock' the color sliders together?
if ((color.X == color.Y) &&
(color.X == color.Z)) {
SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_SETCHECK, (WPARAM)TRUE);
} else {
SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_SETCHECK, (WPARAM)FALSE);
}
// Set the color slider positions
m_redSlider.SetPos (int(color.X * 100.0F));
m_greenSlider.SetPos (int(color.Y * 100.0F));
m_blueSlider.SetPos (int(color.Z * 100.0F));
return ;
}
//////////////////////////////////////////////////////////////
//
// Update_Attenuation
//
void
CSceneLightDialog::Update_Attenuation (void)
{
// Get a pointer to the document so we can change the scene light's
// settings
CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
if (pCDoc && pCDoc->GetScene ()) {
// Update the attenuation settings
float start = ::GetDlgItemFloat (m_hWnd, IDC_START_ATTENUATION_EDIT);
float end = ::GetDlgItemFloat (m_hWnd, IDC_END_ATTENUATION_EDIT);
pCDoc->GetSceneLight ()->Set_Far_Attenuation_Range (start, end);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// Update_Distance
//
void
CSceneLightDialog::Update_Distance (float distance)
{
// Get a pointer to the document so we can change the scene light's
// settings
CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
if (pCDoc && pCDoc->GetScene ()) {
// Get the position of the displayed object
Vector3 obj_pos (0,0,0);
if (pCDoc->GetDisplayedObject ()) {
obj_pos = pCDoc->GetDisplayedObject ()->Get_Position ();
}
// Get the position of the light and the displayed object
Vector3 light_pos = pCDoc->GetSceneLight ()->Get_Position ();
Vector3 new_pos = (light_pos - obj_pos);
new_pos.Normalize ();
new_pos = new_pos * distance;
// Update the attenuation settings
pCDoc->GetSceneLight ()->Set_Position (new_pos);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// Update_Attenuation_Controls
//
void
CSceneLightDialog::Update_Attenuation_Controls (void)
{
// Enable or disable the attenuation controls based on the group's checkstate
BOOL enable = (SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_GETCHECK) == 1);
::EnableWindow (::GetDlgItem (m_hWnd, IDC_START_ATTENUATION_EDIT), enable);
::EnableWindow (::GetDlgItem (m_hWnd, IDC_START_ATTENUATION_SPIN), enable);
::EnableWindow (::GetDlgItem (m_hWnd, IDC_END_ATTENUATION_EDIT), enable);
::EnableWindow (::GetDlgItem (m_hWnd, IDC_END_ATTENUATION_SPIN), enable);
return ;
}
//////////////////////////////////////////////////////////////
//
// OnAttenuationCheck
//
void
CSceneLightDialog::OnAttenuationCheck (void)
{
// Update the scene light to reflect the new setting
bool enable = (SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_GETCHECK) == 1);
CW3DViewDoc *pdoc = ::GetCurrentDocument ();
pdoc->GetSceneLight ()->Set_Flag (LightClass::FAR_ATTENUATION, enable);
// Update the dialog controls to reflect the new setting
Update_Attenuation_Controls ();
return ;
}