SceneLightDialog.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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. // SceneLightDialog.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "W3DView.h"
  22. #include "SceneLightDialog.h"
  23. #include "Utils.H"
  24. #include "MainFrm.H"
  25. #include "W3DViewDoc.H"
  26. #include "Scene.H"
  27. #include "Light.H"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. //////////////////////////////////////////////////////////////
  34. //
  35. // CSceneLightDialog
  36. //
  37. CSceneLightDialog::CSceneLightDialog(CWnd* pParent /*=NULL*/)
  38. : m_CurrentChannel (DIFFUSE),
  39. m_InitialStartAtten (0),
  40. m_InitialEndAtten (0),
  41. m_InitialDistance (0),
  42. m_InitialIntensity (0),
  43. m_InitialAttenOn (TRUE),
  44. CDialog(CSceneLightDialog::IDD, pParent)
  45. {
  46. //{{AFX_DATA_INIT(CSceneLightDialog)
  47. //}}AFX_DATA_INIT
  48. return ;
  49. }
  50. //////////////////////////////////////////////////////////////
  51. //
  52. // DoDataExchange
  53. //
  54. void
  55. CSceneLightDialog::DoDataExchange (CDataExchange* pDX)
  56. {
  57. CDialog::DoDataExchange(pDX);
  58. //{{AFX_DATA_MAP(CSceneLightDialog)
  59. DDX_Control(pDX, IDC_START_ATTENUATION_SPIN, m_StartAttenSpin);
  60. DDX_Control(pDX, IDC_END_ATTENUATION_SPIN, m_EndAttenSpin);
  61. DDX_Control(pDX, IDC_DISTANCE_SPIN, m_DistanceSpin);
  62. DDX_Control(pDX, IDC_INTENSITY_SLIDER, m_IntensitySlider);
  63. DDX_Control(pDX, IDC_SLIDER_BLUE, m_blueSlider);
  64. DDX_Control(pDX, IDC_SLIDER_GREEN, m_greenSlider);
  65. DDX_Control(pDX, IDC_SLIDER_RED, m_redSlider);
  66. //}}AFX_DATA_MAP
  67. return ;
  68. }
  69. BEGIN_MESSAGE_MAP(CSceneLightDialog, CDialog)
  70. //{{AFX_MSG_MAP(CSceneLightDialog)
  71. ON_WM_HSCROLL()
  72. ON_BN_CLICKED(IDC_GRAYSCALE_CHECK, OnGrayscaleCheck)
  73. ON_BN_CLICKED(IDC_CHANNEL_BOTH_RADIO, OnChannelBothRadio)
  74. ON_BN_CLICKED(IDC_CHANNEL_DIFFUSE_RADIO, OnChannelDiffuseRadio)
  75. ON_BN_CLICKED(IDC_CHANNEL_SPECULAR_RADIO, OnChannelSpecularRadio)
  76. ON_BN_CLICKED(IDC_ATTENUATION_CHECK, OnAttenuationCheck)
  77. //}}AFX_MSG_MAP
  78. END_MESSAGE_MAP()
  79. //////////////////////////////////////////////////////////////
  80. //
  81. // OnInitDialog
  82. //
  83. BOOL
  84. CSceneLightDialog::OnInitDialog (void)
  85. {
  86. // Allow the base class to process this message
  87. CDialog::OnInitDialog ();
  88. // Center the dialog around the data tree view instead
  89. // of the direct center of the screen
  90. ::CenterDialogAroundTreeView (m_hWnd);
  91. // Set the initial ranges for the color sliders
  92. m_redSlider.SetRange (0, 100);
  93. m_greenSlider.SetRange (0, 100);
  94. m_blueSlider.SetRange (0, 100);
  95. // Get a pointer to the doc so we can get at the current scene
  96. // pointer.
  97. CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
  98. if (pCDoc && pCDoc->GetScene ()) {
  99. Vector3 diffuse;
  100. Vector3 specular;
  101. pCDoc->GetSceneLight ()->Get_Diffuse (&diffuse);
  102. pCDoc->GetSceneLight ()->Get_Specular (&specular);
  103. // Remember these initial settings so we can restore them
  104. // if the user cancels
  105. m_InitialRedDiffuse = int(diffuse.X * 100.00F);
  106. m_InitialGreenDiffuse = int(diffuse.Y * 100.00F);
  107. m_InitialBlueDiffuse = int(diffuse.Z * 100.00F);
  108. m_InitialRedSpecular = int(specular.X * 100.00F);
  109. m_InitialGreenSpecular = int(specular.Y * 100.00F);
  110. m_InitialBlueSpecular = int(specular.Z * 100.00F);
  111. Set_Color_Control_State (diffuse);
  112. // Get the light's attenuation
  113. double start = 0;
  114. double end = 0;
  115. pCDoc->GetSceneLight ()->Get_Far_Attenuation_Range (start, end);
  116. BOOL atten_on = pCDoc->GetSceneLight ()->Get_Flag (LightClass::FAR_ATTENUATION);
  117. SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_SETCHECK, (WPARAM)atten_on);
  118. // Get the light's intensity
  119. float intensity = pCDoc->GetSceneLight ()->Get_Intensity ();
  120. // Attempt to calculate the light's distance from the object
  121. float distance = 0;
  122. if (pCDoc->GetDisplayedObject () != NULL) {
  123. // Get the position of the light and the displayed object
  124. Vector3 light_pos = pCDoc->GetSceneLight ()->Get_Position ();
  125. Vector3 obj_pos = pCDoc->GetDisplayedObject ()->Get_Position ();
  126. // Compute the distance of the 2 vectors
  127. distance = (light_pos - obj_pos).Length ();
  128. }
  129. // Set-up the edit controls
  130. ::SetDlgItemFloat (m_hWnd, IDC_START_ATTENUATION_EDIT, start);
  131. ::SetDlgItemFloat (m_hWnd, IDC_END_ATTENUATION_EDIT, end);
  132. ::SetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT, distance);
  133. // Set-up the spin controls
  134. m_DistanceSpin.SetRange (0, 1000000L);
  135. m_DistanceSpin.SetPos ((distance * 100));
  136. m_StartAttenSpin.SetRange (0, 1000000L);
  137. m_StartAttenSpin.SetPos ((start * 100));
  138. m_EndAttenSpin.SetRange (0, 1000000L);
  139. m_EndAttenSpin.SetPos ((end * 100));
  140. // Setup the slider control
  141. m_IntensitySlider.SetRange (0, 100);
  142. m_IntensitySlider.SetPos (intensity * 100.0F);
  143. // Record the initial settings so we can restore them on cancel
  144. m_InitialStartAtten = start;
  145. m_InitialEndAtten = end;
  146. m_InitialDistance = distance;
  147. m_InitialIntensity = intensity;
  148. m_InitialAttenOn = atten_on;
  149. }
  150. // Check the 'Diffuse' channel by default
  151. SendDlgItemMessage (IDC_CHANNEL_DIFFUSE_RADIO, BM_SETCHECK, (WPARAM)TRUE);
  152. Update_Attenuation_Controls ();
  153. return TRUE;
  154. }
  155. //////////////////////////////////////////////////////////////
  156. //
  157. // OnHScroll
  158. //
  159. void
  160. CSceneLightDialog::OnHScroll
  161. (
  162. UINT nSBCode,
  163. UINT nPos,
  164. CScrollBar* pScrollBar
  165. )
  166. {
  167. // Did the intensity slider send this message or did the color sliders?
  168. if (pScrollBar == GetDlgItem (IDC_INTENSITY_SLIDER)) {
  169. // Update the light's intensity settings
  170. float intensity = ((float)m_IntensitySlider.GetPos ()) / 100.0F;
  171. ::GetCurrentDocument ()->GetSceneLight ()->Set_Intensity (intensity);
  172. } else {
  173. // Are the 3 colors locked together?
  174. if (SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_GETCHECK)) {
  175. // Which color sent this message?
  176. int iCurrentPos = 0;
  177. if (pScrollBar == GetDlgItem (IDC_SLIDER_RED)) {
  178. // Use this color as default
  179. iCurrentPos = m_redSlider.GetPos ();
  180. }
  181. else if (pScrollBar == GetDlgItem (IDC_SLIDER_GREEN)) {
  182. // Use this color as default
  183. iCurrentPos = m_greenSlider.GetPos ();
  184. }
  185. else {
  186. // Use this color as default
  187. iCurrentPos = m_blueSlider.GetPos ();
  188. }
  189. // Make all the sliders the same pos
  190. m_redSlider.SetPos (iCurrentPos);
  191. m_greenSlider.SetPos (iCurrentPos);
  192. m_blueSlider.SetPos (iCurrentPos);
  193. }
  194. // Update the light to reflect the new settings
  195. Vector3 color;
  196. color.X = float(m_redSlider.GetPos ()) / 100.00F;
  197. color.Y = float(m_greenSlider.GetPos ()) / 100.00F;
  198. color.Z = float(m_blueSlider.GetPos ()) / 100.00F;
  199. Update_Light (color);
  200. }
  201. // Allow the base class to process this message
  202. CDialog::OnHScroll (nSBCode, nPos, pScrollBar);
  203. return ;
  204. }
  205. //////////////////////////////////////////////////////////////
  206. //
  207. // OnCancel
  208. //
  209. void
  210. CSceneLightDialog::OnCancel (void)
  211. {
  212. // Get a pointer to the document so we can change the scene light's
  213. // settings and position
  214. CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
  215. if (pCDoc && pCDoc->GetScene ()) {
  216. Vector3 diffuse;
  217. diffuse.X = float(m_InitialRedDiffuse) / 100.00F;
  218. diffuse.Y = float(m_InitialGreenDiffuse) / 100.00F;
  219. diffuse.Z = float(m_InitialBlueDiffuse) / 100.00F;
  220. Vector3 specular;
  221. specular.X = float(m_InitialRedSpecular) / 100.00F;
  222. specular.Y = float(m_InitialGreenSpecular) / 100.00F;
  223. specular.Z = float(m_InitialBlueSpecular) / 100.00F;
  224. // Restore the scene light's color
  225. pCDoc->GetSceneLight ()->Set_Diffuse (diffuse);
  226. pCDoc->GetSceneLight ()->Set_Specular (specular);
  227. // Restore the intensity, attenuation, and distance settings
  228. pCDoc->GetSceneLight ()->Set_Intensity (m_InitialIntensity);
  229. pCDoc->GetSceneLight ()->Set_Far_Attenuation_Range (m_InitialStartAtten, m_InitialEndAtten);
  230. pCDoc->GetSceneLight ()->Set_Flag (LightClass::FAR_ATTENUATION, (m_InitialAttenOn == TRUE));
  231. Update_Distance (m_InitialDistance);
  232. }
  233. // Allow the base class to process this message
  234. CDialog::OnCancel ();
  235. return ;
  236. }
  237. //////////////////////////////////////////////////////////////
  238. //
  239. // WindowProc
  240. //
  241. LRESULT
  242. CSceneLightDialog::WindowProc
  243. (
  244. UINT message,
  245. WPARAM wParam,
  246. LPARAM lParam
  247. )
  248. {
  249. switch (message)
  250. {
  251. case WM_NOTIFY:
  252. {
  253. // Did this notification come from a spin control?
  254. NMHDR *pheader = (NMHDR *)lParam;
  255. if ((pheader != NULL) && (pheader->code == UDN_DELTAPOS)) {
  256. LPNMUPDOWN pupdown = (LPNMUPDOWN)lParam;
  257. // Get the buddy window associated with this spin control
  258. HWND hbuddy_wnd = (HWND)SendDlgItemMessage ((int)wParam, UDM_GETBUDDY);
  259. if (::IsWindow (hbuddy_wnd)) {
  260. // Get the current value, increment it, and put it back into the control
  261. float value = ::GetWindowFloat (hbuddy_wnd);
  262. value += (((float)(pupdown->iDelta)) / 100.0F);
  263. ::SetWindowFloat (hbuddy_wnd, value);
  264. // Force update the light
  265. Update_Distance (::GetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT));
  266. Update_Attenuation ();
  267. }
  268. }
  269. }
  270. break;
  271. case WM_COMMAND:
  272. {
  273. if (HIWORD (wParam) == EN_KILLFOCUS) {
  274. switch (LOWORD (wParam))
  275. {
  276. case IDC_DISTANCE_EDIT:
  277. {
  278. Update_Distance (::GetDlgItemFloat (m_hWnd, IDC_DISTANCE_EDIT));
  279. }
  280. break;
  281. case IDC_START_ATTENUATION_EDIT:
  282. case IDC_END_ATTENUATION_EDIT:
  283. {
  284. Update_Attenuation ();
  285. }
  286. break;
  287. }
  288. }
  289. }
  290. break;
  291. case WM_PAINT:
  292. {
  293. // Paint the gradients for each color
  294. ::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_RED_GRADIENT), 1, 0, 0);
  295. ::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_GREEN_GRADIENT), 0, 1, 0);
  296. ::Paint_Gradient (::GetDlgItem (m_hWnd, IDC_BLUE_GRADIENT), 0, 0, 1);
  297. }
  298. break;
  299. }
  300. // Allow the base class to process this message
  301. return CDialog::WindowProc (message, wParam, lParam);
  302. }
  303. //////////////////////////////////////////////////////////////
  304. //
  305. // OnGrayscaleCheck
  306. //
  307. void
  308. CSceneLightDialog::OnGrayscaleCheck (void)
  309. {
  310. if (SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_GETCHECK)) {
  311. // Make the green and blue sliders the same as red
  312. m_greenSlider.SetPos (m_redSlider.GetPos ());
  313. m_blueSlider.SetPos (m_redSlider.GetPos ());
  314. Vector3 color;
  315. color.X = float(m_redSlider.GetPos ()) / 100.00F;
  316. color.Y = float(m_greenSlider.GetPos ()) / 100.00F;
  317. color.Z = float(m_blueSlider.GetPos ()) / 100.00F;
  318. Update_Light (color);
  319. }
  320. return ;
  321. }
  322. //////////////////////////////////////////////////////////////
  323. //
  324. // OnChannelBothRadio
  325. //
  326. void
  327. CSceneLightDialog::OnChannelBothRadio (void)
  328. {
  329. m_CurrentChannel = BOTH;
  330. return ;
  331. }
  332. //////////////////////////////////////////////////////////////
  333. //
  334. // OnChannelDiffuseRadio
  335. //
  336. void
  337. CSceneLightDialog::OnChannelDiffuseRadio (void)
  338. {
  339. // Reset the UI to reflect the current diffuse color
  340. Vector3 color;
  341. ::GetCurrentDocument ()->GetSceneLight ()->Get_Diffuse (&color);
  342. Set_Color_Control_State (color);
  343. m_CurrentChannel = DIFFUSE;
  344. return ;
  345. }
  346. //////////////////////////////////////////////////////////////
  347. //
  348. // OnChannelSpecularRadio
  349. //
  350. void
  351. CSceneLightDialog::OnChannelSpecularRadio (void)
  352. {
  353. // Reset the UI to reflect the current specular color
  354. Vector3 color;
  355. ::GetCurrentDocument ()->GetSceneLight ()->Get_Specular (&color);
  356. Set_Color_Control_State (color);
  357. m_CurrentChannel = SPECULAR;
  358. return ;
  359. }
  360. //////////////////////////////////////////////////////////////
  361. //
  362. // Update_Light
  363. //
  364. void
  365. CSceneLightDialog::Update_Light (const Vector3 &color)
  366. {
  367. // Get a pointer to the document so we can change the scene light's
  368. // settings
  369. CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
  370. if (pCDoc && pCDoc->GetScene ()) {
  371. // Update the diffuse setting of the scene light if necessary
  372. if (m_CurrentChannel & DIFFUSE) {
  373. pCDoc->GetSceneLight ()->Set_Diffuse (color);
  374. }
  375. // Update the specular setting of the scene light if necessary
  376. if (m_CurrentChannel & SPECULAR) {
  377. pCDoc->GetSceneLight ()->Set_Specular (color);
  378. }
  379. }
  380. return ;
  381. }
  382. //////////////////////////////////////////////////////////////
  383. //
  384. // Set_Color_Control_State
  385. //
  386. void
  387. CSceneLightDialog::Set_Color_Control_State (const Vector3 &color)
  388. {
  389. // Should we 'lock' the color sliders together?
  390. if ((color.X == color.Y) &&
  391. (color.X == color.Z)) {
  392. SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_SETCHECK, (WPARAM)TRUE);
  393. } else {
  394. SendDlgItemMessage (IDC_GRAYSCALE_CHECK, BM_SETCHECK, (WPARAM)FALSE);
  395. }
  396. // Set the color slider positions
  397. m_redSlider.SetPos (int(color.X * 100.0F));
  398. m_greenSlider.SetPos (int(color.Y * 100.0F));
  399. m_blueSlider.SetPos (int(color.Z * 100.0F));
  400. return ;
  401. }
  402. //////////////////////////////////////////////////////////////
  403. //
  404. // Update_Attenuation
  405. //
  406. void
  407. CSceneLightDialog::Update_Attenuation (void)
  408. {
  409. // Get a pointer to the document so we can change the scene light's
  410. // settings
  411. CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
  412. if (pCDoc && pCDoc->GetScene ()) {
  413. // Update the attenuation settings
  414. float start = ::GetDlgItemFloat (m_hWnd, IDC_START_ATTENUATION_EDIT);
  415. float end = ::GetDlgItemFloat (m_hWnd, IDC_END_ATTENUATION_EDIT);
  416. pCDoc->GetSceneLight ()->Set_Far_Attenuation_Range (start, end);
  417. }
  418. return ;
  419. }
  420. //////////////////////////////////////////////////////////////
  421. //
  422. // Update_Distance
  423. //
  424. void
  425. CSceneLightDialog::Update_Distance (float distance)
  426. {
  427. // Get a pointer to the document so we can change the scene light's
  428. // settings
  429. CW3DViewDoc *pCDoc = ::GetCurrentDocument ();
  430. if (pCDoc && pCDoc->GetScene ()) {
  431. // Get the position of the displayed object
  432. Vector3 obj_pos (0,0,0);
  433. if (pCDoc->GetDisplayedObject ()) {
  434. obj_pos = pCDoc->GetDisplayedObject ()->Get_Position ();
  435. }
  436. // Get the position of the light and the displayed object
  437. Vector3 light_pos = pCDoc->GetSceneLight ()->Get_Position ();
  438. Vector3 new_pos = (light_pos - obj_pos);
  439. new_pos.Normalize ();
  440. new_pos = new_pos * distance;
  441. // Update the attenuation settings
  442. pCDoc->GetSceneLight ()->Set_Position (new_pos);
  443. }
  444. return ;
  445. }
  446. //////////////////////////////////////////////////////////////
  447. //
  448. // Update_Attenuation_Controls
  449. //
  450. void
  451. CSceneLightDialog::Update_Attenuation_Controls (void)
  452. {
  453. // Enable or disable the attenuation controls based on the group's checkstate
  454. BOOL enable = (SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_GETCHECK) == 1);
  455. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_START_ATTENUATION_EDIT), enable);
  456. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_START_ATTENUATION_SPIN), enable);
  457. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_END_ATTENUATION_EDIT), enable);
  458. ::EnableWindow (::GetDlgItem (m_hWnd, IDC_END_ATTENUATION_SPIN), enable);
  459. return ;
  460. }
  461. //////////////////////////////////////////////////////////////
  462. //
  463. // OnAttenuationCheck
  464. //
  465. void
  466. CSceneLightDialog::OnAttenuationCheck (void)
  467. {
  468. // Update the scene light to reflect the new setting
  469. bool enable = (SendDlgItemMessage (IDC_ATTENUATION_CHECK, BM_GETCHECK) == 1);
  470. CW3DViewDoc *pdoc = ::GetCurrentDocument ();
  471. pdoc->GetSceneLight ()->Set_Flag (LightClass::FAR_ATTENUATION, enable);
  472. // Update the dialog controls to reflect the new setting
  473. Update_Attenuation_Controls ();
  474. return ;
  475. }