feat!: Adding RenderContext to the Component.renderTree
Description
The Component.renderTree() method now takes the RenderContext argument, which internally contains the Canvas. This context is intended to gather information about the transforms that are currently applied to the canvas (since the canvas itself doesn't expose that information).
In addition, the RenderContext can be overridden to apply certain effects on each canvas transformation.
Checklist
- [x] The title of my PR starts with a Conventional Commit prefix (
fix:,feat:,docs:etc). - [x] I have read the Contributor Guide and followed the process outlined for submitting PRs.
- [x] I have updated/added tests for ALL new/updated/fixed functionality.
- [x] I have updated/added relevant documentation in
docsand added dartdoc comments with///. - [-] I have updated/added relevant examples in
examples.
Breaking Change
- [x] Yes, this is a breaking change.
- [-] No, this is not a breaking change.
Migration instructions
This PR changes the signature of the Component.renderTree() method. Only users who override renderTree() will be affected. If you are, then update the signature and use context.canvas instead of the canvas.
Related Issues
Yep, that's the idea.
I'm also interested in keeping track of the cull rect, in order to have more efficient rendering.
This will create massive amounts of objects.
For this, I can create a list of pre-built objects inside RenderContext, and just fill them in during the render. This would be a bit like using static Vector2 objects during calculations -- a bit uglier, but hopefully better from the efficiency standpoint.
We can't access this information properly in update.
Here I am slowly gravitating towards the idea of merging the update and render steps. Or, more precisely, updateTree and renderTree - the "normal" update and render would be kept separate for the sake of everyone's sanity.
So, assuming that nobody really overrides updateTree, this would not be a big change from the API standpoint. Of course, the sequence of operations now changes. Previously it was: update everything in the tree, then render everything in the tree. Now it would be more like: update root, then render root, then do the same for every child. I don't think this would produce any observable differences in the behavior though, WDYT?
One other potential benefit that this could bring is that it would guarantee that update cycles will happen exactly as often as render cycles. Under the current approach we cannot give such a guarantee.
So, assuming that nobody really overrides
updateTree, this would not be a big change from the API standpoint. Of course, the sequence of operations now changes. Previously it was: update everything in the tree, then render everything in the tree. Now it would be more like: update root, then render root, then do the same for every child. I don't think this would produce any observable differences in the behavior though, WDYT?
One thing that we'll have to support sooner or later is supporting global z-index for components, I'm wondering if the proposed behavior won't make it harder to build that? Because I guess that even if you have a child rendering before its parent, you'd still want the parent to run its update before the child's update.
One thing that we'll have to support sooner or later is supporting global z-index for components, I'm wondering if the proposed behavior won't make it harder to build that? Because I guess that even if you have a child rendering before its parent, you'd still want the parent to run its update before the child's update.
I don't see how this would be a problem. Fundamentally, update and render are independent operations (with the only restriction that for a component A, A.update should happen before `A.render). Updates between different components may depend on each other, but renders of each component do not depend on updates or renders of other components, nor updates depend on any of the renders. Thus, if you have a sequence of operations like
A.update()
B.update()
C.update()
A.render()
B.render()
C.render()
then it should be possible to reorder them as
A.update()
A.render()
B.update()
B.render()
C.update()
C.render()
without affecting the end result.
What's the status of this PR? This is very useful 👀
I'll close this since it has been open for so long, but we should open an issue where we can discuss this further.