EmitterFramePropPage.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. // EmitterFramePropPage.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "w3dview.h"
  22. #include "EmitterFramePropPage.h"
  23. #include "Utils.H"
  24. #include "ParticleFrameKeyDialog.H"
  25. #include "EmitterInstanceList.H"
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. /////////////////////////////////////////////////////////////////////////////
  32. // EmitterFramePropPageClass property page
  33. IMPLEMENT_DYNCREATE(EmitterFramePropPageClass, CPropertyPage)
  34. /////////////////////////////////////////////////////////////
  35. //
  36. // EmitterFramePropPageClass - constructor
  37. //
  38. /////////////////////////////////////////////////////////////
  39. EmitterFramePropPageClass::EmitterFramePropPageClass() :
  40. CPropertyPage(EmitterFramePropPageClass::IDD),
  41. m_pEmitterList(NULL),
  42. m_bValid(true),
  43. m_FrameBar(NULL),
  44. m_Lifetime(0),
  45. m_MinFrame(0),
  46. m_MaxFrame(1)
  47. {
  48. ::memset (&m_Frames, 0, sizeof (m_Frames));
  49. //{{AFX_DATA_INIT(EmitterFramePropPageClass)
  50. //}}AFX_DATA_INIT
  51. Initialize();
  52. }
  53. /////////////////////////////////////////////////////////////
  54. //
  55. // ~EmitterFramePropPageClass - destructor
  56. //
  57. /////////////////////////////////////////////////////////////
  58. EmitterFramePropPageClass::~EmitterFramePropPageClass()
  59. {
  60. // Free the frame arrays
  61. SAFE_DELETE_ARRAY (m_Frames.KeyTimes);
  62. SAFE_DELETE_ARRAY (m_Frames.Values);
  63. }
  64. /////////////////////////////////////////////////////////////
  65. //
  66. // DoDataExchange
  67. //
  68. /////////////////////////////////////////////////////////////
  69. void EmitterFramePropPageClass::DoDataExchange(CDataExchange* pDX)
  70. {
  71. CPropertyPage::DoDataExchange(pDX);
  72. //{{AFX_DATA_MAP(EmitterFramePropPageClass)
  73. DDX_Control(pDX, IDC_FRAME_LAYOUT_COMBO, m_FrameLayoutCombo);
  74. DDX_Control(pDX, IDC_FRAME_RANDOM_SPIN, m_FrameRandomSpin);
  75. //}}AFX_DATA_MAP
  76. }
  77. BEGIN_MESSAGE_MAP(EmitterFramePropPageClass, CPropertyPage)
  78. //{{AFX_MSG_MAP(EmitterFramePropPageClass)
  79. //}}AFX_MSG_MAP
  80. END_MESSAGE_MAP()
  81. /////////////////////////////////////////////////////////////
  82. //
  83. // Initialize
  84. //
  85. /////////////////////////////////////////////////////////////
  86. void
  87. EmitterFramePropPageClass::Initialize (void)
  88. {
  89. SAFE_DELETE_ARRAY (m_Frames.KeyTimes);
  90. SAFE_DELETE_ARRAY (m_Frames.Values);
  91. if (m_pEmitterList != NULL) {
  92. m_Lifetime = m_pEmitterList->Get_Lifetime ();
  93. m_pEmitterList->Get_Frame_Keyframes (m_Frames);
  94. //
  95. // Determine what the min and max rotations are
  96. //
  97. m_MaxFrame = WWMath::Max(m_Frames.Start,1.0f);
  98. m_MinFrame = WWMath::Min(m_Frames.Start,0.0f);
  99. for (UINT index = 0; index < m_Frames.NumKeyFrames; index ++) {
  100. if (m_Frames.Values[index] > m_MaxFrame) {
  101. m_MaxFrame = m_Frames.Values[index];
  102. }
  103. if (m_Frames.Values[index] < m_MinFrame) {
  104. m_MinFrame = m_Frames.Values[index];
  105. }
  106. }
  107. }
  108. return ;
  109. }
  110. /////////////////////////////////////////////////////////////
  111. //
  112. // OnInitDialog
  113. //
  114. /////////////////////////////////////////////////////////////
  115. BOOL
  116. EmitterFramePropPageClass::OnInitDialog()
  117. {
  118. CPropertyPage::OnInitDialog();
  119. //
  120. // Set the frame layout combo box
  121. //
  122. int mode = m_pEmitterList->Get_Frame_Mode();
  123. switch (mode) {
  124. case W3D_EMITTER_FRAME_MODE_1x1: m_FrameLayoutCombo.SetCurSel(0); break;
  125. case W3D_EMITTER_FRAME_MODE_2x2: m_FrameLayoutCombo.SetCurSel(1); break;
  126. case W3D_EMITTER_FRAME_MODE_4x4: m_FrameLayoutCombo.SetCurSel(2); break;
  127. case W3D_EMITTER_FRAME_MODE_8x8: m_FrameLayoutCombo.SetCurSel(3); break;
  128. case W3D_EMITTER_FRAME_MODE_16x16: m_FrameLayoutCombo.SetCurSel(4); break;
  129. default:
  130. m_FrameLayoutCombo.SetCurSel(4);
  131. break;
  132. }
  133. //
  134. // Create the keyframe control
  135. //
  136. m_FrameBar = ColorBarClass::Get_Color_Bar (::GetDlgItem (m_hWnd, IDC_FRAME_BAR));
  137. //
  138. // Setup the spinners
  139. //
  140. Initialize_Spinner (m_FrameRandomSpin, m_Frames.Rand, 0, 10000);
  141. //
  142. // Reset the keyframe control
  143. //
  144. m_FrameBar->Set_Range (0, 1);
  145. m_FrameBar->Clear_Points ();
  146. m_FrameBar->Modify_Point (0, 0, 0, 0, 0);
  147. m_FrameBar->Set_Graph_Percent (0, Normalize_Frame(m_Frames.Start));
  148. //
  149. // Load the current set of frame keyframes into the control
  150. //
  151. for (UINT index = 0; index < m_Frames.NumKeyFrames; index ++) {
  152. m_FrameBar->Modify_Point (index + 1,
  153. m_Frames.KeyTimes[index] / m_Lifetime,
  154. 0,
  155. 0,
  156. 0);
  157. m_FrameBar->Set_Graph_Percent (index + 1, Normalize_Frame(m_Frames.Values[index]));
  158. }
  159. return TRUE; // return TRUE unless you set the focus to a control
  160. // EXCEPTION: OCX Property Pages should return FALSE
  161. }
  162. /////////////////////////////////////////////////////////////
  163. //
  164. // OnApply
  165. //
  166. /////////////////////////////////////////////////////////////
  167. BOOL EmitterFramePropPageClass::OnApply()
  168. {
  169. return CPropertyPage::OnApply();
  170. }
  171. /////////////////////////////////////////////////////////////
  172. //
  173. // OnNotify
  174. //
  175. /////////////////////////////////////////////////////////////
  176. BOOL EmitterFramePropPageClass::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  177. {
  178. CBR_NMHDR *color_bar_hdr = (CBR_NMHDR *)lParam;
  179. //
  180. // Update the spinner controls if necessary
  181. //
  182. NMHDR *pheader = (NMHDR *)lParam;
  183. if ((pheader != NULL) && (pheader->code == UDN_DELTAPOS)) {
  184. LPNMUPDOWN pupdown = (LPNMUPDOWN)lParam;
  185. ::Update_Spinner_Buddy (pheader->hwndFrom, pupdown->iDelta);
  186. }
  187. //
  188. // Which control sent the notification?
  189. //
  190. switch (color_bar_hdr->hdr.idFrom)
  191. {
  192. case IDC_FRAME_BAR:
  193. {
  194. if (color_bar_hdr->hdr.code == CBRN_DBLCLK_POINT) {
  195. //
  196. // Allow the user to edit the keyframe
  197. //
  198. float frame = Denormalize_Frame(m_FrameBar->Get_Graph_Percent (color_bar_hdr->key_index));
  199. ParticleFrameKeyDialogClass dialog (frame, this);
  200. if (dialog.DoModal () == IDOK) {
  201. frame = dialog.Get_Frame ();
  202. float norm_val = Normalize_Frame(frame);
  203. m_FrameBar->Set_Redraw (false);
  204. m_FrameBar->Set_Graph_Percent (color_bar_hdr->key_index, norm_val);
  205. //
  206. // Determine if the user changed the 'max' or 'min' frame
  207. //
  208. float new_max = WWMath::Max(frame,1.0f);
  209. float new_min = WWMath::Min(frame,0.0f);
  210. int count = m_FrameBar->Get_Point_Count ();
  211. for (int index = 0; index < count; index ++) {
  212. float tmp = Denormalize_Frame(m_FrameBar->Get_Graph_Percent (index) );
  213. if (tmp > new_max) {
  214. new_max = tmp;
  215. }
  216. if (tmp < new_min) {
  217. new_min = tmp;
  218. }
  219. }
  220. //
  221. // Renormalize the FrameBar key frame points if necessary
  222. //
  223. if ((new_max != m_MaxFrame) || (new_min != m_MinFrame)) {
  224. int count = m_FrameBar->Get_Point_Count ();
  225. for (int index = 0; index < count; index ++) {
  226. float frame = Denormalize_Frame(m_FrameBar->Get_Graph_Percent (index));
  227. float new_norm = Normalize_Frame(frame,new_min,new_max);
  228. m_FrameBar->Set_Graph_Percent (index, new_norm);
  229. }
  230. // Remember the new min and max
  231. m_MinFrame = new_min;
  232. m_MaxFrame = new_max;
  233. }
  234. m_FrameBar->Set_Redraw (true);
  235. //
  236. // Update the emitter
  237. //
  238. Update_Frames ();
  239. m_pEmitterList->Set_Frame_Keyframes (m_Frames);
  240. SetModified ();
  241. }
  242. } else if ((color_bar_hdr->hdr.code == CBRN_MOVING_POINT) ||
  243. (color_bar_hdr->hdr.code == CBRN_DELETED_POINT)) {
  244. //
  245. // Update the emitter
  246. //
  247. Update_Frames ();
  248. m_pEmitterList->Set_Frame_Keyframes (m_Frames);
  249. SetModified ();
  250. }
  251. }
  252. break;
  253. case IDC_FRAME_RANDOM_SPIN:
  254. {
  255. // Update the emitter
  256. m_Frames.Rand = ::GetDlgItemFloat (m_hWnd, IDC_FRAME_RANDOM_EDIT);
  257. m_pEmitterList->Set_Frame_Keyframes (m_Frames);
  258. SetModified ();
  259. }
  260. break;
  261. }
  262. return CPropertyPage::OnNotify(wParam, lParam, pResult);
  263. }
  264. /////////////////////////////////////////////////////////////
  265. //
  266. // Update_Rotations
  267. //
  268. /////////////////////////////////////////////////////////////
  269. void
  270. EmitterFramePropPageClass::Update_Frames (void)
  271. {
  272. float position = 0;
  273. float red = 0;
  274. float green = 0;
  275. float blue = 0;
  276. //
  277. // Setup the initial or 'starting' size
  278. //
  279. m_Frames.Start = Denormalize_Frame(m_FrameBar->Get_Graph_Percent (0));
  280. //
  281. // Free the current setting arrays
  282. //
  283. SAFE_DELETE_ARRAY (m_Frames.KeyTimes);
  284. SAFE_DELETE_ARRAY (m_Frames.Values);
  285. //
  286. // Determine if we need to build the array of key frames or not
  287. //
  288. int count = m_FrameBar->Get_Point_Count ();
  289. m_Frames.NumKeyFrames = count - 1;
  290. if (count > 1) {
  291. m_Frames.KeyTimes = new float[count - 1];
  292. m_Frames.Values = new float[count - 1];
  293. //
  294. // Get all the key frames and add them to our structure
  295. //
  296. for (int index = 1; index < count; index ++) {
  297. m_FrameBar->Get_Point (index, &position, &red, &green, &blue);
  298. m_Frames.KeyTimes[index - 1] = position * m_Lifetime;
  299. m_Frames.Values[index - 1] = Denormalize_Frame(m_FrameBar->Get_Graph_Percent (index) );
  300. }
  301. }
  302. return ;
  303. }
  304. /////////////////////////////////////////////////////////////
  305. //
  306. // OnCommand
  307. //
  308. /////////////////////////////////////////////////////////////
  309. BOOL
  310. EmitterFramePropPageClass::OnCommand(WPARAM wParam, LPARAM lParam)
  311. {
  312. switch (LOWORD (wParam))
  313. {
  314. case IDC_FRAME_RANDOM_EDIT:
  315. {
  316. // Update the emitter
  317. if ((HIWORD (wParam) == EN_KILLFOCUS) &&
  318. SendDlgItemMessage (LOWORD (wParam), EM_GETMODIFY))
  319. {
  320. SendDlgItemMessage (LOWORD (wParam), EM_SETMODIFY, (WPARAM)0);
  321. m_Frames.Rand = ::GetDlgItemFloat (m_hWnd, IDC_FRAME_RANDOM_EDIT);
  322. m_pEmitterList->Set_Frame_Keyframes (m_Frames);
  323. SetModified ();
  324. } else if (HIWORD (wParam) == EN_CHANGE) {
  325. SetModified ();
  326. }
  327. }
  328. case IDC_FRAME_LAYOUT_COMBO:
  329. if (HIWORD(wParam) == CBN_SELCHANGE) {
  330. m_pEmitterList->Set_Frame_Mode(m_FrameLayoutCombo.GetCurSel());
  331. SetModified();
  332. }
  333. break;
  334. }
  335. return CPropertyPage::OnCommand(wParam, lParam);
  336. }
  337. /////////////////////////////////////////////////////////////
  338. //
  339. // On_Lifetime_Changed
  340. //
  341. /////////////////////////////////////////////////////////////
  342. void
  343. EmitterFramePropPageClass::On_Lifetime_Changed (float lifetime)
  344. {
  345. if (m_Lifetime != lifetime) {
  346. float conversion = lifetime / m_Lifetime;
  347. //
  348. // Rescale the sizes
  349. //
  350. for (UINT index = 0; index < m_Frames.NumKeyFrames; index ++) {
  351. m_Frames.KeyTimes[index] *= conversion;
  352. }
  353. //
  354. // Update the emitter
  355. //
  356. m_pEmitterList->Set_Frame_Keyframes (m_Frames);
  357. m_Lifetime = lifetime;
  358. }
  359. return ;
  360. }