Files
2026-02-02 04:50:13 +01:00

501 lines
14 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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/>.
*
*/
/*
* Copyright (C) 2006-2010 - Frictional Games
*
* This file is part of HPL1 Engine.
*/
#include "hpl1/engine/game/Game.h"
#include "hpl1/engine/game/ScriptFuncs.h"
#include "hpl1/engine/game/Updater.h"
#include "hpl1/engine/graphics/Graphics.h"
#include "hpl1/engine/graphics/LowLevelGraphics.h"
#include "hpl1/engine/graphics/Renderer3D.h"
#include "hpl1/engine/input/Input.h"
#include "hpl1/engine/input/Mouse.h"
#include "hpl1/engine/resources/Resources.h"
#include "hpl1/engine/system/LogicTimer.h"
#include "hpl1/engine/system/String.h"
#include "hpl1/engine/system/System.h"
#include "hpl1/engine/gui/Gui.h"
#include "hpl1/engine/game/low_level_game_setup.h"
#include "hpl1/engine/system/low_level_system.h"
#include "common/events.h"
#include "hpl1/hpl1.h"
namespace hpl {
//////////////////////////////////////////////////////////////////////////
// FPS COUNTER
//////////////////////////////////////////////////////////////////////////
cFPSCounter::cFPSCounter(LowLevelSystem *apLowLevelSystem) {
mfFPS = 60;
mlFramecounter = 0;
mfFrametimestart = 0;
mfFrametime = 0;
mfUpdateRate = 1;
mpLowLevelSystem = apLowLevelSystem;
mfFrametimestart = ((float)GetApplicationTime()) / 1000.0f;
}
void cFPSCounter::AddFrame() {
mlFramecounter++;
mfFrametime = (((float)GetApplicationTime()) / 1000.0f) - mfFrametimestart;
// update the timer
if (mfFrametime >= mfUpdateRate) {
mfFPS = ((float)mlFramecounter) / mfFrametime;
mlFramecounter = 0;
mfFrametimestart = ((float)GetApplicationTime()) / 1000.0f;
}
}
//////////////////////////////////////////////////////////////////////////
// SETUP VAR CONTAINER
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cSetupVarContainer::cSetupVarContainer() {
msBlank = "";
}
//-----------------------------------------------------------------------
void cSetupVarContainer::AddString(const tString &asName, const tString &asValue) {
Common::StableMap<tString, tString>::value_type val(asName, asValue);
m_mapVars.insert(val);
}
void cSetupVarContainer::AddInt(const tString &asName, int alValue) {
AddString(asName, cString::ToString(alValue));
}
void cSetupVarContainer::AddFloat(const tString &asName, float afValue) {
AddString(asName, cString::ToString(afValue));
}
void cSetupVarContainer::AddBool(const tString &asName, bool abValue) {
AddString(asName, abValue ? "true" : "false");
}
//-----------------------------------------------------------------------
const tString &cSetupVarContainer::GetString(const tString &asName) {
Common::StableMap<tString, tString>::iterator it = m_mapVars.find(asName);
if (it == m_mapVars.end())
return msBlank;
else
return it->second;
}
float cSetupVarContainer::GetFloat(const tString &asName, float afDefault) {
const tString &sVal = GetString(asName);
if (sVal == "")
return afDefault;
else
return cString::ToFloat(sVal.c_str(), afDefault);
}
int cSetupVarContainer::GetInt(const tString &asName, int alDefault) {
const tString &sVal = GetString(asName);
if (sVal == "")
return alDefault;
else
return cString::ToInt(sVal.c_str(), alDefault);
}
bool cSetupVarContainer::GetBool(const tString &asName, bool abDefault) {
const tString &sVal = GetString(asName);
if (sVal == "")
return abDefault;
else
return cString::ToBool(sVal.c_str(), abDefault);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cGame::cGame(LowLevelGameSetup *apGameSetup, cSetupVarContainer &aVars) {
GameInit(apGameSetup, aVars);
}
//-----------------------------------------------------------------------
cGame::cGame(LowLevelGameSetup *apGameSetup, int alWidth, int alHeight, int alBpp, bool abFullscreen,
unsigned int alUpdateRate, int alMultisampling) {
cSetupVarContainer Vars;
Vars.AddInt("ScreenWidth", alWidth);
Vars.AddInt("ScreenHeight", alHeight);
Vars.AddInt("ScreenBpp", alBpp);
Vars.AddBool("Fullscreen", abFullscreen);
Vars.AddInt("Multisampling", alMultisampling);
Vars.AddInt("LogicUpdateRate", alUpdateRate);
GameInit(apGameSetup, Vars);
}
//-----------------------------------------------------------------------
void cGame::GameInit(LowLevelGameSetup *apGameSetup, cSetupVarContainer &aVars) {
mpGameSetup = apGameSetup;
Log("Creating Engine Modules\n");
Log("--------------------------------------------------------\n");
// Create the modules that game connects to and init them!
Log(" Creating graphics module\n");
mpGraphics = mpGameSetup->createGraphics();
Log(" Creating system module\n");
mpSystem = mpGameSetup->createSystem();
Log(" Creating resource module\n");
mpResources = mpGameSetup->createResources(mpGraphics);
Log(" Creating input module\n");
mpInput = mpGameSetup->createInput(mpGraphics);
Log(" Creating sound module\n");
mpSound = mpGameSetup->createSound();
Log(" Creating physics module\n");
mpPhysics = mpGameSetup->createPhysics();
Log(" Creating ai module\n");
mpAI = mpGameSetup->createAi();
Log(" Creating gui module\n");
mpGui = hplNew(cGui, ());
Log(" Creating scene module\n");
mpScene = mpGameSetup->createScene(mpGraphics, mpResources, mpSound, mpPhysics, mpSystem, mpAI);
Log("--------------------------------------------------------\n\n");
// Init the resources
mpResources->Init(mpGraphics, mpSystem, mpSound, mpScene, mpGui);
// Init the graphics
mpGraphics->Init(aVars.GetInt("ScreenWidth", 800),
aVars.GetInt("ScreenHeight", 600),
aVars.GetInt("ScreenBpp", 32),
aVars.GetBool("Fullscreen", false),
aVars.GetInt("Multisampling", 0),
aVars.GetString("WindowCaption"),
mpResources);
// Init Sound
mpSound->Init(mpResources, aVars.GetBool("UseSoundHardware", true),
aVars.GetBool("ForceGeneric", false),
aVars.GetBool("UseEnvironmentalAudio", false),
aVars.GetInt("MaxSoundChannels", 32),
aVars.GetInt("StreamUpdateFreq", 10),
aVars.GetBool("UseSoundThreading", true),
aVars.GetBool("UseVoiceManagement", true),
aVars.GetInt("MaxMonoChannelsHint", 0),
aVars.GetInt("MaxStereoChannelsHint", 0),
aVars.GetInt("StreamBufferSize", 4096),
aVars.GetInt("StreamBufferCount", 8),
aVars.GetBool("LowLevelSoundLogging", false),
aVars.GetString("DeviceName"));
// Init physics
mpPhysics->Init(mpResources);
// Init AI
mpAI->Init();
// Init Gui
mpGui->Init(mpResources, mpGraphics, mpSound, mpScene);
Log("Initializing Game Module\n");
Log("--------------------------------------------------------\n");
// Create the updatehandler
Log(" Adding engine updates\n");
mpUpdater = hplNew(cUpdater, (mpSystem->GetLowLevel()));
// Add some loaded modules to the updater
mpUpdater->AddGlobalUpdate(mpInput);
mpUpdater->AddGlobalUpdate(mpPhysics);
mpUpdater->AddGlobalUpdate(mpScene);
mpUpdater->AddGlobalUpdate(mpSound);
mpUpdater->AddGlobalUpdate(mpAI);
mpUpdater->AddGlobalUpdate(mpGui);
mpUpdater->AddGlobalUpdate(mpResources);
// Setup the "default" updater container
mpUpdater->AddContainer("Default");
mpUpdater->SetContainer("Default");
// Create the logic timer.
mpLogicTimer = mpSystem->CreateLogicTimer(aVars.GetInt("LogicUpdateRate", 800));
// Init some standard script funcs
Log(" Initializing script functions\n");
cScriptFuncs::Init(mpGraphics, mpResources, mpSystem, mpInput, mpScene, mpSound, this);
// Since game is not done:
mbGameIsDone = false;
mfUpdateTime = 0;
mfGameTime = 0;
mbLimitFPS = true;
mpFPSCounter = hplNew(cFPSCounter, (mpSystem->GetLowLevel()));
Log("--------------------------------------------------------\n\n");
Log("User Initialization\n");
Log("--------------------------------------------------------\n");
}
//-----------------------------------------------------------------------
cGame::~cGame() {
Log("--------------------------------------------------------\n\n");
hplDelete(mpLogicTimer);
hplDelete(mpFPSCounter);
hplDelete(mpUpdater);
hplDelete(mpGui);
hplDelete(mpScene);
hplDelete(mpInput);
hplDelete(mpSound);
hplDelete(mpGraphics);
hplDelete(mpResources);
hplDelete(mpPhysics);
hplDelete(mpAI);
hplDelete(mpSystem);
Log(" Deleting game setup provided by user\n");
hplDelete(mpGameSetup);
Log("HPL Exit was successful!\n");
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHOD
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
int glClearUpdateCheck = 0;
void cGame::Run() {
double fNumOfTimes = 0;
double fMediumTime = 0;
mpUpdater->OnStart();
mpLogicTimer->Reset();
// Loop the game... fix the var...
unsigned long lTempTime = GetApplicationTime();
mfFrameTime = 0;
unsigned long lTempFrameTime = GetApplicationTime();
bool mbIsUpdated = true;
while (!mbGameIsDone && !g_engine->shouldQuit()) {
//////////////////////////
// Update logic.
while (mpLogicTimer->WantUpdate() && !mbGameIsDone) {
unsigned int lUpdateTime = GetApplicationTime();
mpUpdater->Update(GetStepSize());
unsigned int lDeltaTime = GetApplicationTime() - lUpdateTime;
mfUpdateTime = (float)(lDeltaTime) / 1000.0f;
mbIsUpdated = true;
glClearUpdateCheck++;
mfGameTime += GetStepSize();
}
mpLogicTimer->EndUpdateLoop();
// If not making a single rendering is better to use gpu and
// cpu at the same time and make query checks etc after logic update.
// If any delete has occurred in the update this might crash. so skip it for now.
/*if(mbRenderOnce==false) {
mpGraphics->GetRenderer3D()->FetchOcclusionQueries();
mpUpdater->OnPostBufferSwap();
}*/
// Draw graphics!
if (mbIsUpdated)
mpScene->UpdateRenderList(mfFrameTime);
if (mbLimitFPS == false || mbIsUpdated) {
mbIsUpdated = false;
// Get the the from the last frame.
mfFrameTime = ((float)(GetApplicationTime() - lTempFrameTime)) / 1000;
lTempFrameTime = GetApplicationTime();
// Draw this frame
// unsigned long lFTime = GetApplicationTime();
mpUpdater->OnDraw();
mpScene->Render(mpUpdater, mfFrameTime);
// Update fps counter.
mpFPSCounter->AddFrame();
// Update the screen.
mpGraphics->GetLowLevel()->SwapBuffers();
mpGraphics->GetRenderer3D()->FetchOcclusionQueries();
mpUpdater->OnPostBufferSwap();
fNumOfTimes++;
}
}
Log("--------------------------------------------------------\n\n");
Log("Statistics\n");
Log("--------------------------------------------------------\n");
unsigned long lTime = GetApplicationTime() - lTempTime;
fMediumTime = fNumOfTimes / (((double)lTime) / 1000);
Log(" Medium framerate: %f\n", fMediumTime);
Log("--------------------------------------------------------\n\n");
Log("User Exit\n");
Log("--------------------------------------------------------\n");
mpUpdater->OnExit();
}
//-----------------------------------------------------------------------
void cGame::Exit() {
mbGameIsDone = true;
}
//-----------------------------------------------------------------------
void cGame::ResetLogicTimer() {
mpLogicTimer->Reset();
}
void cGame::SetUpdatesPerSec(int alUpdatesPerSec) {
mpLogicTimer->SetUpdatesPerSec(alUpdatesPerSec);
}
int cGame::GetUpdatesPerSec() {
return mpLogicTimer->GetUpdatesPerSec();
}
float cGame::GetStepSize() {
return mpLogicTimer->GetStepSize();
}
//-----------------------------------------------------------------------
cScene *cGame::GetScene() {
return mpScene;
}
//-----------------------------------------------------------------------
cResources *cGame::GetResources() {
return mpResources;
}
//-----------------------------------------------------------------------
cGraphics *cGame::GetGraphics() {
return mpGraphics;
}
//-----------------------------------------------------------------------
cSystem *cGame::GetSystem() {
return mpSystem;
}
//-----------------------------------------------------------------------
cInput *cGame::GetInput() {
return mpInput;
}
//-----------------------------------------------------------------------
cSound *cGame::GetSound() {
return mpSound;
}
//-----------------------------------------------------------------------
cPhysics *cGame::GetPhysics() {
return mpPhysics;
}
//-----------------------------------------------------------------------
cAI *cGame::GetAI() {
return mpAI;
}
//-----------------------------------------------------------------------
cGui *cGame::GetGui() {
return mpGui;
}
//-----------------------------------------------------------------------
cUpdater *cGame::GetUpdater() {
return mpUpdater;
}
float cGame::GetFPS() {
return mpFPSCounter->mfFPS;
}
//-----------------------------------------------------------------------
void cGame::SetFPSUpdateRate(float afSec) {
mpFPSCounter->mfUpdateRate = afSec;
}
float cGame::GetFPSUpdateRate() {
return mpFPSCounter->mfUpdateRate;
}
//-----------------------------------------------------------------------
} // namespace hpl