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