Ticker for front scene only
tlvenn opened this issue · comments
Hi,
Currently the scene config and the ticker code assumes that if you want a ticker, you want it to cover both scenes but there are scenarios where you want control over when to render / update the back scene which contains heavy things to draw but let Graphx redraw the front / hud scene automatically.
Could we have an enum (tickerScope
maybe ?) in the scene config to drive this ? I think you either want both
or front_only
.
Is a good point, my understanding is that Darts ticker will request a new frame to the backend window, forcing a rendering in the CustomPainter anyway, I might be wrong though. The only way i know you can save redrawing is a RepaintBoundry() widge. Its been a while since i check graphx internals… But i guess a custom class that overrides SceneController behaviour when creating the CustomPainter might do the trick of skipping update/render calls per Scene
Thanks for your quick reply @roipeker
My knowledge on this topic is limited, when I saw this code
https://github.com/roipeker/graphx/blob/master/lib/src/core/scene_controller.dart#L125
I though it would be trivial to simply tick the front scene only instead of ticking them both depending on the config but I don't fully understand what is happening behind the scene (no pun intended lol) and whether it's possible to actually only have the foreground painter to update without triggering the main / background painter as well.
@tlvenn Yep, the flow is not straightforward, and code lacks docs comments.
Basically, SceneBuilderWidget is the only Widget
in GraphX: initializes the basic flutter widgets needed to render ( CustomPaint
) and get input context signals (mouse/pointer/keyboard).
SceneController initializes the logic of the scene. Creates the Ticker, outputs the CustomPainters
(what u need to change), and creates the "managers" for inputs called by the SceneBuilderWidget
widgets events.
When you pass back
and front
"scenes" (GSprites), it creates an internal ScenePainter
which is the top most "object" between the Canvas and GraphX stage. That's the key for "repainting" ...
class ScenePainter with EventDispatcherMixin
means it behaves like a ChangeNotifier
, that's why when the controller asks it to create the actual CustomPainter
to be consumed in the Widget, it passes a reference to itself in the constructor.
CustomPainter buildPainter() => _GraphicsPainter(this);
and
_GraphicsPainter(this.scene) : super(repaint: scene);
So, here's where the Ticker
hits as the executioner of update/render.
SceneController:_onTick
calls tick(delta)
on both scenes (ScenePainter
).
That's where $update()
and $render()
are called (based on SceneConfig flags ).
$render()
calls requestRender()
, which notify()
(as a ChangeNotifier does) the CustomPaint to repaint internally.
That's pretty much the flow. I hope it makes some sense.
So, as you see there're a few variables around that comes from SceneConfig
... you can change them internally in your graphx scene through the stage.
For example, to disable the render/enterFrame for 1 scene:
stage?.scene.autoUpdateAndRender = false;
That's about it.
Thanks for the explanation @roipeker, i was actually kinda roughly thinking it was working like that. In the end, if only the front scene updates, I would expect the SceneController
to only instantiate a new foreground custom painter from the front scene GSprite
and pass it to the CustomPaint
widget, leaving the main / back custom painter intact.
stage?.scene.autoUpdateAndRender = false;
Thanks for that trick, it ultimately address what I was trying to do
On that note, what is the proper way to request an update / paint for a scene with no tick / auto updater ?
Right now the only way I made it to work is to use graphScene.stage!.$tick(double.nan)
but it seems to be a hack..
I tried the more obvious graphScene.requiresRedraw()
but it does nothing or I am not understanding how it is supposed to work...
Well, Isnt so straightforward cause painting and internal update (enter frame) processing happens on different functions but under the same “ticker”.
What u did looks hacky but seems the only way to go currently, as the elapsed frame time is part of the TickerManager and that double reprents the different between this update and previous one (classic 16ms or 60fps) to calculate framerate, or use it for some physics/game simulation.
GMovieClip might use that delta for the internal framerate of a Gtexture list (like a gif rendering) … and mayhe the ParticlesSystem component might also use it, but thats all. You might pass a delta 16 (or mayhe is .0016) to hardcode a fake “60fps” … even if u run that ticker manually or calculate urself the time difference when u call the function.
i hope i didn't over explain the idea. Cant check the code currently to give u a more accurate response
Btw, just to be clear… graphx was built as a prototype tool, for fun... To make an API more familiar to Flash, or some js rendering engine like Pixie.
It uses a VERY naive approach to do what it does. After all is like a glorified CustomPainter with tons of classes that paints over the same Canvas every frame).
My focus was to have fun while coming up with something to experiment ideas. I doubt i would approach a major refactor now, but today i would definitely face it differently. Much of the API was the solution i came up at the time… so Im sure there is much room for improvement.
Hey no worry at all, yes it's not straightforward, what I wanted to convey was that I had a good mental model of the role the SceneController` was playing not necessarily about its internals or the minutia of the framerates and the like. I appreciate your swift replies, thanks again for that.
I also understand the inception of this project and do value what it brings already on top of custom painters even if there are rough edges and the documentation is outdated.