Now that the resource loading is asynchronous, I would like to add a loading screen for resources, and a progress bar.
As mentioned here: http://www.orxproject.org/forum?func=view&catid=16&id=6946#6969
I can query the resource module to know when a resource is loaded.
Is it possible to turn off async loading so that I can update the progress bar after each orxObject_CreateFromConfig statement, or is it better practice to subscribe to the:
and listen for a
and update the progress bar that way.
I could update the count of objects I expect to load and clear away the loader screen when that count is reached.
Just wanted to check that as best practice before I start.
For starter, only textures and sounds are loaded asynchronously by orx (though you can load your own extra resources asynchronously if you have any).
Secondly, orxRESOURCE_EVENT_ADD is not what you want. It's an event used by the resource watcher in order to support hot reload. You should deactivate it when releasing your game as resource won't change on disk anymore.
Now for you progress bar issue, turning async loading off is probably not the best answer, as your main loop will be blocked by disk access all the time, resulting in a very choppy framerate.
As a side note, you can't prevent sounds from being loaded asynchronously, however you can ask textures to be loaded synchronously by removing the temporary texture (orxDisplay_SetTempBitmap). Also it's good to know that sounds are processed on their own separate thread, they don't use the resource thread.
Which brings us to the options available to you:
- You could count how many textures you'd need to load and then listen to the orxTEXTURE_EVENT_LOAD, when both numbers match, texture loading is over. I don't think it's the easiest way to do it though.
- You could create all objects at once (I usually have them all in a single hierarchy whose root I often call "Scene"). When the call to create all those objects is done, you can now easily setup your progress bar as you can poll how many pending resource operations are left by calling orxResource_GetTotalPendingOpCounter(). When this counter reaches 0, you're done loading.
To sum it up, here's how I'd do it:
- Create your loading screen/progress bar, this way resource will be handled first for them
- call orxObject_CreateFromConfig("Scene")
- call orxResource_GetTotalOpCounter(), match that number with your whole progress bar, ie. if you have X operations pending at that moment, everytime one operation is processed, your bar progresses by 1/Xth.
- Every update call orxResource_GetTotalOpCounter(), update your progress bar accordingly. When reaching 0, delete the loading screen and continue on your merry way.
Lemme know if you see any obvious issue with this approach.
This sounds like a very nice solution, but it doesn't work well (under orx-1.6). I've tried to start with a very simple loading screen, that just says "Loading..." until all the assets are loaded. I did this by having an initial camera whose GroupList contains only the loading screen objects (the "Loading..." text), then I've created my scene as usual. Then in my run callback, I query the orxResource_GetTotalPendingOpCounter, and switch to my main camera when it returns 0. The trouble is that this happens too soon.
When I switch to the main camera, I can still see that the background texture is missing for a brief second. In order to make it more visible, I've tried using a very large texture that takes 3-4 seconds to load, and I can clearly see that the loading screen exits too soon. In order to make sure that I'm not making a mistake while preloading the scene, I've instead tried to keep the loading screen by waiting for 5 seconds (instead of waiting for the orxResource_GetTotalPendingOpCounter). In this case, there was no brief white background, so the loading does take place while the loading screen is displayed.
Here's the sequence I follow:
I've checked the source code of Raster Blaster Pinball to see how Sausage ended up doing it, and it seems that he's ended up counting the number of texture load events and comparing the number to a predefined constant. I wish there were a more automated way (including sounds) to do this. Iarwain's recommendation does seem to be the perfect solution, but orxResource_GetTotalPendingOpCounter doesn't return the right thing. Maybe it returns the number of operations that hasn't started yet? There's something clearly wrong because I can see that orxResource_GetTotalPendingOpCounter returns 0 within 20ms or so...
By the way, it's easy to preload textures without showing them, but what's your suggestion about doing the same for sounds? Should I play dummy sounds whose volume is 0? Or is there a better way?
Let me know if that fixes your issue. If not, if you could have a small setup for me to investigate, that would be appreciated.
Regarding the sounds, what I usually do (it only works for sounds that have the config property KeepInCache set to true), is that I create them and delete them right away: the samples will get loaded but never played. I usually do this at the orxOBJECT level. One can even simply set dummies with a lifetime of 0, something like this (though I haven't tried it myself):
Actually check Bean Farmer Pinball code instead. Raster Blaster will be changed.
Interested to see what happens here because I think my routine is still flawed. In the case of Android (and only Android), sometimes the game load freezes at ~95%. All other versions are fine.
Seeing what Iarwain wrote, I have some patching to do with loading on Android.
I've just tried with the linux64 2015-02-24 nightly build, and the problem persists. I've attached a minimal setup, which tries to preload a large background image with a loading screen. You can see that there's a significant gap between the "loading..." text disappearing and the actual background texture appearing.
That's quite convenient, thanks
sausage wrote: Thanks, I'll check it as soon as I find some time https://forum.orx-project.org/uploads/legacy/fbfiles/files/loading_question.zip
I was afraid of that, and now that you confirmed it, we'll need to find a way to work around, beside listening to all texture load events.
One option would be to have a "start" texture load event, this way it'd be easy to know how many are pending without knowing how many textures are handled. I like this one, because it's an easy one.
Unfortunately the decompression is handled on a separate thread, via the task system, but there isn't any good query API yet, all that is available is orxThread_GetTaskCounter(), which won't filter out on task types. So I guess another option would be to add types to tasks and a way to filter them out on queries. I like it a bit less because it's more work for a rather independent problem, in the end.
What do you think?
PS: Thanks for the testbed, I'll use it to test whichever solution gets implemented.
My next version of the game loader was going to increment a texturesToLoad ((int)) variable on every start event, and then decrement on every loaded event.
That way I would guarentee the numbers match dynamically.
My only concern was the possibility that 5 start events could fire, and 5 loaded events could fire before any more starts which means that the loader would think it was finished.
Might need a delay at the end of the routine just in case to test for any further start events.
I'll write it and try it out. This doesn't address the decompression issue, but perhaps the forced delay does for now.
As for a delayed check, that should be rather straightforward to do with a simple orxClock_AddGlobalTimer(), if need be.
Another option would be to wait for a custom event (or input, they're handy for this as well) that the user would fire when he knows that all the texture loads have been queued. Only then will the test wait for the load counter to go back to 0.
I guess I could also manage a pending load counter directly inside the display plugin (or the texture module), which would simplify one's work on the client side.
Are you saying that the orxTEXTURE_EVENT_LOAD doesn't fire until the file load and decompression of the texture is totally complete? Is that's the case, then I probably have everything I need to solve my particular case.
Unless I'm overlooking something.
I need it for my animations. When I change the animation of the soldier (for instance going from idle -> walk) in my game, sometimes the underlined texture isn't loaded and it would be great if I could find this out. Otherwise, for first couple of frames, the soldier is "teleported" to some location - because the texture isn't loaded yet. If I could then query the status of the texture, I could postpone the walk operation till the texture is fully loaded.
Anyway, I think that handling the async resource management is a bit tricky. This is mainly because of inter-thread communication. There could still be point in the time when the system reports that all textures are loaded, but some may be added only recently and not noticed by the loading thread. Or could it?
I think that some kind of determinism is needed there. For instance some hierarchical texture loading. For instance, make some root resource in the scene, and then parent all the other resources (textures, ...) to this root resource. And then wait for the root resources for complete, while querying the other resources status as was proposed by iarwain. I don't if it is possible to implements this.
When are you planning to send the "start" event? When you start accessing the disk, or decompressing the data? I think the former would solve the problem in combination with GetTotalPendingTaskCounter.
I was also thinking about maybe doing this the other way round. Instead of counting unknown resource load events, we could also test our objects to see whether they've loaded all the resources they need. For instance, if we had a function like orxBOOL orxObject_AllResourcesReady(), we could recursively walk our object hierarchy (The real scene, or the preload dummy scene) and check if everything is in place. I think this would also be a more generic solution, enabling the loading of a level in phases. If we could disable the sounds on dummy preload objects without killing them, this solution would even extend to sound preloading. It would also be more "functional" since it only relies on the current state of the world, instead of watching events over a period of time. This is also similar to Trigve's suggestion if I'm not misunderstanding.
NP In any case, I needed to prepare something similar to it, to experiment with the loading screen.
Trigve: Sure, I can an orxTexture_IsReady() if that's what you meant. It'd rely on the underlying events to update its status. For the resource hierarchy, I'm not sure how to do that in a simple fashion, for both the engine and the end user.
Enobayram: The "start" event would be sent upon as soon as the loading request is received, ie. even before starting the disk access task. The way I was seeing it was with a orxTexture_GetLoadingCounter() for example, that would reflect at any time how many textures are in the process of being loaded. When that number is 0, it means it's safe, as in no visual glitches will appear, to use any of the textures.
The orxObject_AllResourcesReady() is also an option, but that would mean knowing exactly all the components and adding another redundancy for testing all different resources, which I'm not a huge fan but could live with, if need really be.
You can disable the sound on dummies, either by pausing them upon creation or simply deactivating the owner object. I personally prefer the separate pre-load option (ie. not linked to the objects themselves but done in bulk at a given time) as this way I know two things:
- no extra delay will be incurred when creating the object
- no out-of-memory is likely to happen as all the resources that I'm going to use have already been loaded at the same time
- I don't have to do any post-processing of my objects, I keep things data-driven by having the preload sections on one side, and the "live" ones on the other side, all I do is simply a one liner of creating an object hierarchy and having to inspect/modify it later on: the pre-load one deletes itself, the live one does what it's supposed to do
But it's really a matter of personal preference, nothing more.
Actually, GetLoadingCounter() would solve my current loading problems. Except for sound, I know that sounds don't take long to load, but the human eye-ear coordination is precise enough to notice a millisecond delay in a pop sound, that was supposed to be synchronized to an object creation. So, if you're planning to "pop" objects right after the loading screen, you'd better be sure that the pop sound is already cached. I suggested orxObject_AllResourcesReady to solve a more general problem, where you might be separately interested in the statuses of subsets of your textures. Not that I need it now, nor that I have future plans that require it, just overengineering as a habit I'm trying to quit. I totally agree on the redundancy point though.
First step would be to add the same notification pipeline for sounds (right now they're entirely loaded on a separate thread and no event is sent later on on the main thread). Then, when it's unified, we'd need to think how much control we want to give to the user and how much automatization we want to provide.
In the simple case of using an object when everything's ready in it, that's not too bad, complexity comes in when people manually chunks resource and plug them on the fly in their animation sets, for example.
But for now, I'll try to homogenize the notification systems on textures and sounds. What do you think?
Your suggested orxTexture_IsReady() would be handy, but I would also need some functionality to get associated texture for the given animation. Some pseudo code:
I like your last idea, to have some mechanism to know if the object is ready for the use. It was like the thing I was suggesting, maybe described badly in my post.
How will it treat the hierarchies? Will the root object be ready to use only if all the children are ready to use?
Another question is how would the complicated scene be loaded (similar to your example of "manually chunks resource and plug them on the fly" - I'm in that camp too) . I start the new scene. Show the loading screen, wait for the root object to be ready. But meantime, some other objects could be created by some already-ready objects and so waiting could be prolonged (or in theory, infinite if there are some cyclic dependencies:) ). Should I therefor after loading the root object pause it and wait till the object (and all the children automatically) would be in the ready state and only then unpause it and let it go?
Now, in your example, when for instance the animation sets are created on the fly, the root object could be in the ready state in no time. But how would we know if all the "dynamic" stuff is in ready state? I do think that it is responsibility of the user to signal if the given object is in the ready state or not. But how would it be implemented? Maybe sending some ready event? Or some orxObject_SetIsReady() function?
I think it would be reasonable to expect that if you're doing fancy stuff dynamically, you're responsible for making sure that everything is preloaded by the time you need them. If orxObject_IsReady (or something like that) takes care of what's visible in the config, one can easily preload dummy objects containing any extra resources. IMHO, that would be a nice compromise between automatic vs. manual. So maybe, if you have a simple scene, just create it during the load screen, but if you have more complicated stuff, load dummy objects in addition to your scene to take care of the fancy stuff.
I think that would be nice on its own, and it would certainly satisfy my current loading screen needs
I think it all depends on the implementation of the orxObject_IsReady(). I would welcome if the orxObject_IsReady() would scan the actual object (and also the children if some param is set to true) to find the all resources needed for the object and returning true if all of them are ready. Then all I need is this functionality and I take care of everything else myself. If the orxObject_IsReady() would be implemented in this fashion, I think no dummy objects may be needed.
I'm not a fan of dummy objects
Here is the workflow I would probable use:
New scene loading - Load the actual scene from some file (or as part of old game load), create loading screen, create objects. Based on the object state (for instance soldier state - idle, walk, crouch, ...), change/add/delete stuff from the object (animation, effects, texture, ...). Now pause all objects so no state change could occurs. Wait till the root object's orxObject_IsReady() returns true (or if you have list of all your objects, you can iterater over it and call orxObject_IsReady() for each of them). Disable loading screen. Unpause root object.
My 2 cents. I may be wrong, so feel free to point it out
is there a reason why for preloading texture i can just do
but for sample i need to do
also, why is there a KeepInCache for Sound but not for Graphic (i know that for a Graphic that means to keep the whole Texture)
The reason is that there's an extra indirection with sounds.
Textures map to the image files, whereas sounds map either to sample files or streams.
You'll find the corresponding functions in the orxSoundSystem API (orxSoundSystem_CreateStreamFromFile & orxSoundSystem_LoadSample). However if you were to call them directly, the Sound module wouldn't know about them, so it wouldn't be of much help with respect to caching/pre-loading.
Lemme know if there's any issue with that. I'll investigate the sound part soon.
Just revisiting this problem now that the orxTexture_GetLoadCounter has been introduced. I managed to greatly improve my texture loader bar routine.
However the intermittent race condition during texture loads for Android still occurs.
In short, the texture loading process for desktop platforms is fine. But in 50% of cases, an Android application will seize. I know the application has not fully frozen or crashed, as the music can still be heard in the background until the watchdog on the android device finally resets it.
I simplified my Texture Handler to help diagnose the problem. I removed unnecessary code, so that it just outputs the event type and the texture count remaining:
Using this code I managed to produce the log from the Android device. See attached. Notice that on Init(), there are already 7 textures to load. This rises up to 38 Create Events, and then this decreases as the Loading Events fire.
Finally we get to 8 textures remaining, where the something goes a little haywire.
Again, this is only a problem on Android. Perhaps this is mostly a post for lydesik, but interested on any general thoughts. https://forum.orx-project.org/uploads/legacy/fbfiles/files/texture1.txt
Also, what is the log result on desktop, to compare?
Cool, will upload a version with creation names as well.