Keeping a canvas ImageBuffer updated

This question comes from my necessity to write a class that unifies Cairo and Canvas, much like what OpenFL already does, as I understand. So perhaps the best solution to this is for Lime itself to have a wrapper for Cairo that uses Canvas for HTML5 targets.

So I created a Canvas:

var canvas:CanvasElement = Browser.document.createCanvasElement();
canvas.width = 600;
canvas.height = 600;
var context:CanvasRenderingContext2D = canvas.getContext2d();

Then I create an Image from the Canvas:

var image:Image = Image.fromCanvas(canvas);

This works great the first time I access the Image's data. But after I update the Canvas, the Image remains unchanged.

I’ve tried a few ways to force the Image to update, but the only thing that worked (while maintaining transparency) was creating a new Image every time, which is wasteful.

Is there a recommended way to update an existing Image based on a Canvas?

Update after rethinking my approach:

In the end, it made more sense for me to just maintain the Canvas myself, as I’m not planning to do anything further with the Image:

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height,
              0, gl.RGBA, gl.UNSIGNED_BYTE, canvas);

The issue I was having with transparency involved Lime not re-premultiplying alpha when the Canvas was updated. That was just a matter of using:

gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);

So I’m all set for now!
Though I still think my first comment at the top of my last post may still be an even better way forward in the future?

I actually had thought about the idea of adding a “Context2D” API for OpenFL that would combine both Cairo and Canvas. I’d be interested to hear if that would be desirable

If you went the Lime approach again I think you increment the image.version value and OpenFL will update the texture

I think this could be really handy!
How does this compare to how OpenFL already structures the drawing API?

Hmm, that doesn’t seem to update it for me either. It turns black after the first frame. Sorry I don’t have a great minimum replication example!

In my case, I’m still okay with just drawing to a GL texture. I do miss out on using Image's helpers, but there are workarounds! I’m guessing it’s a relatively rare situation for a Lime user to be in haha

I’m riffing on this idea a bit now and hope to see something come about :slight_smile:

Just as WebGL is effectively a JavaScript wrapper around OpenGL ES, HTML5 Canvas is basically a JavaScript wrapper around Cairo, which means I could implement something similar to canvas but let it run in Cairo under the hood and then we could target one 2D API only

The basic idea I was thinking was:

  • Context2D exposes the 2D software context (cairo, canvas)
  • Context3D exposes the 3D hardware context (opengl, flash stage3D)
  • Stage renders using either context (internally)
  • stage.context3D or stage.context2D is exposed for the context it is using

Yes! I was surprised how nearly identical Canvas and Cairo were when I made a very simple version of what you’re saying.

I like the organization of your idea! :smiley:

So right now, for OpenFL, rendering implements Cairo and Canvas by creating a DrawCommandBuffer filled with abstracted commands, and the Cairo and Canvas renderers read them individually.

I would imagine this way you currently do it would already be optimal for OpenFL. Making a Canvas implementation that renders to Cairo does not seem helpful for OpenFL’s use case specifically.

But this proposal seems like a really nice separate helper class for people (like me) who aren’t using DrawCommandBuffer but want a unified API!

And I guess Context2D would also have to implement Flash’s drawing API to be analogous to Context3D?

Oh yeah – true – it would be ideal to implement it over Flash’s drawing API as well though (I assume?) we could implement the same stuff over Flash

…or we could argue that Flash has no “context2D” if we’re too lazy to implement :slight_smile: