Triggering redraw from events rather than in a loop
Hi, I'm trying to implement kind of an editor tool. The screen should be redrawn only when there's a user action (mouse move, key press, touch event...), but not in a continuous loop (as it's going to kill the battery on mobile platforms). I'm a bit stuck here. I tried returning AppState::Blocked from OnInit but then, of course the app is blocked. I could not find any example in the samples triggering a redraw 'manually' from within an event handler, and it looks also that whenever the app is blocked, there's a hard coded delay of 100 ms before running the internal loop again.
Is there a way with Oryol to do this? Any code snippet?
Thank you!
Pascal
Phew, I haven't thought of that use case, usually games try hard to render at 60 fps...
I wouldn't use the Blocked AppState, this was for some esoteric situation on Android.
As a workaround I would try to still do everything in the OnRunning, and have a flag 'needsRedraw', in this case update the rendered scene and call Gfx::CommitFrame(), this should update the displayed image on all platforms, then delete the needsRedraw flag. In the else-branch (of if (needsRedraw)). I think you still need to return from time to time to the OS, even if you don't want to render something.
Does that make sense? :) If this doesn't work, or is too hacky we might need to come up with a solution in the App class.
Hmm hmm, my suggestion wouldn't work that well with an event-handler that's called from the OS though... on some platforms (usually mobile) the entire Oryol frame is running from within an OS callback, which is either triggered by a timer, or by the vsync. One possible solution would be to allow to 'hijack' the entire Oryol frame-callback from a piece of user-provided code (which in your case would be your own event-callback)... I think that sounds doable...
Do you have some more information or even some code to look at, for instance what operating system's you want this to work on, and how those redraw-events would be triggered?
Hi,
I don't really have code to show (yet) but I have a good idea how what I want to achieve:
-I'm trying to implement an editor using basically 3 layers. The top layer is a UI (based for example on turbo badger, or maybe directly nanovg + custom event management) -the second layer is used to display "vector" objects like selection rectangles, handles to move the objects. and I need specialized event handlers for these objects (basically whatever is not captured by the first layer will be passed to the 2nd layer) -the 3rd layer can either use 2D primitives (editing mode) or 3D primitives (visualization mode).
The target operating systems for development are Linux, OS-X and Windows (by development, I mean developers should be able to develop/test/debug easily on these platforms). The target deployment systems will be IOS, Android, and Emscripten.
The way I see it is that during initialization, I will install callbacks for all events (just the way it's done in the turbo badger integration code for example). Whenever an event occurs, I'll have some logic to re-dispatch the event either to the UI logic, or the different layers logic. Whenever something has changed on the screen as a consequence of the user interaction, I'll call my drawing code. Of course, for this to work the App should be integrated in the target OS/GUI main event loop (through the event callbacks), rather than using its own loop. This means also that the renderer can be single threaded, as every time there's an event we accept that the UI is blocked until all redraws have been done.
I know how to do this using pure GL/GLES + either Linux/emscripten/android, but there are so many nifty things in Oryol that I'd really like to use it :-) Plus I like the coding style and the general 'lean' mindset of your framework.
If I understand you well, the OnRunning will be called either from the vsync or with a timer (supposedly running at 30 hz or 60 hz). As you said, in OnRunning I could return immediately if the redraw is not required (checking a dirty flag set by the application, or if the screen size has changed). This can work if there's no 'magic code' before and after OnRedraw (like an automatic screen cleanup for example). Battery wise, it would cost 60 callback calls per second executing almost no code, so it may be acceptable (only tests could tell).
What do you advise?
I need to think a bit about this, currently I'm a bit wrapped up in the UWP stuff. I think the 60 Hz 'nearly do nothing' idea is the way to go. Using a 'built-in' UI will definitely be easier than trying to hook the render callback to an operating system UI event.
I'm not sure if there will be a chicken-egg-situation with Turbobadger or input event handling (I think we'll need to keep the input event loop alive).
I haven't much experience with such event-driven rendering, so far I was only using a fairly dumb render loop where each frame was fully rendered.
Since there's no 'proper' solution yet and I don't have a strong opinion about how it should work, you could try out what would be the minimal changes required on Oryol to make it work and provide a pull request :) If you debug-step out of OnRunning into the App class you get a good idea what's going on under the hood. Rendering is fully controlled in user-code, there are no behind-the-scenes changes. Some modules (like Input) install per-frame runloop callbacks, but not Gfx.