   Creating a loading screen with progress bar
  Hey!I have been trying to come up with a nice enough way to create a loading screen with a progress bar. My design so far goes like this:MainLoop()    CurTime = timeGetTime();    if (CurTime > LoadingTimer + LOADING_TIME_INTERVAL)   if (LoadingStatus != LOADING_ENDED)  LoadGame()  LoadingStatus++  SetLoadingBar(LoadingStatus)  LoadingTimer = CurTime   End    EndEndStartGame()    LoadingStatus = 0    LoadingTimer = timeGetTime()    LoadGame()EndLoadGame()    switch (LoadingStatus)   case 0  SetupSomething()  break   case 1  SetupSomethingElse()  break   case 2  SetupLastThing()  break    EndEndAs you can see, it goes through a loop every set interval (even if loading has finished up during the interval, it will simply wait until the interval time runs out and then continue with the next iteration of the loading cycle.Is this a good way of doing a loading procedure? I am guessing there are other ways, but this is the one I am capable of coming up with.   
  Have your load function accept a callback that takes the progress as a parameter. In the callback, update the progress bar. Using this method its also pretty easy to make a system to cancel loading too.C++:bool Callback(float Progress){   // update progress bar   return cancel;}void LoadGame(bool (*ProgressUpdate)(float)){   for(int i = 0; i < tasks; i++)   { // do task if(ProgressUpdate((float)i / (float)tasks))    return;   }}...LoadGame(Callback);This will call the callback every time a task is finished, and every time it gives the callback the opportunity to cancel loading (by returning true).   ;  I would wack the loading bar into another thread.  The problem your going to get with your method is that the loading  bar will jerkily move along as different files take different amounts of time to load.  Whereas putting it on another thread will solve that issue.  ( assuming of course that you've got the processin power to do so, which shouldnt really be a problem ).Check out flipcode, theres a tutorial on there somewhere on how to use threads, quite useful.   ;  If you're using OpenGL or DirectX, using the graphics API from another thread has problems that might not be immediately obvious.What I do is put a callback into my resource manager template, such that the global loading screen gets a poke each time a new resource is loaded from disk.Then, I create a full-screen texture with the background, and draw that to the screen within the loading screen.Thus:MainLoop:  if environment.levelToLoad != null then    environment.loadingScreen = new LoadingScreen(levelToLoad + ".jpg");    environment.loadingScreen.Display();    ClearCurrentLevel();    LoadLevel(levelToLoad);    levelToLoad = null;  endifResourceLoader<Resource>:  GetResource(name):    if cache.HasResource(name) then return cache.Resource(name)    endif    if environment.loadingScreen != null then environment.loadingScreen.Poke(name)    endif    resource = new Resource(name)    cache.SetResource(name, resource)    return resource;  Another possible consideration is that loading is often a hierarchical process. For example, loading a level might involve multiple steps, one of which is to load meshes. Each mesh might have multiple submeshes, each of which needs to load verts, indices, materials, and so forth.Ideally, the progress bar should reflect this hierarchy and update during the sub-steps as well. One way to do this is to have the progress bar store a state which can be pushed and popped. When the state is pushed, subsequent updates operate in the range of the progress bar associated with the previous state.I've found this to work well, but I'm sure there are other (perhaps better) ways of doing it.   ;  What we do is split up our LoadLevel call into a series of subfunctions, each of which is registered into a queue. The main loop works off items in queue until time slice is up, and then continues (i.e. renders progress bar). For subfunctions (e.g. LoadAllWaterTextures) that would take much longer than a 200ms slice, we convert them into a coroutine that can yield, i.e. return control every 200ms.hplus0603: do I understand you correctly in that the main loop is 'frozen' in your approach and LoadLevel is responsible for rendering the progress bar / checking for key presses (e.g. cancel loading/quit immediately)?How do you interrupt lengthy portions of LoadLevel - do you also use coroutines, or call into a PumpMessagesAndRender function from several spots?While coroutines in C++ definitely take some getting used to, our method does mean the all the handy stuff in the main loop is available and doesn't need to be copy-pasted. Also, there's no worry about gnarly call order issues, where stuff called by PumpMessagesAndRender may be reentered if you're not careful.Sure would be nice to go with threads and events, but sadly that's not realistic since we are using OpenGL and SDL (-> not much control over message pump) and it needs to work on several platforms.   ;  As for knowing how far along the progress you are, I heard a good idea on a mailing list:Have an update/poke or whatever function in the loading bar class, which is called at certain points during loading.The first time you run through a load of a certain set of resources, the loading bar is in 'measure' mode, where it just counts the pokes. After the measuring is done, the next time the same resource set is loaded you will know how many pokes to expect and therefore what point you are up to in the overall loading.If you do this all in one thread, something I found to be careful of with this system is making the pokes more frequent than the refresh rate. On my dev PC vsync was off and I poked the loading bar for every row of the heightmap - nice smooth loading bar :) But on my friends PC with vsync the loading had to wait for screen refreshes and was real slow.   ;  @zppz: you also seem to be using the PumpMessagesAndRender approach also. Am I correct in that assumption, or is there yet another approach?Quote:The first time you run through a load of a certain set of resources, the loading bar is in 'measure' mode, where it just counts the pokes. After the measuring is done, the next time the same resource set is loaded you will know how many pokes to expect and therefore what point you are up to in the overall loading.Interesting. One disadvantage to this approach is that you have to save the poke results to file; or is it acceptable to not display anything during the first load after every startup?Also, if intervals between pokes vary widely, the perceived progress bar movement is not as smooth as if you had estimates of how long each step takes. That's pretty trifling though, and estimates would have to be kept up to date (can be done every 4 weeks or so with about 5min of work, which is ok).I forgot to mention this above. When queuing up our subtasks, we pass a rough estimate [ms] of their duration. When a task completes (or coroutine yields), the progress percentage is advanced accordingly to estimated_duration / total_estimated_durations.This works quite well because even if loading takes some multiple of the reference system (from which estimates are derived), the relative progress percentage is still correct. Effects such as differing CPU vs. HD speeds may cause nonlinear changes to subtask duration, but that only results in slightly less constant/homogenous changes.Documentation follows:/*Overview--------"Loading" is the act of preparing a game session, including reading allrequired data from disk. Ideally, this would be very quick, but for complexmaps and/or low-end machines, a duration of several seconds can be expected.Having the game freeze that long is unacceptable; instead, we want to displaythe current progress and task, which greatly increases user patience.Allowing for Display--------------------To display progress, we need to periodically 'interrupt' loading.Threads come to mind, but there is a problem: since OpenGL graphics callsmust come from the main thread, loading would have to happen in abackground thread. Everything would thus need to be made thread-safe,which is a considerable complication.Therefore, we load from a single thread, and split the operation up into"tasks" (as short as possible). These are typically function calls from theold InitEverything(); instead of being called directly, they are registeredwith our queue. We are called from the main loop and process as many tasksas possible within one "timeslice".After that, progress is updated: an estimated duration for each task(derived from timings on one machine) is used to calculate headway.As long as task lengths only differ by a constant factor between machines,this timing is exact; even if not, only smoothness of update suffers.Interrupting Lengthy Tasks--------------------------The above is sufficient for basic needs, but breaks down if tasks are long(> 500ms). To fix this, we will need to modify the tasks themselves:either make them coroutines, i.e. have them return to the main loop and thenresume where they left off, or re-enter a limited version of the main loop.The former requires persistent state and careful implementation,but yields significant advantages:- progress calculation is easy and smooth,- all services of the main loop (especially input*) are available, and- complexity due to reentering the main loop is avoided.* input is important, since we want to be able to abort long loads oreven exit the game immediately.We therefore go with the 'coroutine' (more correctly 'generator') approach.Examples of tasks that take so long and typical implementations maybe seen in MapReader.cpp.Intended Use------------Replace the InitEverything() function with the following:  LDR_BeginRegistering();  LDR_Register(..) for each sub-function (*)  LDR_EndRegistering();Then in the main loop, call LDR_ProgressiveLoad().* RegMemFun from LoaderThunks.h may be used instead; it takes care ofregistering member functions, which would otherwise be messy.*/;Original post by Jan WassenbergQuote: ....   Documentation follows:*** Source Snippet Removed ***....one thing that i am struggling with is that i have a GUI for the user to pick which data to load..so for my problem i have already initialized the opengl window and at so at runtime i want to load the data plus load a progress bar. The second problem i have is that i want something cross platform and i am developing using VS .NET 2003 so its in windows but do not want to use windows only calls for cross platforms sake.;  Having nothing showing the first run would not really be an option, so yes, I saved the result from a 'measure' run to a file before release. That was back in the day though (google zpracer)... I do the loading differently now - which brings my to the next point: interesting that you mention about opengl and threads etc. There was a discussion recently in the Opengl forum about loading resources while rendering which you might want to take a look at: hereWith the 'measure' method as it was pointed out if the user can choose what resources are to be loaded, you would need to figure out the smallest uninterrupable blocks of loading and measure them individually, then use the total of that as the number of expected pokes when loading them all together.As for the jerkiness of loading progress, yeah I spent some time placing the poke calls to get a reasonably smooth progress bar. However remember this is just a loading screen.. even ten increments ought to be enough, and many professional games dont really have much more than that. After a while the user will become accustomed to how fast parts of the progress go anyway, I know I sure did the 100th time I loaded a difficult Baldur's gate scene after dying :)   