This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Installer/CopyDialog.cpp

592 lines
25 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Installer *
* *
* $Archive:: /Commando/Code/Installer/CopyDialog.cpp $*
* *
* $Author:: Ian_l $*
* *
* $Modtime:: 1/12/02 7:32p $*
* *
* $Revision:: 15 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// Includes.
#include "CopyDialog.h"
#include "AssetMgr.h"
#include "Camera.h"
#include "DialogControl.h"
#include "DialogMgr.h"
#include "DialogText.h"
#include "ErrorHandler.h"
#include "Hanim.h"
#include "Installer.h"
#include "Light.h"
#include "MenuBackdrop.h"
#include "Resource.h"
#include "Scene.h"
#include "Translator.h"
#include "ViewerCtrl.h"
#include "Ww3D.h"
#include "WWAudio.h"
// Defines.
#define MODEL_COUNT 13
#define MODEL_DISPLAY_TIME 22000 // Display time for each model (in milliseconds).
// Static data.
static const char *_ModelNames [MODEL_COUNT] = {"C_AG_GDI_MG",
"C_AG_GDI_MGO",
"C_AG_NOD_MG",
"C_AG_GDI_LOCKE",
"C_AG_NOD_SAKU",
"IGM_PIST",
"IGM_SNIP",
"IGM_C4-R",
"VDC_GDI_HUMVEE",
"V_GDI_MEDTNK",
"V_NOD_TURRET",
"V_GDI_ORCA",
"ENC_GPWR"
};
static const char *_AnimNames [MODEL_COUNT] = {"S_A_HUMAN.H_A_A0A1",
"S_A_HUMAN.H_A_A0B1",
"S_A_HUMAN.H_A_A0A1",
"S_A_HUMAN.H_A_A0B1",
"S_B_HUMAN.H_B_A0A0_13",
"",
"",
"",
"",
"",
"",
"V_GDI_ORCA.V_GDI_ORCA",
""
};
static const int _ModelHeadings [MODEL_COUNT] = {IDS_GDI_SOLDIER_HEADING,
IDS_GDI_OFFICER_HEADING,
IDS_NOD_SOLDIER_HEADING,
IDS_LOCKE_HEADING,
IDS_SAKURA_HEADING,
IDS_PISTOL_HEADING,
IDS_SNIPER_RIFLE_HEADING,
IDS_REMOTE_C4_HEADING,
IDS_GDI_HUMM_VEE_HEADING,
IDS_GDI_MEDIUM_TANK_HEADING,
IDS_NOD_TURRET_HEADING,
IDS_GDI_ORCA_HEADING,
IDS_GDI_POWER_PLANT_HEADING
};
static const int _ModelDescriptions [MODEL_COUNT] = {IDS_GDI_SOLDIER_DESCRIPTION,
IDS_GDI_OFFICER_DESCRIPTION,
IDS_NOD_SOLDIER_DESCRIPTION,
IDS_LOCKE_DESCRIPTION,
IDS_SAKURA_DESCRIPTION,
IDS_PISTOL_DESCRIPTION,
IDS_SNIPER_RIFLE_DESCRIPTION,
IDS_REMOTE_C4_DESCRIPTION,
IDS_GDI_HUMM_VEE_DESCRIPTION,
IDS_GDI_MEDIUM_TANK_DESCRIPTION,
IDS_NOD_TURRET_DESCRIPTION,
IDS_GDI_ORCA_DESCRIPTION,
IDS_GDI_POWER_PLANT_DESCRIPTION
};
/***********************************************************************************************
* CopyDialogClass::CopyDialogClass -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
CopyDialogClass::CopyDialogClass()
: InstallMenuDialogClass (IDD_DIALOG_COPY),
SupplementalModel (NULL),
ProgressBarModel (NULL),
ProgressBarAnim (NULL),
CurrentModel (0),
CountdownTimer (NULL),
FlashTimer (NULL),
FileSystemErrorPopup (NULL),
AddedModels (false)
{
}
/***********************************************************************************************
* CopyDialogClass::On_Init_Dialog -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::On_Init_Dialog (void)
{
WideStringClass sourcepath;
ViewerCtrlClass *viewercontrol = Get_Dlg_Item (IDC_COPY_VIEWER)->As_ViewerCtrlClass();
// Disable the OK button until copying is complete.
Enable_Dlg_Item (IDOK, false);
// Configure the W3D elements.
viewercontrol->Set_Background_Visible (false);
Add_Models();
// Start the copy thread.
CopyThread = new CopyThreadClass (_Installer.Get_Total_Size (false));
CopyThread->Execute();
CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
InstallMenuDialogClass::On_Init_Dialog();
}
/***********************************************************************************************
* CopyDialogClass::On_Activate -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::On_Activate (bool onoff)
{
if (onoff) {
AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 64);
AIL_serve();
} else {
AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 8);
}
InstallMenuDialogClass::On_Activate (onoff);
}
/***********************************************************************************************
* CopyDialogClass::On_Frame_Update -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::On_Frame_Update (void)
{
WideStringClass statusmessage;
DialogTextClass *statustext1, *statustext2;
// Set both status lines with the status message. By default, use the small text for display.
CopyThread->Get_Status_Message (statusmessage);
statustext1 = Get_Dlg_Item (IDC_COPY_STATUS1)->As_DialogTextClass();
statustext2 = Get_Dlg_Item (IDC_COPY_STATUS2)->As_DialogTextClass();
// Update the copy status.
switch (CopyThread->Get_Status()) {
case CopyThreadClass::STATUS_OK:
{
float fraction, framecount;
char percentagestring [10];
Add_Models();
// Advance to next model if timer has 'gone off'.
if (CountdownTimer->Value() == 0) {
CurrentModel = (CurrentModel + 1) % MODEL_COUNT;
Set_Model (CurrentModel);
delete CountdownTimer;
CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
}
// Update the progress bar.
statustext1->Set_Text (statusmessage);
statustext2->Set_Text (L"");
framecount = ProgressBarModel->Peek_Animation()->Get_Num_Frames();
fraction = CopyThread->Get_Fraction_Complete();
ProgressBarModel->Set_Animation (ProgressBarAnim, fraction * (framecount - 1), RenderObjClass::ANIM_MODE_MANUAL);
percentagestring [sizeof (percentagestring) - 1] = '\0';
_snprintf (percentagestring, sizeof (percentagestring) - 1, "%u%%", (unsigned) (fraction * 100.0f));
Set_Dlg_Item_Text (IDC_COPY_PERCENTAGE, WideStringClass (percentagestring));
break;
}
case CopyThreadClass::STATUS_ERROR:
FileSystemErrorPopup = MessageBoxClass::Create_Dialog (TxWideStringClass (IDS_APPLICATION_ERROR), TxWideStringClass (IDS_FILE_SYSTEM_ERROR), MessageBoxClass::MESSAGE_BOX_TYPE_RETRY_QUIT, this);
CountdownTimer->Stop();
break;
case CopyThreadClass::STATUS_SUCCESS:
Remove_Models();
// Advance to next model if timer has 'gone off'.
if (CountdownTimer->Value() == 0) {
CurrentModel = (CurrentModel + 1) % MODEL_COUNT;
Set_Model (CurrentModel);
delete CountdownTimer;
CountdownTimer = new CDTimerClass <SafeTimerClass> (MODEL_DISPLAY_TIME);
}
if (FlashTimer == NULL) {
FlashTimer = new TTimerClass <SafeTimerClass>;
// Allow the user to continue by enabling the OK button.
Enable_Dlg_Item (IDOK, true);
}
// Flash the status message in large text.
statustext1->Set_Text (L"");
Set_Dlg_Item_Text (IDC_COPY_PERCENTAGE, L"");
if (((FlashTimer->Value() / 1000) % 3) == 0) {
statustext2->Set_Text (statusmessage);
} else {
statustext2->Set_Text (L"");
}
break;
case CopyThreadClass::STATUS_ABORTED:
Remove_Models();
// Use the large text to display the status message.
statustext1->Set_Text (L"");
statustext2->Set_Text (statusmessage);
// Cancel this dialog if the copy thread has terminated.
if (!CopyThread->Is_Running()) {
MenuDialogClass::On_Command (IDCANCEL, 0, 0);
// NOTE: Must return because this object may have already been deleted.
return;
}
break;
case CopyThreadClass::STATUS_FAILURE:
{
WideStringClass errormessage;
// A fatal error has occurred.
CopyThread->Get_Error_Message (errormessage);
throw (errormessage);
}
default:
break;
}
InstallMenuDialogClass::On_Frame_Update();
}
/***********************************************************************************************
* CopyDialogClass::Add_Models -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::Add_Models()
{
if (!AddedModels) {
const char *supplementalmodelname = "IN_COPYGIZMO";
const char *supplementalanimname = "IN_COPYGIZMO.IN_COPYGIZMO";
const char *progressbarmodelname = "IN_PROGRESS";
const char *progressbaranimname = "IN_PROGRESS.IN_PROGRESS";
HAnimClass *supplementalanim;
SupplementalModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj (supplementalmodelname);
if (SupplementalModel != NULL) {
Get_BackDrop()->Peek_Scene()->Add_Render_Object (SupplementalModel);
supplementalanim = WW3DAssetManager::Get_Instance()->Get_HAnim (supplementalanimname);
if (supplementalanim != NULL) {
SupplementalModel->Set_Animation (supplementalanim, 0, RenderObjClass::ANIM_MODE_LOOP);
REF_PTR_RELEASE (supplementalanim);
}
}
ProgressBarModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj (progressbarmodelname);
if (ProgressBarModel != NULL) {
Get_BackDrop()->Peek_Scene()->Add_Render_Object (ProgressBarModel);
ProgressBarAnim = WW3DAssetManager::Get_Instance()->Get_HAnim (progressbaranimname);
if (ProgressBarAnim != NULL) {
ProgressBarModel->Set_Animation (ProgressBarAnim, 0, RenderObjClass::ANIM_MODE_MANUAL);
}
}
Set_Model (CurrentModel);
AddedModels = true;
}
}
/***********************************************************************************************
* CopyDialogClass::Set_Model -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::Set_Model (unsigned modelindex)
{
const float rotationrate = 45.0f;
// Set the appropriate model, animation and interface for the viewer.
ViewerCtrlClass *viewercontrol = Get_Dlg_Item (IDC_COPY_VIEWER)->As_ViewerCtrlClass();
Set_Dlg_Item_Text (IDC_COPY_HEADER, TxWideStringClass (_ModelHeadings [modelindex]));
Set_Dlg_Item_Text (IDC_COPY_DESCRIPTION, TxWideStringClass (_ModelDescriptions [modelindex]));
viewercontrol->Set_Model (_ModelNames [modelindex]);
viewercontrol->Set_Animation (_AnimNames [modelindex]);
viewercontrol->Set_Interface_Mode (ViewerCtrlClass::Z_ROTATION, rotationrate);
// Traverse the model...
for (int index = 0; index < viewercontrol->Peek_Model()->Get_Num_Sub_Objects(); index++) {
RenderObjClass *sub_obj = viewercontrol->Peek_Model()->Get_Sub_Object (index);
// Hide muzzle flashes - they are not appropriate in this context.
if (::strstr (sub_obj->Get_Name(), "MUZZLEFLASH") != NULL) {
sub_obj->Set_Hidden (true);
}
// Hide flares - the rendering system has not been initialized.
if (sub_obj->Class_ID() == RenderObjClass::CLASSID_DAZZLE) {
sub_obj->Set_Hidden (true);
}
REF_PTR_RELEASE (sub_obj);
}
}
/***********************************************************************************************
* CopyDialogClass::Remove_Models -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::Remove_Models()
{
if (AddedModels) {
REF_PTR_RELEASE (ProgressBarAnim);
ProgressBarModel->Remove();
REF_PTR_RELEASE (ProgressBarModel);
SupplementalModel->Remove();
REF_PTR_RELEASE (SupplementalModel);
AddedModels = false;
}
}
/***********************************************************************************************
* CopyDialogClass::End_Dialog -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::End_Dialog (void)
{
Remove_Models();
// Wait for copy thread to terminate (in case it hasn't finished yet).
while (CopyThread->Is_Running()) {
Sleep (50);
}
delete CopyThread;
AIL_set_preference (DIG_DS_MIX_FRAGMENT_CNT, 8);
if (CountdownTimer != NULL) delete CountdownTimer;
if (FlashTimer != NULL) delete FlashTimer;
InstallMenuDialogClass::End_Dialog();
}
/***********************************************************************************************
* CopyDialogClass::Callback -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::Callback (int id, PopupDialogClass *popup)
{
if (popup == FileSystemErrorPopup) {
switch (id) {
case IDC_BUTTON_RETRY:
CopyThread->Set_Status (CopyThreadClass::STATUS_RETRY);
REF_PTR_RELEASE (popup);
CountdownTimer->Start();
break;
case IDC_BUTTON_QUIT:
CopyThread->Set_Status (CopyThreadClass::STATUS_QUIT);
REF_PTR_RELEASE (popup);
CountdownTimer->Start();
break;
default:
break;
}
} else {
switch (id) {
case IDC_BUTTON_YES:
CopyThread->Set_Abort (true);
CountdownTimer->Start();
break;
case IDC_BUTTON_NO:
case IDCANCEL:
case IDOK:
CopyThread->Set_Abort (false);
CountdownTimer->Start();
break;
default:
break;
}
}
// NOTE: Do not call base callback - this function replaces base callback functionality.
}
/***********************************************************************************************
* CopyDialogClass::On_Command -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void CopyDialogClass::On_Command (int ctrl_id, int message_id, DWORD param)
{
switch (ctrl_id) {
case IDOK:
// If the OK button has been disabled throw away this message.
if (!Is_Dlg_Item_Enabled (IDOK)) return;
break;
case IDCANCEL:
// If the copy process has already finished then cancel immediately.
if (!CopyThread->Is_Running()) {
MenuDialogClass::On_Command (IDCANCEL, 0, 0);
return;
} else {
// Can the user cancel?
// NOTE: User will not be able to cancel if the copying process is uninterruptable because,
// for example, it is updating the registry.
if (!CopyThread->Can_Abort (true)) {
CopyThread->Set_Abort (false);
return;
}
CountdownTimer->Stop();
}
default:
break;
}
InstallMenuDialogClass::On_Command (ctrl_id, message_id, param);
}