openfl / openfl-html5

[deprecated] OpenFL HTML5 backend
Other
0 stars 1 forks source link

Immediately sync data for BitmapData.copyChannel. #45

Closed jgranick closed 10 years ago

jgranick commented 10 years ago

45 Issue by OregonPete,

BitmapData.copyChannel should work like BitmapData.copyPixel, meaning the modified source data should be available in the source object so it can be used externally without having to render first (you know, like in the real Flash ;).

jgranick commented 10 years ago

Comment by jgranick:

It would be great to hear the use case for this.

The idea is that BitmapData remains an image so long as that's all it needs to be. Then it promotes to being a canvas if the pixel data is read or modified, when needed, the image data is generated, but this is not synced back to the image unless it has been changed, and unless it is time to render. In this way, you can make many changes before the next frame without the cost of constantly syncing.

I think (maybe I am wrong?) the problem here is that the source image for copy channel is having image data generated each time this is called. Instead, it should be generated image data (if not available) for the full source image, and this should be pulled.

So let me know what error case this fixed, and lets see if there's a better way to go about it

jgranick commented 10 years ago

Comment by OregonPete:

We're currently porting our AS3/Flash games to Haxe for better portability to multiple targets. In the past, we've only used copyChannel for things like merging a jpg and alpha mask during preload to restore a split png because JPGs have much better compression than PNGs. By splitting a png into two JPGs, we've saved as much as 50% in loading size.

In order to restore the original images, we copyChannel the mask to the source's alpha channel. When we ported to openFL, it took me hours to figure out why the function didn't behave the same as in AS3 and the alpha wasn't restored. It would be great if you guys could document behavioral inconsistencies like that, especially if they seem to be deliberate like in this case. If you don't wish to restore the original behavior, it might be better to create a different "batch" function that explicitly doesn't sync the data until render. Maybe call it copyChannelAsync?

jgranick commented 10 years ago

Comment by jgranick:

Been there -- if you convert the "flat" PNG to a black background, and use a PNG (with, say, 16 colors greyscale) to handle alpha, you can potentially shave 90% of the size down.

Do you have something you could share as a tiny little sample, that I could work against? I have no plans to have a change in the way that it looks/feels. I just have some ideas for how we can properly emulate the same behavior, while getting better performance by syncing to the canvas only later.

jgranick commented 10 years ago

Comment by OregonPete:

I'm afraid I don't have a "tiny little" sample, but I've put something together that shows what we're doing. You can download the package at:

http://www.peterkrausche.com/download/AlphaMergeExample.7z

You should be able to open the project in FlashDevelop and debug it as an html5 target. You'll need to place the index.template.html that I've included in your "openfl-html5/templates/html5/template" folder for it to work (rename it to index.html after making a backup of your original). The compiled app in bin/html5/bin probably won't work out of the box unless your browser can handle loading local files.

We've ported a lot of Daniel Sperl's Starling framwork to haxe and mutilated what we needed to get it working with creatjs / easeljs as the backend rendering system.

The asset folder contains the two spritesheet pieces. I've included the original png so you can see how much we saved in this one case. The spritesheet was created with TexturePacker in the Sparrow/Starling format. Our asset manager (you'll find it in src/common/util/AM.hx) merges the two files in the combineAlphaJpgs() function. As you can see, I've circumvented the sync problem by creating a little utility called copyToAlphaChannel that calls the openfl-html5 BitmapData.__syncImageData function.

While I have you on the line, I wonder if you could help us out. We really need the openfl-html5 flash Stage to be transparent, as it is when working with wmode direct (needed for Starling in Flash). We've spent hours trying to figure out why it keeps rendering black (or the color we select in the application.xml), no matter what we do. A simple context.clearRect should usually solve this, but for some reason it won't. There have been a couple of inquiries by others in the openfl forum about this in the past months but they've gone unanswered. Any suggestions on how to tackle this problem?

Thanks!

jgranick commented 10 years ago

Comment by OregonPete:

Okay, I think I finally figured out the non-transparent Stage problem. Around line 82 of the flash.Stage class, you guys use this:

context = untyped __js ('this.__canvas.getContext ("2d", { alpha: false })');

which, it seems, makes it totally impossible to make the canvas transparent. This is probably a discussion for another thread, but would it be possible to include a "transparent" parameter when instantiating the stage and use something like

context = canvas.getContext2d();

in that case instead of the line further up?

jgranick commented 10 years ago

Comment by jgranick:

If you would like to override a template, create your own directory structure that matches the one from OpenFL, so if you had "templates/html5/template/index.html" in your project directory, add <template path="templates" /> to your project, and it should override the one that's included from OpenFL, assuming that you add this tag after the <haxelib name="openfl" /> tag.

That should help keep things cleaner and nicer :)

I'd be interested to hear the stage alpha should be controlled by code, or whether it should be controlled by how the project is embedded in HTML. I think that most projects will not have alpha on the stage, this ends up providing a nice bump in performance when supported, though I understand that when you need it, you need it!

In order to have a transparent fill, instead of a solid fill, were you modifying openfl-html5 to do it, or does the stage.color property accept an alpha value?

jgranick commented 10 years ago

Comment by jgranick:

Thanks again for your help with the sample!

I've made improvements to make sure that image data is synced if necessary, made improvements to copy channel and getPixels while I was at it.

I notice that in your project, you reference the image and canvas elements directly... I believe this is why you had the problem (since normally, this is hidden behind the Bitmap/BitmapData implementation)

I moved the call to __syncImageData into your "getImageElement" util instead of after the copy channel, I suppose either works, but the idea is that it should be called before looking for an image or canvas element, because that commits any pending pixel edits before a render.

jgranick commented 10 years ago

Comment by OregonPete:

I'm afraid the stage.color with alpha didn't work (was one of the first things I tried). In normal Flash, the stage transparency is handled through the wmode direct parameter in the embed statement of the html, or in the app.xml if you're in AIR. So it would be fine if the stage transparency in openFL emulated that behavior.

Yes, we needed to access the image and canvas elements directly because we're using easelJS under the hood and easel needs them. Sorry, but openFL just isn't fast enough. ;) At the same time, we're trying to emulate Starling as much as possible so we don't have too much work when porting all our games to the haxe html5 target.

jgranick commented 10 years ago

Comment by jgranick:

I've just improved the way that "openfl-html5" is embedded, though this will require an update to your HTML file. Now, "openfl.embed" is an exposed function, that accepts the target element, as well as the width, height and color for the embed. These are filled out automatically in the standard template, but you should be able to set the background color to null if you want it to be transparent

If you have any specific areas where the performance seems lackluster, let me know. We've seen better performance than libraries we've compared it to so far