CopyDialog.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Installer *
  23. * *
  24. * $Archive:: /Commando/Code/Installer/CopyDialog.cpp $*
  25. * *
  26. * $Author:: Ian_l $*
  27. * *
  28. * $Modtime:: 1/12/02 7:32p $*
  29. * *
  30. * $Revision:: 15 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. // Includes.
  36. #include "CopyDialog.h"
  37. #include "AssetMgr.h"
  38. #include "Camera.h"
  39. #include "DialogControl.h"
  40. #include "DialogMgr.h"
  41. #include "DialogText.h"
  42. #include "ErrorHandler.h"
  43. #include "Hanim.h"
  44. #include "Installer.h"
  45. #include "Light.h"
  46. #include "MenuBackdrop.h"
  47. #include "Resource.h"
  48. #include "Scene.h"
  49. #include "Translator.h"
  50. #include "ViewerCtrl.h"
  51. #include "Ww3D.h"
  52. #include "WWAudio.h"
  53. // Defines.
  54. #define MODEL_COUNT 13
  55. #define MODEL_DISPLAY_TIME 22000 // Display time for each model (in milliseconds).
  56. // Static data.
  57. static const char *_ModelNames [MODEL_COUNT] = {"C_AG_GDI_MG",
  58. "C_AG_GDI_MGO",
  59. "C_AG_NOD_MG",
  60. "C_AG_GDI_LOCKE",
  61. "C_AG_NOD_SAKU",
  62. "IGM_PIST",
  63. "IGM_SNIP",
  64. "IGM_C4-R",
  65. "VDC_GDI_HUMVEE",
  66. "V_GDI_MEDTNK",
  67. "V_NOD_TURRET",
  68. "V_GDI_ORCA",
  69. "ENC_GPWR"
  70. };
  71. static const char *_AnimNames [MODEL_COUNT] = {"S_A_HUMAN.H_A_A0A1",
  72. "S_A_HUMAN.H_A_A0B1",
  73. "S_A_HUMAN.H_A_A0A1",
  74. "S_A_HUMAN.H_A_A0B1",
  75. "S_B_HUMAN.H_B_A0A0_13",
  76. "",
  77. "",
  78. "",
  79. "",
  80. "",
  81. "",
  82. "V_GDI_ORCA.V_GDI_ORCA",
  83. ""
  84. };
  85. static const int _ModelHeadings [MODEL_COUNT] = {IDS_GDI_SOLDIER_HEADING,
  86. IDS_GDI_OFFICER_HEADING,
  87. IDS_NOD_SOLDIER_HEADING,
  88. IDS_LOCKE_HEADING,
  89. IDS_SAKURA_HEADING,
  90. IDS_PISTOL_HEADING,
  91. IDS_SNIPER_RIFLE_HEADING,
  92. IDS_REMOTE_C4_HEADING,
  93. IDS_GDI_HUMM_VEE_HEADING,
  94. IDS_GDI_MEDIUM_TANK_HEADING,
  95. IDS_NOD_TURRET_HEADING,
  96. IDS_GDI_ORCA_HEADING,
  97. IDS_GDI_POWER_PLANT_HEADING
  98. };
  99. static const int _ModelDescriptions [MODEL_COUNT] = {IDS_GDI_SOLDIER_DESCRIPTION,
  100. IDS_GDI_OFFICER_DESCRIPTION,
  101. IDS_NOD_SOLDIER_DESCRIPTION,
  102. IDS_LOCKE_DESCRIPTION,
  103. IDS_SAKURA_DESCRIPTION,
  104. IDS_PISTOL_DESCRIPTION,
  105. IDS_SNIPER_RIFLE_DESCRIPTION,
  106. IDS_REMOTE_C4_DESCRIPTION,
  107. IDS_GDI_HUMM_VEE_DESCRIPTION,
  108. IDS_GDI_MEDIUM_TANK_DESCRIPTION,
  109. IDS_NOD_TURRET_DESCRIPTION,
  110. IDS_GDI_ORCA_DESCRIPTION,
  111. IDS_GDI_POWER_PLANT_DESCRIPTION
  112. };
  113. /***********************************************************************************************
  114. * CopyDialogClass::CopyDialogClass -- *
  115. * *
  116. * INPUT: *
  117. * *
  118. * OUTPUT: *
  119. * *
  120. * WARNINGS: *
  121. * *
  122. * HISTORY: *
  123. * 08/22/01 IML : Created. *
  124. *=============================================================================================*/
  125. CopyDialogClass::CopyDialogClass()
  126. : InstallMenuDialogClass (IDD_DIALOG_COPY),
  127. SupplementalModel (NULL),
  128. ProgressBarModel (NULL),
  129. ProgressBarAnim (NULL),
  130. CurrentModel (0),
  131. CountdownTimer (NULL),
  132. FlashTimer (NULL),
  133. FileSystemErrorPopup (NULL),
  134. AddedModels (false)
  135. {
  136. }
  137. /***********************************************************************************************
  138. * CopyDialogClass::On_Init_Dialog -- *
  139. * *
  140. * INPUT: *
  141. * *
  142. * OUTPUT: *
  143. * *
  144. * WARNINGS: *
  145. * *
  146. * HISTORY: *
  147. * 08/22/01 IML : Created. *
  148. *=============================================================================================*/
  149. void CopyDialogClass::On_Init_Dialog (void)
  150. {
  151. WideStringClass sourcepath;
  152. ViewerCtrlClass *viewercontrol = Get_Dlg_Item (IDC_COPY_VIEWER)->As_ViewerCtrlClass();
  153. // Disable the OK button until copying is complete.
  154. Enable_Dlg_Item (IDOK, false);
  155. // Configure the W3D elements.
  156. viewercontrol->Set_Background_Visible (false);
  157. Add_Models();
  158. // Start the copy thread.
  159. CopyThread = new CopyThreadClass (_Installer.Get_Total_Size (false));
  160. CopyThread->Execute();
  161. CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
  162. InstallMenuDialogClass::On_Init_Dialog();
  163. }
  164. /***********************************************************************************************
  165. * CopyDialogClass::On_Activate -- *
  166. * *
  167. * INPUT: *
  168. * *
  169. * OUTPUT: *
  170. * *
  171. * WARNINGS: *
  172. * *
  173. * HISTORY: *
  174. * 08/22/01 IML : Created. *
  175. *=============================================================================================*/
  176. void CopyDialogClass::On_Activate (bool onoff)
  177. {
  178. if (onoff) {
  179. AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 64);
  180. AIL_serve();
  181. } else {
  182. AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 8);
  183. }
  184. InstallMenuDialogClass::On_Activate (onoff);
  185. }
  186. /***********************************************************************************************
  187. * CopyDialogClass::On_Frame_Update -- *
  188. * *
  189. * INPUT: *
  190. * *
  191. * OUTPUT: *
  192. * *
  193. * WARNINGS: *
  194. * *
  195. * HISTORY: *
  196. * 08/22/01 IML : Created. *
  197. *=============================================================================================*/
  198. void CopyDialogClass::On_Frame_Update (void)
  199. {
  200. WideStringClass statusmessage;
  201. DialogTextClass *statustext1, *statustext2;
  202. // Set both status lines with the status message. By default, use the small text for display.
  203. CopyThread->Get_Status_Message (statusmessage);
  204. statustext1 = Get_Dlg_Item (IDC_COPY_STATUS1)->As_DialogTextClass();
  205. statustext2 = Get_Dlg_Item (IDC_COPY_STATUS2)->As_DialogTextClass();
  206. // Update the copy status.
  207. switch (CopyThread->Get_Status()) {
  208. case CopyThreadClass::STATUS_OK:
  209. {
  210. float fraction, framecount;
  211. char percentagestring [10];
  212. Add_Models();
  213. // Advance to next model if timer has 'gone off'.
  214. if (CountdownTimer->Value() == 0) {
  215. CurrentModel = (CurrentModel + 1) % MODEL_COUNT;
  216. Set_Model (CurrentModel);
  217. delete CountdownTimer;
  218. CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
  219. }
  220. // Update the progress bar.
  221. statustext1->Set_Text (statusmessage);
  222. statustext2->Set_Text (L"");
  223. framecount = ProgressBarModel->Peek_Animation()->Get_Num_Frames();
  224. fraction = CopyThread->Get_Fraction_Complete();
  225. ProgressBarModel->Set_Animation (ProgressBarAnim, fraction * (framecount - 1), RenderObjClass::ANIM_MODE_MANUAL);
  226. percentagestring [sizeof (percentagestring) - 1] = '\0';
  227. _snprintf (percentagestring, sizeof (percentagestring) - 1, "%u%%", (unsigned) (fraction * 100.0f));
  228. Set_Dlg_Item_Text (IDC_COPY_PERCENTAGE, WideStringClass (percentagestring));
  229. break;
  230. }
  231. case CopyThreadClass::STATUS_ERROR:
  232. FileSystemErrorPopup = MessageBoxClass::Create_Dialog (TxWideStringClass (IDS_APPLICATION_ERROR), TxWideStringClass (IDS_FILE_SYSTEM_ERROR), MessageBoxClass::MESSAGE_BOX_TYPE_RETRY_QUIT, this);
  233. CountdownTimer->Stop();
  234. break;
  235. case CopyThreadClass::STATUS_SUCCESS:
  236. Remove_Models();
  237. // Advance to next model if timer has 'gone off'.
  238. if (CountdownTimer->Value() == 0) {
  239. CurrentModel = (CurrentModel + 1) % MODEL_COUNT;
  240. Set_Model (CurrentModel);
  241. delete CountdownTimer;
  242. CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
  243. }
  244. if (FlashTimer == NULL) {
  245. FlashTimer = new TTimerClass <SafeTimerClass>;
  246. // Allow the user to continue by enabling the OK button.
  247. Enable_Dlg_Item (IDOK, true);
  248. }
  249. // Flash the status message in large text.
  250. statustext1->Set_Text (L"");
  251. Set_Dlg_Item_Text (IDC_COPY_PERCENTAGE, L"");
  252. if (((FlashTimer->Value() / 1000) % 3) == 0) {
  253. statustext2->Set_Text (statusmessage);
  254. } else {
  255. statustext2->Set_Text (L"");
  256. }
  257. break;
  258. case CopyThreadClass::STATUS_ABORTED:
  259. Remove_Models();
  260. // Use the large text to display the status message.
  261. statustext1->Set_Text (L"");
  262. statustext2->Set_Text (statusmessage);
  263. // Cancel this dialog if the copy thread has terminated.
  264. if (!CopyThread->Is_Running()) {
  265. MenuDialogClass::On_Command (IDCANCEL, 0, 0);
  266. // NOTE: Must return because this object may have already been deleted.
  267. return;
  268. }
  269. break;
  270. case CopyThreadClass::STATUS_FAILURE:
  271. {
  272. WideStringClass errormessage;
  273. // A fatal error has occurred.
  274. CopyThread->Get_Error_Message (errormessage);
  275. throw (errormessage);
  276. }
  277. default:
  278. break;
  279. }
  280. InstallMenuDialogClass::On_Frame_Update();
  281. }
  282. /***********************************************************************************************
  283. * CopyDialogClass::Add_Models -- *
  284. * *
  285. * INPUT: *
  286. * *
  287. * OUTPUT: *
  288. * *
  289. * WARNINGS: *
  290. * *
  291. * HISTORY: *
  292. * 08/22/01 IML : Created. *
  293. *=============================================================================================*/
  294. void CopyDialogClass::Add_Models()
  295. {
  296. if (!AddedModels) {
  297. const char *supplementalmodelname = "IN_COPYGIZMO";
  298. const char *supplementalanimname = "IN_COPYGIZMO.IN_COPYGIZMO";
  299. const char *progressbarmodelname = "IN_PROGRESS";
  300. const char *progressbaranimname = "IN_PROGRESS.IN_PROGRESS";
  301. HAnimClass *supplementalanim;
  302. SupplementalModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj (supplementalmodelname);
  303. if (SupplementalModel != NULL) {
  304. Get_BackDrop()->Peek_Scene()->Add_Render_Object (SupplementalModel);
  305. supplementalanim = WW3DAssetManager::Get_Instance()->Get_HAnim (supplementalanimname);
  306. if (supplementalanim != NULL) {
  307. SupplementalModel->Set_Animation (supplementalanim, 0, RenderObjClass::ANIM_MODE_LOOP);
  308. REF_PTR_RELEASE (supplementalanim);
  309. }
  310. }
  311. ProgressBarModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj (progressbarmodelname);
  312. if (ProgressBarModel != NULL) {
  313. Get_BackDrop()->Peek_Scene()->Add_Render_Object (ProgressBarModel);
  314. ProgressBarAnim = WW3DAssetManager::Get_Instance()->Get_HAnim (progressbaranimname);
  315. if (ProgressBarAnim != NULL) {
  316. ProgressBarModel->Set_Animation (ProgressBarAnim, 0, RenderObjClass::ANIM_MODE_MANUAL);
  317. }
  318. }
  319. Set_Model (CurrentModel);
  320. AddedModels = true;
  321. }
  322. }
  323. /***********************************************************************************************
  324. * CopyDialogClass::Set_Model -- *
  325. * *
  326. * INPUT: *
  327. * *
  328. * OUTPUT: *
  329. * *
  330. * WARNINGS: *
  331. * *
  332. * HISTORY: *
  333. * 08/22/01 IML : Created. *
  334. *=============================================================================================*/
  335. void CopyDialogClass::Set_Model (unsigned modelindex)
  336. {
  337. const float rotationrate = 45.0f;
  338. // Set the appropriate model, animation and interface for the viewer.
  339. ViewerCtrlClass *viewercontrol = Get_Dlg_Item (IDC_COPY_VIEWER)->As_ViewerCtrlClass();
  340. Set_Dlg_Item_Text (IDC_COPY_HEADER, TxWideStringClass (_ModelHeadings [modelindex]));
  341. Set_Dlg_Item_Text (IDC_COPY_DESCRIPTION, TxWideStringClass (_ModelDescriptions [modelindex]));
  342. viewercontrol->Set_Model (_ModelNames [modelindex]);
  343. viewercontrol->Set_Animation (_AnimNames [modelindex]);
  344. viewercontrol->Set_Interface_Mode (ViewerCtrlClass::Z_ROTATION, rotationrate);
  345. // Traverse the model...
  346. for (int index = 0; index < viewercontrol->Peek_Model()->Get_Num_Sub_Objects(); index++) {
  347. RenderObjClass *sub_obj = viewercontrol->Peek_Model()->Get_Sub_Object (index);
  348. // Hide muzzle flashes - they are not appropriate in this context.
  349. if (::strstr (sub_obj->Get_Name(), "MUZZLEFLASH") != NULL) {
  350. sub_obj->Set_Hidden (true);
  351. }
  352. // Hide flares - the rendering system has not been initialized.
  353. if (sub_obj->Class_ID() == RenderObjClass::CLASSID_DAZZLE) {
  354. sub_obj->Set_Hidden (true);
  355. }
  356. REF_PTR_RELEASE (sub_obj);
  357. }
  358. }
  359. /***********************************************************************************************
  360. * CopyDialogClass::Remove_Models -- *
  361. * *
  362. * INPUT: *
  363. * *
  364. * OUTPUT: *
  365. * *
  366. * WARNINGS: *
  367. * *
  368. * HISTORY: *
  369. * 08/22/01 IML : Created. *
  370. *=============================================================================================*/
  371. void CopyDialogClass::Remove_Models()
  372. {
  373. if (AddedModels) {
  374. REF_PTR_RELEASE (ProgressBarAnim);
  375. ProgressBarModel->Remove();
  376. REF_PTR_RELEASE (ProgressBarModel);
  377. SupplementalModel->Remove();
  378. REF_PTR_RELEASE (SupplementalModel);
  379. AddedModels = false;
  380. }
  381. }
  382. /***********************************************************************************************
  383. * CopyDialogClass::End_Dialog -- *
  384. * *
  385. * INPUT: *
  386. * *
  387. * OUTPUT: *
  388. * *
  389. * WARNINGS: *
  390. * *
  391. * HISTORY: *
  392. * 08/22/01 IML : Created. *
  393. *=============================================================================================*/
  394. void CopyDialogClass::End_Dialog (void)
  395. {
  396. Remove_Models();
  397. // Wait for copy thread to terminate (in case it hasn't finished yet).
  398. while (CopyThread->Is_Running()) {
  399. Sleep (50);
  400. }
  401. delete CopyThread;
  402. AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 8);
  403. if (CountdownTimer != NULL) delete CountdownTimer;
  404. if (FlashTimer != NULL) delete FlashTimer;
  405. InstallMenuDialogClass::End_Dialog();
  406. }
  407. /***********************************************************************************************
  408. * CopyDialogClass::Callback -- *
  409. * *
  410. * INPUT: *
  411. * *
  412. * OUTPUT: *
  413. * *
  414. * WARNINGS: *
  415. * *
  416. * HISTORY: *
  417. * 08/22/01 IML : Created. *
  418. *=============================================================================================*/
  419. void CopyDialogClass::Callback (int id, PopupDialogClass *popup)
  420. {
  421. if (popup == FileSystemErrorPopup) {
  422. switch (id) {
  423. case IDC_BUTTON_RETRY:
  424. CopyThread->Set_Status (CopyThreadClass::STATUS_RETRY);
  425. REF_PTR_RELEASE (popup);
  426. CountdownTimer->Start();
  427. break;
  428. case IDC_BUTTON_QUIT:
  429. CopyThread->Set_Status (CopyThreadClass::STATUS_QUIT);
  430. REF_PTR_RELEASE (popup);
  431. CountdownTimer->Start();
  432. break;
  433. default:
  434. break;
  435. }
  436. } else {
  437. switch (id) {
  438. case IDC_BUTTON_YES:
  439. CopyThread->Set_Abort (true);
  440. CountdownTimer->Start();
  441. break;
  442. case IDC_BUTTON_NO:
  443. case IDCANCEL:
  444. case IDOK:
  445. CopyThread->Set_Abort (false);
  446. CountdownTimer->Start();
  447. break;
  448. default:
  449. break;
  450. }
  451. }
  452. // NOTE: Do not call base callback - this function replaces base callback functionality.
  453. }
  454. /***********************************************************************************************
  455. * CopyDialogClass::On_Command -- *
  456. * *
  457. * INPUT: *
  458. * *
  459. * OUTPUT: *
  460. * *
  461. * WARNINGS: *
  462. * *
  463. * HISTORY: *
  464. * 08/22/01 IML : Created. *
  465. *=============================================================================================*/
  466. void CopyDialogClass::On_Command (int ctrl_id, int message_id, DWORD param)
  467. {
  468. switch (ctrl_id) {
  469. case IDOK:
  470. // If the OK button has been disabled throw away this message.
  471. if (!Is_Dlg_Item_Enabled (IDOK)) return;
  472. break;
  473. case IDCANCEL:
  474. // If the copy process has already finished then cancel immediately.
  475. if (!CopyThread->Is_Running()) {
  476. MenuDialogClass::On_Command (IDCANCEL, 0, 0);
  477. return;
  478. } else {
  479. // Can the user cancel?
  480. // NOTE: User will not be able to cancel if the copying process is uninterruptable because,
  481. // for example, it is updating the registry.
  482. if (!CopyThread->Can_Abort (true)) {
  483. CopyThread->Set_Abort (false);
  484. return;
  485. }
  486. CountdownTimer->Stop();
  487. }
  488. default:
  489. break;
  490. }
  491. InstallMenuDialogClass::On_Command (ctrl_id, message_id, param);
  492. }