fredsa / forplay

Automatically exported from code.google.com/p/forplay
Apache License 2.0
12 stars 4 forks source link

Make ImageLayer behave as expected with CanvasImages #7

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Building an ImageLayer around a CanvasImage doesn't quite do what you'd expect 
-- it always comes up blank in HTML/DOM mode, and updates to the CanvasImage 
aren't reflected in the ImageLayer correctly on all platforms. The correct 
behavior should be that the ImageLayer represents a live rendering of any 
changes made to the CanvasImage.

Original issue reported on code.google.com by jgw@google.com on 13 May 2011 at 2:32

GoogleCodeExporter commented 9 years ago
Fixing this will also make it possible to get rid of CanvasLayer (except 
perhaps as a convenience), because there would be no difference between it and 
an ImageLayer wrapped around a CanvasImage.

Original comment by jgw@google.com on 13 May 2011 at 2:32

GoogleCodeExporter commented 9 years ago
Is there a workaround for this?

Original comment by matt...@mastracci.com on 11 Jun 2011 at 1:54

GoogleCodeExporter commented 9 years ago
Here's a quick workaround to make CanvasImages work somewhat in ImageLayers in 
HTML mode. I suspect that this won't reflect modifications to the canvas in 
ImageLayers after they've been painted once, but it's good enough for simple 
tasks like mirroring a sprite:

Index: src/forplay/html/HtmlImage.java
===================================================================
--- src/forplay/html/HtmlImage.java (revision 4)
+++ src/forplay/html/HtmlImage.java (working copy)
@@ -41,9 +41,11 @@

   // only used in the WebGL renderer.
   private WebGLTexture tex, pow2tex;
+  private boolean canvas;

   HtmlImage(CanvasElement img) {
     this.img = img.cast();
+    canvas = true;
   }

   HtmlImage(ImageElement img) {
@@ -87,7 +89,7 @@

   @Override
   public boolean isReady() {
-    return isComplete(this.img);
+    return canvas || isComplete(this.img);
   }

   /*

Original comment by matt...@mastracci.com on 11 Jun 2011 at 4:09

GoogleCodeExporter commented 9 years ago
@Matt: The really tricky part is in handling dom/canvas mode. This is one of 
those many Great Oversights in browser API design:
- you can draw to a canvas
- you can draw canvases to other canvases
- you can stick a canvas in the dom
- but you can't easily use a canvas in *multiple places* in the dom (!)

If we look at the three main browsers, at least two of them have (incompatible, 
non-standard) solutions to this problem:
- WebKit has background:-webkit-canvas 
(http://www.webkit.org/blog/176/css-canvas-drawing/).
- Firefox4 has background:-moz-element 
(https://developer.mozilla.org/en/CSS/-moz-element).
- IE9 has jack.

The only solution I can come up with on IE9 is to use toDataURL() and shove the 
resulting base64-encoded ball of crap into a style, which is shared by all 
ImageLayer instances (putting the data url into each ImageLayer's <img> element 
as its 'src' is *extremely* expensive, because you end up duplicating the image 
all over the place via its url).

But there's a subtle semantic difference between the FF/WebKit solutions and 
the IE9 data url hack -- the former are immediate (i.e., the ImageLayers are 
updated as soon as you paint to the canvas), whereas the latter requires a 
manual step (copying the data url into the style) before changes are visible.

Oddly enough, though, in GL mode we actually *want* there to be a manual step, 
so we can tell the developer that it will be a relatively expensive operation. 
This is because it boils down to a glTexImage2D() call, which obviously 
requires a texture copy (anecdotally, it seems to be even more expensive than I 
would have thought in Chrome -- it may be copying across processes at the 
moment).

So... Long-story-short, I think we need to implement this in such a way that 
the behavior is the same across browsers. The easiest way to do this would be 
to implement the IE9 CSS hack everywhere in dom/canvas mode, implement the 
obvious thing in GL, and add an explicit method on either Canvas or CanvasImage 
that's required to flush changes.

Then I'd like to explicitly deprecate (and soon remove) CanvasLayer, in favor 
of CanvasImage + ImageLayer. This will be both simpler (one less layer type), 
and less surprising, because it won't have any performance surprises (frequent 
paints to a CanvasLayer right now can be a lot more expensive than you'd think).

Original comment by jgw@google.com on 14 Jun 2011 at 1:51