flame icon indicating copy to clipboard operation
flame copied to clipboard

feat!: Adding RenderContext to the Component.renderTree

Open st-pasha opened this issue 3 years ago • 5 comments

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 docs and 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

st-pasha avatar May 30 '22 18:05 st-pasha

Yep, that's the idea.

I'm also interested in keeping track of the cull rect, in order to have more efficient rendering.

st-pasha avatar May 30 '22 19:05 st-pasha

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.

st-pasha avatar Jun 02 '22 20:06 st-pasha

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.

spydon avatar Jun 13 '22 21:06 spydon

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.

st-pasha avatar Jun 13 '22 22:06 st-pasha

What's the status of this PR? This is very useful 👀

alestiago avatar Aug 04 '22 04:08 alestiago

I'll close this since it has been open for so long, but we should open an issue where we can discuss this further.

spydon avatar Mar 07 '23 21:03 spydon