RingSizePropPage.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  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. // RingSizePropPage.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "w3dview.h"
  22. #include "ringsizeproppage.h"
  23. #include "colorutils.h"
  24. #include "utils.h"
  25. #include "scaledialog.h"
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. IMPLEMENT_DYNCREATE(RingSizePropPageClass, CPropertyPage)
  32. /////////////////////////////////////////////////////////////
  33. // Local prototypes
  34. /////////////////////////////////////////////////////////////
  35. static bool Is_LERP (float last_value, float last_time, float curr_value, float curr_time, float next_value, float next_time);
  36. /////////////////////////////////////////////////////////////
  37. //
  38. // RingSizePropPageClass
  39. //
  40. /////////////////////////////////////////////////////////////
  41. RingSizePropPageClass::RingSizePropPageClass (RingRenderObjClass *ring)
  42. : m_RenderObj (ring),
  43. m_bValid (true),
  44. m_InnerScaleXBar (NULL),
  45. m_InnerScaleYBar (NULL),
  46. m_OuterScaleXBar (NULL),
  47. m_OuterScaleYBar (NULL),
  48. m_InnerSize (0.5F, 0.5F),
  49. m_OuterSize (1.0F, 1.0F),
  50. CPropertyPage(RingSizePropPageClass::IDD)
  51. {
  52. //{{AFX_DATA_INIT(RingSizePropPageClass)
  53. // NOTE: the ClassWizard will add member initialization here
  54. //}}AFX_DATA_INIT
  55. Initialize ();
  56. return ;
  57. }
  58. /////////////////////////////////////////////////////////////
  59. //
  60. // ~RingSizePropPageClass
  61. //
  62. /////////////////////////////////////////////////////////////
  63. RingSizePropPageClass::~RingSizePropPageClass (void)
  64. {
  65. return ;
  66. }
  67. /////////////////////////////////////////////////////////////
  68. //
  69. // DoDataExchange
  70. //
  71. /////////////////////////////////////////////////////////////
  72. void
  73. RingSizePropPageClass::DoDataExchange (CDataExchange* pDX)
  74. {
  75. CPropertyPage::DoDataExchange(pDX);
  76. //{{AFX_DATA_MAP(RingSizePropPageClass)
  77. DDX_Control(pDX, IDC_INNER_SIZE_X_SPIN, m_InnerSizeXSpin);
  78. DDX_Control(pDX, IDC_INNER_SIZE_Y_SPIN, m_InnerSizeYSpin);
  79. DDX_Control(pDX, IDC_OUTER_SIZE_X_SPIN, m_OuterSizeXSpin);
  80. DDX_Control(pDX, IDC_OUTER_SIZE_Y_SPIN, m_OuterSizeYSpin);
  81. //}}AFX_DATA_MAP
  82. return ;
  83. }
  84. BEGIN_MESSAGE_MAP(RingSizePropPageClass, CPropertyPage)
  85. //{{AFX_MSG_MAP(RingSizePropPageClass)
  86. ON_WM_DESTROY()
  87. //}}AFX_MSG_MAP
  88. END_MESSAGE_MAP()
  89. /////////////////////////////////////////////////////////////
  90. //
  91. // Initialize
  92. //
  93. /////////////////////////////////////////////////////////////
  94. void
  95. RingSizePropPageClass::Initialize (void)
  96. {
  97. m_InnerScaleChannel.Reset ();
  98. m_OrigInnerScaleChannel.Reset ();
  99. m_OuterScaleChannel.Reset ();
  100. m_OrigOuterScaleChannel.Reset ();
  101. if (m_RenderObj != NULL) {
  102. m_InnerSize = m_RenderObj->Get_Inner_Extent ();
  103. m_OuterSize = m_RenderObj->Get_Outer_Extent ();
  104. m_InnerScaleChannel = m_RenderObj->Get_Inner_Scale_Channel ();
  105. m_OrigInnerScaleChannel = m_RenderObj->Get_Inner_Scale_Channel ();
  106. m_OuterScaleChannel = m_RenderObj->Get_Outer_Scale_Channel ();
  107. m_OrigOuterScaleChannel = m_RenderObj->Get_Outer_Scale_Channel ();
  108. if (m_OrigInnerScaleChannel.Get_Key_Count () == 0) {
  109. m_InnerScaleChannel.Add_Key (m_RenderObj->Get_Inner_Scale (), 0);
  110. m_OrigInnerScaleChannel.Add_Key (m_RenderObj->Get_Inner_Scale (), 0);
  111. }
  112. if (m_OrigOuterScaleChannel.Get_Key_Count () == 0) {
  113. m_OuterScaleChannel.Add_Key (m_RenderObj->Get_Outer_Scale (), 0);
  114. m_OrigOuterScaleChannel.Add_Key (m_RenderObj->Get_Outer_Scale (), 0);
  115. }
  116. }
  117. return ;
  118. }
  119. /////////////////////////////////////////////////////////////
  120. //
  121. // OnInitDialog
  122. //
  123. /////////////////////////////////////////////////////////////
  124. BOOL
  125. RingSizePropPageClass::OnInitDialog (void)
  126. {
  127. // Allow the base class to process this message
  128. CPropertyPage::OnInitDialog ();
  129. m_InnerScaleXBar = ColorBarClass::Get_Color_Bar (::GetDlgItem (m_hWnd, IDC_INNER_SCALE_BAR_X));
  130. m_InnerScaleYBar = ColorBarClass::Get_Color_Bar (::GetDlgItem (m_hWnd, IDC_INNER_SCALE_BAR_Y));
  131. m_OuterScaleXBar = ColorBarClass::Get_Color_Bar (::GetDlgItem (m_hWnd, IDC_OUTER_SCALE_BAR_X));
  132. m_OuterScaleYBar = ColorBarClass::Get_Color_Bar (::GetDlgItem (m_hWnd, IDC_OUTER_SCALE_BAR_Y));
  133. //
  134. // Setup the spinners
  135. //
  136. ::Initialize_Spinner (m_InnerSizeXSpin, m_InnerSize.X, 0, 10000);
  137. ::Initialize_Spinner (m_InnerSizeYSpin, m_InnerSize.Y, 0, 10000);
  138. ::Initialize_Spinner (m_OuterSizeXSpin, m_OuterSize.X, 0, 10000);
  139. ::Initialize_Spinner (m_OuterSizeYSpin, m_OuterSize.Y, 0, 10000);
  140. //
  141. // Setup the timelines
  142. //
  143. m_InnerScaleXBar->Set_Range (0, 1);
  144. m_InnerScaleYBar->Set_Range (0, 1);
  145. m_OuterScaleXBar->Set_Range (0, 1);
  146. m_OuterScaleYBar->Set_Range (0, 1);
  147. //
  148. // Insert the starting points
  149. //
  150. m_InnerScaleXBar->Modify_Point (0, 0, 0, 0, 0);
  151. m_InnerScaleYBar->Modify_Point (0, 0, 0, 0, 0);
  152. m_OuterScaleXBar->Modify_Point (0, 0, 0, 0, 0);
  153. m_OuterScaleYBar->Modify_Point (0, 0, 0, 0, 0);
  154. m_InnerScaleXBar->Set_Graph_Percent (0, m_OrigInnerScaleChannel[0].Get_Value ().X);
  155. m_InnerScaleYBar->Set_Graph_Percent (0, m_OrigInnerScaleChannel[0].Get_Value ().Y);
  156. m_OuterScaleXBar->Set_Graph_Percent (0, m_OrigOuterScaleChannel[0].Get_Value ().X);
  157. m_OuterScaleYBar->Set_Graph_Percent (0, m_OrigOuterScaleChannel[0].Get_Value ().Y);
  158. //
  159. // Set-up the inner-scale timelines
  160. //
  161. int x_index = 1;
  162. int y_index = 1;
  163. for (int index = 1; index < m_OrigInnerScaleChannel.Get_Key_Count (); index ++) {
  164. const LERPAnimationChannelClass<Vector2>::KeyClass &prev_value = m_OrigInnerScaleChannel.Get_Key (index - 1);
  165. const LERPAnimationChannelClass<Vector2>::KeyClass &curr_value = m_OrigInnerScaleChannel.Get_Key (index);
  166. //
  167. // Find out which channels are unique (we toss the others)
  168. //
  169. bool unique_x = false;
  170. bool unique_y = false;
  171. if (index == (m_OrigInnerScaleChannel.Get_Key_Count () - 1)) {
  172. unique_x = (curr_value.Get_Value ().X != prev_value.Get_Value ().X);
  173. unique_y = (curr_value.Get_Value ().Y != prev_value.Get_Value ().Y);
  174. } else {
  175. const LERPAnimationChannelClass<Vector2>::KeyClass &next_value = m_OrigInnerScaleChannel[index + 1];
  176. //
  177. // Check to ensure the X-value isn't just a LERP of the 2 adjacent keys.
  178. //
  179. unique_x = (::Is_LERP ( prev_value.Get_Value ().X,
  180. prev_value.Get_Time (),
  181. curr_value.Get_Value ().X,
  182. curr_value.Get_Time (),
  183. next_value.Get_Value ().X,
  184. next_value.Get_Time ()) == false);
  185. //
  186. // Check to ensure the Y-value isn't just a LERP of the 2 adjacent keys.
  187. //
  188. unique_y = (::Is_LERP ( prev_value.Get_Value ().Y,
  189. prev_value.Get_Time (),
  190. curr_value.Get_Value ().Y,
  191. curr_value.Get_Time (),
  192. next_value.Get_Value ().Y,
  193. next_value.Get_Time ()) == false);
  194. }
  195. //
  196. // Insert a key for each unique axis
  197. //
  198. if (unique_x) {
  199. m_InnerScaleXBar->Modify_Point (x_index, curr_value.Get_Time (), 0, 0, 0);
  200. m_InnerScaleXBar->Set_Graph_Percent (x_index, curr_value.Get_Value ().X);
  201. x_index ++;
  202. }
  203. if (unique_y) {
  204. m_InnerScaleYBar->Modify_Point (y_index, curr_value.Get_Time (), 0, 0, 0);
  205. m_InnerScaleYBar->Set_Graph_Percent (y_index, curr_value.Get_Value ().Y);
  206. y_index ++;
  207. }
  208. // One of the keys MUST be unique...
  209. ASSERT (unique_x || unique_y);
  210. }
  211. //
  212. // Set-up the outer-scale timelines
  213. //
  214. x_index = 1;
  215. y_index = 1;
  216. for (index = 1; index < m_OrigOuterScaleChannel.Get_Key_Count (); index ++) {
  217. const LERPAnimationChannelClass<Vector2>::KeyClass &prev_value = m_OrigOuterScaleChannel.Get_Key (index - 1);
  218. const LERPAnimationChannelClass<Vector2>::KeyClass &curr_value = m_OrigOuterScaleChannel.Get_Key (index);
  219. //
  220. // Find out which channels are unique (we toss the others)
  221. //
  222. bool unique_x = false;
  223. bool unique_y = false;
  224. if (index == (m_OrigOuterScaleChannel.Get_Key_Count () - 1)) {
  225. unique_x = (curr_value.Get_Value ().X != prev_value.Get_Value ().X);
  226. unique_y = (curr_value.Get_Value ().Y != prev_value.Get_Value ().Y);
  227. } else {
  228. const LERPAnimationChannelClass<Vector2>::KeyClass &next_value = m_OrigOuterScaleChannel[index + 1];
  229. //
  230. // Check to ensure the X-value isn't just a LERP of the 2 adjacent keys.
  231. //
  232. unique_x = (::Is_LERP ( prev_value.Get_Value ().X,
  233. prev_value.Get_Time (),
  234. curr_value.Get_Value ().X,
  235. curr_value.Get_Time (),
  236. next_value.Get_Value ().X,
  237. next_value.Get_Time ()) == false);
  238. //
  239. // Check to ensure the Y-value isn't just a LERP of the 2 adjacent keys.
  240. //
  241. unique_y = (::Is_LERP ( prev_value.Get_Value ().Y,
  242. prev_value.Get_Time (),
  243. curr_value.Get_Value ().Y,
  244. curr_value.Get_Time (),
  245. next_value.Get_Value ().Y,
  246. next_value.Get_Time ()) == false);
  247. }
  248. //
  249. // Insert a key for each unique axis
  250. //
  251. if (unique_x) {
  252. m_OuterScaleXBar->Modify_Point (x_index, curr_value.Get_Time (), 0, 0, 0);
  253. m_OuterScaleXBar->Set_Graph_Percent (x_index, curr_value.Get_Value ().X);
  254. x_index ++;
  255. }
  256. if (unique_y) {
  257. m_OuterScaleYBar->Modify_Point (y_index, curr_value.Get_Time (), 0, 0, 0);
  258. m_OuterScaleYBar->Set_Graph_Percent (y_index, curr_value.Get_Value ().Y);
  259. y_index ++;
  260. }
  261. // One of the keys MUST be unique...
  262. ASSERT (unique_x || unique_y);
  263. }
  264. //
  265. // Ensure our initial 'current' values are up-to-date
  266. //
  267. Update_Inner_Scale_Array ();
  268. Update_Outer_Scale_Array ();
  269. return TRUE;
  270. }
  271. /////////////////////////////////////////////////////////////
  272. //
  273. // OnApply
  274. //
  275. /////////////////////////////////////////////////////////////
  276. BOOL
  277. RingSizePropPageClass::OnApply (void)
  278. {
  279. // Allow the base class to process this message
  280. return CPropertyPage::OnApply ();
  281. }
  282. /////////////////////////////////////////////////////////////
  283. //
  284. // OnDestroy
  285. //
  286. /////////////////////////////////////////////////////////////
  287. void
  288. RingSizePropPageClass::OnDestroy (void)
  289. {
  290. CPropertyPage::OnDestroy();
  291. return ;
  292. }
  293. /////////////////////////////////////////////////////////////
  294. //
  295. // OnNotify
  296. //
  297. /////////////////////////////////////////////////////////////
  298. BOOL
  299. RingSizePropPageClass::OnNotify
  300. (
  301. WPARAM wParam,
  302. LPARAM lParam,
  303. LRESULT *pResult
  304. )
  305. {
  306. CBR_NMHDR *color_bar_hdr = (CBR_NMHDR *)lParam;
  307. //
  308. // Which control sent the notification?
  309. //
  310. switch (color_bar_hdr->hdr.idFrom)
  311. {
  312. case IDC_INNER_SCALE_BAR_X:
  313. case IDC_INNER_SCALE_BAR_Y:
  314. case IDC_OUTER_SCALE_BAR_X:
  315. case IDC_OUTER_SCALE_BAR_Y:
  316. {
  317. //
  318. // Determine the timeline bar which sent the notification
  319. //
  320. ColorBarClass *timeline = NULL;
  321. if (color_bar_hdr->hdr.idFrom == IDC_INNER_SCALE_BAR_X) {
  322. timeline = m_InnerScaleXBar;
  323. } else if (color_bar_hdr->hdr.idFrom == IDC_INNER_SCALE_BAR_Y) {
  324. timeline = m_InnerScaleYBar;
  325. } else if (color_bar_hdr->hdr.idFrom == IDC_OUTER_SCALE_BAR_X) {
  326. timeline = m_OuterScaleXBar;
  327. } else if (color_bar_hdr->hdr.idFrom == IDC_OUTER_SCALE_BAR_Y) {
  328. timeline = m_OuterScaleYBar;
  329. }
  330. bool update = (color_bar_hdr->hdr.code == CBRN_MOVING_POINT) ||
  331. (color_bar_hdr->hdr.code == CBRN_DELETED_POINT);
  332. if (color_bar_hdr->hdr.code == CBRN_DBLCLK_POINT) {
  333. //
  334. // Allow the user to edit the keyframe
  335. //
  336. float scale = timeline->Get_Graph_Percent (color_bar_hdr->key_index);
  337. ScaleDialogClass dialog (scale, this);
  338. if (dialog.DoModal () == IDOK) {
  339. //
  340. // Update the timeline
  341. //
  342. timeline->Set_Graph_Percent (color_bar_hdr->key_index, dialog.Get_Scale ());
  343. update = true;
  344. }
  345. }
  346. //
  347. // Update the object
  348. //
  349. if (update) {
  350. if ( color_bar_hdr->hdr.idFrom == IDC_INNER_SCALE_BAR_X ||
  351. color_bar_hdr->hdr.idFrom == IDC_INNER_SCALE_BAR_Y)
  352. {
  353. Update_Inner_Scale_Array ();
  354. } else if ( color_bar_hdr->hdr.idFrom == IDC_OUTER_SCALE_BAR_X ||
  355. color_bar_hdr->hdr.idFrom == IDC_OUTER_SCALE_BAR_Y)
  356. {
  357. Update_Outer_Scale_Array ();
  358. }
  359. SetModified ();
  360. }
  361. }
  362. break;
  363. case IDC_INNER_SIZE_X_SPIN:
  364. case IDC_INNER_SIZE_Y_SPIN:
  365. {
  366. // Update the object
  367. m_InnerSize.X = ::GetDlgItemFloat (m_hWnd, IDC_INNER_SIZE_X_EDIT);
  368. m_InnerSize.Y = ::GetDlgItemFloat (m_hWnd, IDC_INNER_SIZE_Y_EDIT);
  369. m_RenderObj->Set_Inner_Extent (m_InnerSize);
  370. SetModified ();
  371. }
  372. break;
  373. case IDC_OUTER_SIZE_X_SPIN:
  374. case IDC_OUTER_SIZE_Y_SPIN:
  375. {
  376. // Update the object
  377. m_OuterSize.X = ::GetDlgItemFloat (m_hWnd, IDC_OUTER_SIZE_X_EDIT);
  378. m_OuterSize.Y = ::GetDlgItemFloat (m_hWnd, IDC_OUTER_SIZE_Y_EDIT);
  379. m_RenderObj->Set_Outer_Extent (m_OuterSize);
  380. SetModified ();
  381. }
  382. break;
  383. }
  384. return CPropertyPage::OnNotify (wParam, lParam, pResult);
  385. }
  386. /////////////////////////////////////////////////////////////
  387. //
  388. // OnCommand
  389. //
  390. /////////////////////////////////////////////////////////////
  391. BOOL
  392. RingSizePropPageClass::OnCommand
  393. (
  394. WPARAM wParam,
  395. LPARAM lParam
  396. )
  397. {
  398. switch (LOWORD (wParam))
  399. {
  400. case IDC_INNER_SIZE_X_EDIT:
  401. case IDC_INNER_SIZE_Y_EDIT:
  402. {
  403. // Update the object
  404. if ((HIWORD (wParam) == EN_KILLFOCUS) &&
  405. SendDlgItemMessage (LOWORD (wParam), EM_GETMODIFY))
  406. {
  407. SendDlgItemMessage (LOWORD (wParam), EM_SETMODIFY, (WPARAM)0);
  408. // Update the object
  409. m_InnerSize.X = ::GetDlgItemFloat (m_hWnd, IDC_INNER_SIZE_X_EDIT);
  410. m_InnerSize.Y = ::GetDlgItemFloat (m_hWnd, IDC_INNER_SIZE_Y_EDIT);
  411. m_RenderObj->Set_Inner_Extent (m_InnerSize);
  412. SetModified ();
  413. } else if (HIWORD (wParam) == EN_CHANGE) {
  414. SetModified ();
  415. }
  416. }
  417. break;
  418. case IDC_OUTER_SIZE_X_EDIT:
  419. case IDC_OUTER_SIZE_Y_EDIT:
  420. {
  421. // Update the object
  422. if ((HIWORD (wParam) == EN_KILLFOCUS) &&
  423. SendDlgItemMessage (LOWORD (wParam), EM_GETMODIFY))
  424. {
  425. SendDlgItemMessage (LOWORD (wParam), EM_SETMODIFY, (WPARAM)0);
  426. // Update the object
  427. m_OuterSize.X = ::GetDlgItemFloat (m_hWnd, IDC_OUTER_SIZE_X_EDIT);
  428. m_OuterSize.Y = ::GetDlgItemFloat (m_hWnd, IDC_OUTER_SIZE_Y_EDIT);
  429. m_RenderObj->Set_Outer_Extent (m_OuterSize);
  430. SetModified ();
  431. } else if (HIWORD (wParam) == EN_CHANGE) {
  432. SetModified ();
  433. }
  434. }
  435. break;
  436. }
  437. return CPropertyPage::OnCommand (wParam, lParam);
  438. }
  439. /////////////////////////////////////////////////////////////
  440. //
  441. // OnCancel
  442. //
  443. /////////////////////////////////////////////////////////////
  444. void
  445. RingSizePropPageClass::OnCancel (void)
  446. {
  447. //
  448. // Reset the object to its original state
  449. //
  450. m_RenderObj->Set_Inner_Scale_Channel (m_OrigInnerScaleChannel);
  451. m_RenderObj->Set_Outer_Scale_Channel (m_OrigOuterScaleChannel);
  452. CPropertyPage::OnCancel ();
  453. return ;
  454. }
  455. /////////////////////////////////////////////////////////////
  456. //
  457. // Update_Inner_Scale_Array
  458. //
  459. /////////////////////////////////////////////////////////////
  460. void
  461. RingSizePropPageClass::Update_Inner_Scale_Array (void)
  462. {
  463. m_InnerScaleChannel.Reset ();
  464. float position = 0;
  465. float red = 0;
  466. float green = 0;
  467. float blue = 0;
  468. //
  469. // Allocate arrays we can store the 3 separate timelines in
  470. //
  471. int max_x = m_InnerScaleXBar->Get_Point_Count ();
  472. int max_y = m_InnerScaleYBar->Get_Point_Count ();
  473. LERPAnimationChannelClass<float> x_values;
  474. LERPAnimationChannelClass<float> y_values;
  475. //
  476. // Build the X-axis timline
  477. //
  478. for (int index = 0; index < max_x; index++) {
  479. m_InnerScaleXBar->Get_Point (index, &position, &red, &green, &blue);
  480. x_values.Add_Key (m_InnerScaleXBar->Get_Graph_Percent (index), position);
  481. }
  482. //
  483. // Build the Y-axis timline
  484. //
  485. for (index = 0; index < max_y; index++) {
  486. m_InnerScaleYBar->Get_Point (index, &position, &red, &green, &blue);
  487. y_values.Add_Key (m_InnerScaleYBar->Get_Graph_Percent (index), position);
  488. }
  489. //
  490. // Combine the 3 separate time lines into one time line
  491. //
  492. int x_index = 0;
  493. int y_index = 0;
  494. int list_index = 0;
  495. float x_val = x_values[0].Get_Value ();
  496. float y_val = y_values[0].Get_Value ();
  497. while ( x_index < max_x ||
  498. y_index < max_y)
  499. {
  500. //
  501. // Find the smallest time
  502. //
  503. float time = 2.0F;
  504. float x_time = time;
  505. float y_time = time;
  506. if (x_index < max_x) {
  507. x_time = x_values[x_index].Get_Time ();
  508. }
  509. if (y_index < max_y) {
  510. y_time = y_values[y_index].Get_Time ();
  511. }
  512. time = min (x_time, time);
  513. time = min (y_time, time);
  514. if (x_time == time) {
  515. x_index ++;
  516. }
  517. if (y_time == time) {
  518. y_index ++;
  519. }
  520. //
  521. // Evaluate X
  522. //
  523. x_val = x_values.Evaluate (time);
  524. y_val = y_values.Evaluate (time);
  525. //
  526. // Add this scalar to the list
  527. //
  528. m_InnerScaleChannel.Add_Key (Vector2 (x_val, y_val), time);
  529. }
  530. //
  531. // Update the object
  532. //
  533. m_RenderObj->Set_Inner_Scale_Channel (m_InnerScaleChannel);
  534. m_RenderObj->Restart_Animation ();
  535. return ;
  536. }
  537. /////////////////////////////////////////////////////////////
  538. //
  539. // Update_Outer_Scale_Array
  540. //
  541. /////////////////////////////////////////////////////////////
  542. void
  543. RingSizePropPageClass::Update_Outer_Scale_Array (void)
  544. {
  545. m_OuterScaleChannel.Reset ();
  546. float position = 0;
  547. float red = 0;
  548. float green = 0;
  549. float blue = 0;
  550. //
  551. // Allocate arrays we can store the 3 separate timelines in
  552. //
  553. int max_x = m_OuterScaleXBar->Get_Point_Count ();
  554. int max_y = m_OuterScaleYBar->Get_Point_Count ();
  555. LERPAnimationChannelClass<float> x_values;
  556. LERPAnimationChannelClass<float> y_values;
  557. //
  558. // Build the X-axis timline
  559. //
  560. for (int index = 0; index < max_x; index++) {
  561. m_OuterScaleXBar->Get_Point (index, &position, &red, &green, &blue);
  562. x_values.Add_Key (m_OuterScaleXBar->Get_Graph_Percent (index), position);
  563. }
  564. //
  565. // Build the Y-axis timline
  566. //
  567. for (index = 0; index < max_y; index++) {
  568. m_OuterScaleYBar->Get_Point (index, &position, &red, &green, &blue);
  569. y_values.Add_Key (m_OuterScaleYBar->Get_Graph_Percent (index), position);
  570. }
  571. //
  572. // Combine the 3 separate time lines into one time line
  573. //
  574. int x_index = 0;
  575. int y_index = 0;
  576. int list_index = 0;
  577. float x_val = x_values[0].Get_Value ();
  578. float y_val = y_values[0].Get_Value ();
  579. while ( x_index < max_x ||
  580. y_index < max_y)
  581. {
  582. //
  583. // Find the smallest time
  584. //
  585. float time = 2.0F;
  586. float x_time = time;
  587. float y_time = time;
  588. if (x_index < max_x) {
  589. x_time = x_values[x_index].Get_Time ();
  590. }
  591. if (y_index < max_y) {
  592. y_time = y_values[y_index].Get_Time ();
  593. }
  594. time = min (x_time, time);
  595. time = min (y_time, time);
  596. if (x_time == time) {
  597. x_index ++;
  598. }
  599. if (y_time == time) {
  600. y_index ++;
  601. }
  602. //
  603. // Evaluate X
  604. //
  605. x_val = x_values.Evaluate (time);
  606. y_val = y_values.Evaluate (time);
  607. //
  608. // Add this scalar to the list
  609. //
  610. m_OuterScaleChannel.Add_Key (Vector2 (x_val, y_val), time);
  611. }
  612. //
  613. // Update the object
  614. //
  615. m_RenderObj->Set_Outer_Scale_Channel (m_OuterScaleChannel);
  616. m_RenderObj->Restart_Animation ();
  617. return ;
  618. }
  619. /////////////////////////////////////////////////////////////
  620. //
  621. // Is_LERP
  622. //
  623. /////////////////////////////////////////////////////////////
  624. bool
  625. Is_LERP
  626. (
  627. float last_value,
  628. float last_time,
  629. float curr_value,
  630. float curr_time,
  631. float next_value,
  632. float next_time
  633. )
  634. {
  635. float percent = (curr_time - last_time) / (next_time - last_time);
  636. float interpolated_value = last_value + ((next_value-last_value) * percent);
  637. return bool(WWMath::Fabs (interpolated_value - curr_value) < WWMATH_EPSILON);
  638. }