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:
janwas 2005-03-22 02:17:55 +00:00
parent 5e3b0f06ec
commit 6d792365aa
13 changed files with 246 additions and 45 deletions

View File

@ -36,8 +36,16 @@
<object type="button" name="loading_screen_titlebar_text" size="15%+54 4 85%-54 32" absolute="false" font="prospero18" z="165" text_align="center" text_valign="center" hidden="false"/>
<!-- progress bar -->
<object type="button" name="loading_screen_progress_bar_text" size="0%+32 100%-205 100%-32 100%-185" font="tahoma14" textcolor="0 0 0" text_align="center" text_valign="center" z="165" hidden="false"/>
<object type="progressbar" name="loading_screen_progress_bar" style="blue_bar_outlined" size="0%+32 100%-185 100%-32 100%-160" z="165" hidden="false"/>
<object type="button" name="loading_screen_progress_bar_text" size="0%+32 100%-205 100%-32 100%-185" font="tahoma14" textcolor="0 0 0" text_align="center" text_valign="center" z="165" hidden="false">
<action on="Progress">
this.caption = g_LoadDescription;
</action>
</object>
<object type="progressbar" name="loading_screen_progress_bar" style="blue_bar_outlined" size="0%+32 100%-185 100%-32 100%-160" z="165" hidden="false">
<action on="Progress">
this.caption = g_Progress;
</action>
</object>
<!-- concept image -->
<object type="image" name="loading_screen_background_concept" sprite="black_bkg" size="32 32 33.3008%+32 88.9323%+32" z="110" hidden="false" />

View File

@ -42,24 +42,43 @@ function startLoadingScreen()
getGUIObjectByName("loading_screen_tip").caption = "Wise man once say ...\nHe who thinks slow, he act in haste, be rash and quick and foolish. But he that thinks too much, acts too slowly. The stupid always win, Commandersan. Remember that. You are tiny grasshopper.";
// Begin game session.
setTimeout( loadSession, 200 );
// setTimeout( loadSession, 200 );
startGame(); // new version returns quickly; we will hit the main loop
// occasionally, so need for evil timeout hack
}
// ====================================================================
function loadSession()
{
if (! startGame())
{
// Failed to start the game; go back to the main menu. TODO: display an error message.
GUIObjectHide("loading_screen");
GUIObjectUnhide("PREGAME_GUI");
// Show an error message
btCaptions = new Array("OK");
btCode = new Array("");
messageBox(400, 200, "The game could not be started with the given parameters. You probably have entered an invalid map name.", "Error", 0, btCaptions, btCode);
}
//function loadSession()
//{
// if (! startGame())
// {
// // Failed to start the game; go back to the main menu. TODO: display an error message.
// GUIObjectHide("loading_screen");
// GUIObjectUnhide("PREGAME_GUI");
// // Show an error message
// btCaptions = new Array("OK");
// btCode = new Array("");
// messageBox(400, 200, "The game could not be started with the given parameters. You probably have entered an invalid map name.", "Error", 0, btCaptions, btCode);
// }
//
// // Create resource pools for each player, etc.
// setupSession();
//
// FlipGUI(GUIType);
//
// // Select session peace track.
// curr_session_playlist_1 = newRandomSound("music", "peace");
// // Fade out main theme and fade in session theme.
// CrossFade(curr_music, curr_session_playlist_1, 0.0001);
//
// // Switch GUI from main menu to game session.
// GUIObjectHide("loading_screen");
// GUIObjectUnhide("SESSION_GUI");
//}
function reallyStartGame()
{
// Create resource pools for each player, etc.
setupSession();
@ -68,7 +87,9 @@ function loadSession()
// Select session peace track.
curr_session_playlist_1 = newRandomSound("music", "peace");
// Fade out main theme and fade in session theme.
CrossFade(curr_music, curr_session_playlist_1, 0.0001);
CrossFade(curr_music, curr_session_playlist_1, 0.1);
// janwas: greatly accelerate this timesink;
// will be replaced soon by native version that doesn't block.
// Switch GUI from main menu to game session.
GUIObjectHide("loading_screen");

View File

@ -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);

View File

@ -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*

View File

@ -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.

View File

@ -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));

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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..

View File

@ -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()

View File

@ -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;

View File

@ -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);