forked from mirrors/0ad
rough but functional loading progress bar support.
numerous TODOs remaining - initial update instead of only after completing first job; fix GUI overdraw issue; decrease granularity (currently only 3 updates) This was SVN commit r2033.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "Pyrogenesis.h"
|
||||
#include "Hotkey.h"
|
||||
#include "ConfigDB.h"
|
||||
#include "Loader.h"
|
||||
|
||||
#include "Quaternion.h"
|
||||
#include "Unit.h"
|
||||
@@ -69,6 +70,7 @@ CGameView::~CGameView()
|
||||
UnloadResources();
|
||||
}
|
||||
|
||||
|
||||
void CGameView::Initialize(CGameAttributes *pAttribs)
|
||||
{
|
||||
CConfigValue* cfg;
|
||||
@@ -96,6 +98,32 @@ void CGameView::Initialize(CGameAttributes *pAttribs)
|
||||
InitResources();
|
||||
}
|
||||
|
||||
struct ThunkParams
|
||||
{
|
||||
CGameView* const this_;
|
||||
CGameAttributes* const pAttribs;
|
||||
ThunkParams(CGameView* this__, CGameAttributes* pAttribs_)
|
||||
: this_(this__), pAttribs(pAttribs_) {}
|
||||
};
|
||||
|
||||
static int LoadThunk(void* param, double time_left)
|
||||
{
|
||||
const ThunkParams* p = (const ThunkParams*)param;
|
||||
CGameView* const this_ = p->this_;
|
||||
CGameAttributes* const pAttribs = p->pAttribs;
|
||||
|
||||
this_->Initialize(pAttribs);
|
||||
delete p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CGameView::RegisterInit(CGameAttributes *pAttribs)
|
||||
{
|
||||
void* param = new ThunkParams(this, pAttribs);
|
||||
THROW_ERR(LDR_Register(LoadThunk, param, L"CGameView", 1000));
|
||||
}
|
||||
|
||||
|
||||
void CGameView::Render()
|
||||
{
|
||||
g_Renderer.SetCamera(m_Camera);
|
||||
|
||||
@@ -60,8 +60,9 @@ public:
|
||||
CGameView(CGame *pGame);
|
||||
~CGameView();
|
||||
|
||||
void RegisterInit(CGameAttributes *pAttribs);
|
||||
void Initialize(CGameAttributes *pGameAttributes);
|
||||
|
||||
|
||||
// Update: Update all the view information (i.e. rotate camera, scroll,
|
||||
// whatever). This will *not* change any World information - only the
|
||||
// *presentation*
|
||||
|
||||
@@ -118,6 +118,17 @@ STMT(\
|
||||
)
|
||||
#endif
|
||||
|
||||
#define THROW_ERR(func)\
|
||||
STMT(\
|
||||
int err__ = (int)((func) & UINT_MAX);\
|
||||
if(err__ < 0)\
|
||||
{\
|
||||
assert(0 && "FYI: CHECK_ERR reports that a function failed."\
|
||||
"feel free to ignore or suppress this warning.");\
|
||||
throw err__;\
|
||||
}\
|
||||
)
|
||||
|
||||
|
||||
|
||||
// useful because VC6 may return 0 on failure, instead of throwing.
|
||||
|
||||
+48
-5
@@ -26,8 +26,8 @@
|
||||
#endif
|
||||
#include "lib/res/cursor.h"
|
||||
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/Font.h"
|
||||
|
||||
#include "ps/CConsole.h"
|
||||
|
||||
#include "ps/Game.h"
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "EntityManager.h"
|
||||
#include "PathfindEngine.h"
|
||||
#include "Scheduler.h"
|
||||
#include "StringConvert.h"
|
||||
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "scripting/JSInterface_Entity.h"
|
||||
@@ -481,7 +482,7 @@ static void Render()
|
||||
|
||||
oglCheck();
|
||||
|
||||
if (g_Game)
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->Render();
|
||||
|
||||
@@ -943,6 +944,45 @@ TIMER(InitRenderer)
|
||||
g_Renderer.SetViewport(vp);
|
||||
}
|
||||
|
||||
|
||||
static int ProgressiveLoad()
|
||||
{
|
||||
wchar_t description[100];
|
||||
int progress_percent;
|
||||
int ret = LDR_ProgressiveLoad(100e-3, description, ARRAY_SIZE(description), &progress_percent);
|
||||
switch(ret)
|
||||
{
|
||||
// no load active => no-op (skip code below)
|
||||
case 1:
|
||||
return 1;
|
||||
// current task isn't complete (we don't care about this distinction)
|
||||
case ERR_TIMED_OUT:
|
||||
break;
|
||||
// just finished loading
|
||||
case 0:
|
||||
g_Game->ReallyStartGame();
|
||||
wcscpy_s(description, ARRAY_SIZE(description), L"Game is starting..");
|
||||
// LDR_ProgressiveLoad returns L""; set to valid text to
|
||||
// avoid problems in converting to JSString
|
||||
break;
|
||||
// error!
|
||||
default:
|
||||
CHECK_ERR(ret);
|
||||
// can't do this above due to legit ERR_TIMED_OUT
|
||||
break;
|
||||
}
|
||||
|
||||
// display progress / description in loading screen
|
||||
CStrW i18n_description = translate(description);
|
||||
JSString* js_desc = StringConvert::wstring_to_jsstring(g_ScriptingHost.getContext(), i18n_description);
|
||||
g_ScriptingHost.SetGlobal("g_Progress", INT_TO_JSVAL(progress_percent));
|
||||
g_ScriptingHost.SetGlobal("g_LoadDescription", STRING_TO_JSVAL(js_desc));
|
||||
g_GUI.SendEventToAll("progress");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u64 PREVTSC;
|
||||
|
||||
static void Shutdown()
|
||||
@@ -1227,6 +1267,9 @@ PREVTSC=CURTSC;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void Frame()
|
||||
@@ -1244,11 +1287,11 @@ static void Frame()
|
||||
assert(TimeSinceLastFrame >= 0.0f);
|
||||
|
||||
MICROLOG(L"reload files");
|
||||
|
||||
res_reload_changed_files();
|
||||
|
||||
MICROLOG(L"input");
|
||||
ProgressiveLoad();
|
||||
|
||||
MICROLOG(L"input");
|
||||
in_get_events();
|
||||
g_SessionManager.Poll();
|
||||
|
||||
@@ -1259,7 +1302,7 @@ static void Frame()
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->Update(TimeSinceLastFrame);
|
||||
|
||||
|
||||
if (!g_FixedFrameTiming)
|
||||
g_Game->GetView()->Update(float(TimeSinceLastFrame));
|
||||
|
||||
|
||||
+38
-15
@@ -6,6 +6,7 @@
|
||||
#include "gui/CGUI.h"
|
||||
#endif
|
||||
#include "timer.h"
|
||||
#include "Loader.h"
|
||||
|
||||
CGame *g_Game=NULL;
|
||||
|
||||
@@ -39,6 +40,42 @@ CGame::~CGame()
|
||||
debug_out("CGame::~CGame(): Game object DESTROYED\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSRETURN CGame::RegisterInit(CGameAttributes* pAttribs)
|
||||
{
|
||||
LDR_BeginRegistering();
|
||||
|
||||
// RC, 040804 - GameView needs to be initialised before World, otherwise GameView initialisation
|
||||
// overwrites anything stored in the map file that gets loaded by CWorld::Initialize with default
|
||||
// values. At the minute, it's just lighting settings, but could be extended to store camera position.
|
||||
// Storing lighting settings in the gameview seems a little odd, but it's no big deal; maybe move it at
|
||||
// some point to be stored in the world object?
|
||||
m_GameView.RegisterInit(pAttribs);
|
||||
m_World.RegisterInit(pAttribs);
|
||||
m_Simulation.RegisterInit(pAttribs);
|
||||
|
||||
LDR_EndRegistering();
|
||||
return 0;
|
||||
}
|
||||
|
||||
PSRETURN CGame::ReallyStartGame()
|
||||
{
|
||||
jsval rval;
|
||||
JSBool ok = JS_CallFunctionName(g_ScriptingHost.getContext(),
|
||||
g_GUI.GetScriptObject(), "reallyStartGame", 0, NULL, &rval);
|
||||
assert(ok);
|
||||
|
||||
debug_out("GAME STARTED, ALL INIT COMPLETE\n");
|
||||
m_GameStarted=true;
|
||||
|
||||
#ifndef NO_GUI
|
||||
g_GUI.SendEventToAll("sessionstart");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PSRETURN CGame::StartGame(CGameAttributes *pAttribs)
|
||||
{
|
||||
try
|
||||
@@ -54,21 +91,7 @@ PSRETURN CGame::StartGame(CGameAttributes *pAttribs)
|
||||
|
||||
m_pLocalPlayer=m_Players[1];
|
||||
|
||||
// RC, 040804 - GameView needs to be initialised before World, otherwise GameView initialisation
|
||||
// overwrites anything stored in the map file that gets loaded by CWorld::Initialize with default
|
||||
// values. At the minute, it's just lighting settings, but could be extended to store camera position.
|
||||
// Storing lighting settings in the gameview seems a little odd, but it's no big deal; maybe move it at
|
||||
// some point to be stored in the world object?
|
||||
m_GameView.Initialize(pAttribs);
|
||||
m_World.Initialize(pAttribs);
|
||||
m_Simulation.Initialize(pAttribs);
|
||||
|
||||
debug_out("GAME STARTED, ALL INIT COMPLETE\n");
|
||||
m_GameStarted=true;
|
||||
|
||||
#ifndef NO_GUI
|
||||
g_GUI.SendEventToAll("sessionstart");
|
||||
#endif
|
||||
RegisterInit(pAttribs);
|
||||
}
|
||||
catch (PSERROR_Game e)
|
||||
{
|
||||
|
||||
+5
-1
@@ -41,7 +41,8 @@ public:
|
||||
Return: 0 on OK - a PSRETURN code otherwise
|
||||
*/
|
||||
PSRETURN StartGame(CGameAttributes *pGameAttributes);
|
||||
|
||||
PSRETURN ReallyStartGame();
|
||||
|
||||
/*
|
||||
Perform all per-frame updates
|
||||
*/
|
||||
@@ -74,6 +75,9 @@ public:
|
||||
{ return &m_GameView; }
|
||||
inline CSimulation *GetSimulation()
|
||||
{ return &m_Simulation; }
|
||||
|
||||
private:
|
||||
PSRETURN RegisterInit(CGameAttributes* pAttribs);
|
||||
};
|
||||
|
||||
extern CGame *g_Game;
|
||||
|
||||
@@ -158,7 +158,7 @@ static bool HaveTimeForNextTask(double time_left, double time_budget, int estima
|
||||
// (if it's less than that, we won't check the next task length)
|
||||
if(time_left < 0.40*time_budget)
|
||||
{
|
||||
const double estimated_duration = estimated_duration_ms * 1e-3;
|
||||
const double estimated_duration = estimated_duration_ms*1e-3;
|
||||
// .. and the upcoming task is expected to be long -
|
||||
// leave it for the next timeslice.
|
||||
if(estimated_duration > time_left + time_budget*0.20)
|
||||
@@ -201,10 +201,10 @@ int LDR_ProgressiveLoad(double time_budget, wchar_t* description_,
|
||||
|
||||
while(!load_requests.empty())
|
||||
{
|
||||
const double time_left = end_time - get_time();
|
||||
const LoadRequest& lr = load_requests.front();
|
||||
double time_left = end_time - get_time();
|
||||
|
||||
// do actual work of loading
|
||||
const LoadRequest& lr = load_requests.front();
|
||||
ret = lr.func(lr.param, time_left);
|
||||
// .. either finished entirely, or failed => remove from queue
|
||||
if(ret != ERR_TIMED_OUT)
|
||||
@@ -228,6 +228,7 @@ int LDR_ProgressiveLoad(double time_budget, wchar_t* description_,
|
||||
// check if we're out of time; take into account next task length.
|
||||
// note: do this at the end of the loop to make sure there's
|
||||
// progress even if the timer is low-resolution (=> time_left = 0).
|
||||
time_left = end_time - get_time();
|
||||
if(!HaveTimeForNextTask(time_left, time_budget, lr.estimated_duration_ms))
|
||||
{
|
||||
ret = ERR_TIMED_OUT;
|
||||
@@ -237,7 +238,6 @@ int LDR_ProgressiveLoad(double time_budget, wchar_t* description_,
|
||||
|
||||
// queue is empty, we just finished.
|
||||
state = IDLE;
|
||||
assert(progress_percent == 100);
|
||||
ret = 0;
|
||||
|
||||
// set output params (there are several return points above)
|
||||
@@ -250,5 +250,7 @@ done:
|
||||
description = load_requests.front().description.c_str();
|
||||
wcscpy_s(description_, max_chars, description);
|
||||
|
||||
debug_out("LDR_ProgressiveLoad RETURNING; desc=%ls progress=%d\n", description_, progress_percent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "BaseEntityCollection.h"
|
||||
#include "EntityManager.h"
|
||||
#include "timer.h"
|
||||
#include "Loader.h"
|
||||
|
||||
#define LOG_CATEGORY "world"
|
||||
|
||||
@@ -41,6 +42,32 @@ void CWorld::Initialize(CGameAttributes *pAttribs)
|
||||
}
|
||||
}
|
||||
|
||||
struct ThunkParams
|
||||
{
|
||||
CWorld* const this_;
|
||||
CGameAttributes* const pAttribs;
|
||||
ThunkParams(CWorld* this__, CGameAttributes* pAttribs_)
|
||||
: this_(this__), pAttribs(pAttribs_) {}
|
||||
};
|
||||
|
||||
static int LoadThunk(void* param, double time_left)
|
||||
{
|
||||
const ThunkParams* p = (const ThunkParams*)param;
|
||||
CWorld* const this_ = p->this_;
|
||||
CGameAttributes* const pAttribs = p->pAttribs;
|
||||
|
||||
this_->Initialize(pAttribs);
|
||||
delete p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CWorld::RegisterInit(CGameAttributes *pAttribs)
|
||||
{
|
||||
void* param = new ThunkParams(this, pAttribs);
|
||||
THROW_ERR(LDR_Register(LoadThunk, param, L"CWorld", 1000));
|
||||
}
|
||||
|
||||
|
||||
CWorld::~CWorld()
|
||||
{
|
||||
// The Entity Manager should perhaps be converted into a CWorld member..
|
||||
|
||||
+5
-2
@@ -18,6 +18,7 @@ class CWorld
|
||||
// been converted
|
||||
CUnitManager &m_UnitManager;
|
||||
CEntityManager &m_EntityManager;
|
||||
|
||||
public:
|
||||
inline CWorld(CGame *pGame):
|
||||
m_pGame(pGame),
|
||||
@@ -28,11 +29,13 @@ public:
|
||||
|
||||
~CWorld();
|
||||
|
||||
void RegisterInit(CGameAttributes *pGameAttributes);
|
||||
/*
|
||||
Initialize the World - load the map and all objects
|
||||
Initialize the World - load the map and all objects
|
||||
*/
|
||||
void Initialize(CGameAttributes *pGameAttributes);
|
||||
|
||||
|
||||
|
||||
inline CTerrain *GetTerrain()
|
||||
{ return &m_Terrain; }
|
||||
inline CUnitManager *GetUnitManager()
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "CConsole.h"
|
||||
#include "Unit.h"
|
||||
#include "Model.h"
|
||||
#include "Loader.h"
|
||||
|
||||
#include "gui/CGUI.h"
|
||||
|
||||
@@ -37,6 +38,34 @@ void CSimulation::Initialize(CGameAttributes *pAttribs)
|
||||
g_EntityManager.InitializeAll();
|
||||
}
|
||||
|
||||
|
||||
struct ThunkParams
|
||||
{
|
||||
CSimulation* const this_;
|
||||
CGameAttributes* const pAttribs;
|
||||
ThunkParams(CSimulation* this__, CGameAttributes* pAttribs_)
|
||||
: this_(this__), pAttribs(pAttribs_) {}
|
||||
};
|
||||
|
||||
static int LoadThunk(void* param, double time_left)
|
||||
{
|
||||
const ThunkParams* p = (const ThunkParams*)param;
|
||||
CSimulation* const this_ = p->this_;
|
||||
CGameAttributes* const pAttribs = p->pAttribs;
|
||||
|
||||
this_->Initialize(pAttribs);
|
||||
delete p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSimulation::RegisterInit(CGameAttributes *pAttribs)
|
||||
{
|
||||
void* param = new ThunkParams(this, pAttribs);
|
||||
THROW_ERR(LDR_Register(LoadThunk, param, L"CSimulation", 1000));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CSimulation::Update(double frameTime)
|
||||
{
|
||||
m_DeltaTime += frameTime;
|
||||
|
||||
@@ -33,8 +33,9 @@ public:
|
||||
inline CTurnManager *GetTurnManager()
|
||||
{ return m_pTurnManager; }
|
||||
|
||||
void RegisterInit(CGameAttributes *pGameAttributes);
|
||||
void Initialize(CGameAttributes *pGameAttributes);
|
||||
|
||||
|
||||
// Perform all CSimulation updates for the specified elapsed time.
|
||||
void Update(double frameTime);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user