As you maybe know, Alchemy is out on the labs.
Quoting the official announcement: Alchemy is a research project that allows users to compile C and C++ code that is targeted to run on the open source ActionScript Virtual Machine (AVM2).
I decided to provide an example of double-buffering beetween C code and ActionScript code for people who need it.
There are few traps to avoid.
Documentation on Adobe labs says to use GLEByteArrayProvider to get the ByteArray used as RAM by your C library directly. I tried it, but this class wasn’t public with my configuration.
If you experience the same, you have to reference it dynamically as shown below (like you did with Dictionary class during AS3 beta 2).
var ns : Namespace = new Namespace( "cmodule.MyModule" ); var ba : ByteArray = (ns::gstate).ds;
With this workaround, it works like a charm, except GLEByteArrayProvider.get() returns a byte array with a little endian sealed.
This code gives me an error:
var ns:Namespace = new Namespace("cmodule.CGraphicFilter"); baMem = (ns::gstate).ds; baMem.endian = Endian.BIG_ENDIAN; lib = (new CLibInit()).init();
LEByteArray endian set attempted
at LEByteArray/set endian()[56201.achacks.as:50]
at AlchemyTest()
You can use an intermediate byte array with big indian to get data as expected by Flash API (as shown below):
protected function enterFrame( e : Event ) : void { baMem.position = position; var ba : ByteArray = new ByteArray(); baMem.readBytes( ba, 0, size ); bd.setPixels( rect, ba ); }
Finally, I felt more comfortable to hack endianness during ram writing on c side . I’m writing bytes values in reverse order (bgra instead of argb).
Here’s C code:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include "AS3.h" AS3_Val initVideoData( void* self, AS3_Val args ); AS3_Val update( void* self, AS3_Val args ); int v; unsigned char* rawImageData; AS3_Val init( void* self, AS3_Val args ) { // malloc (width * height * 4 channels) size rawImageData = malloc( 800 * 600 * 4 ); // fill with black memset( rawImageData, 0, sizeof( rawImageData ) ); // return pointer position return AS3_Ptr( rawImageData ); } AS3_Val update( void* self, AS3_Val args ) { int x, y, pos; v++; v%=16; for( x = 0; x < 800; x++ ) { for( y = 0; y < 600; y++ ) { pos = (x+y*800)*4; // stub code on red channel. I use BGRA order to simulate big endianness rawImageData[ pos +2 ] = 128 + 128 * sin( x / v ); } } return 0; } int main() { AS3_Val initMethod = AS3_Function( NULL, init ); AS3_Val updateMethod = AS3_Function( NULL, update ); AS3_Val result = AS3_Object("init: AS3ValType,update: AS3ValType",initMethod,updateMethod); AS3_Release( initMethod ); AS3_Release( updateMethod ); AS3_LibInit( result ); return 0; }
Here’s Flash code to work with C code to update screen.
package { import cmodule.DoubleBuffering.CLibInit; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; import flash.utils.ByteArray; [SWF( width="800", height="600", frameRate="25" , backgroundColor="0x000000")] public class AlchemyDoubleBuffering extends Sprite { protected const w : int = 800; protected const h : int = 600; protected const lib : Object = (new CLibInit()).init(); protected const ba : ByteArray = new ByteArray(); protected var rect : Rectangle; protected var bd : BitmapData; protected var baAlchemyRAM : ByteArray; protected var videoPointer : uint; public function AlchemyDoubleBuffering() { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.LOW; rect = new Rectangle( 0, 0, w, h ); bd = new BitmapData( w, h, false, 0 ); addChild( new Bitmap( bd ) ); // get Alchemy RAM var ns : Namespace = new Namespace( "cmodule.DoubleBuffering" ); baAlchemyRAM = (ns::gstate).ds; // call C code to init RAM and store video position videoPointer = lib.init(); addEventListener( Event.ENTER_FRAME, enterFrame ); } protected function enterFrame( e : Event ) : void { // call C code to update RAM data lib.update(); // update screen with RAM data from stored position baAlchemyRAM.position = videoPointer; bd.setPixels( rect, baAlchemyRAM ); } } }
I had a conversation with Mario, and like him, I felt really disappointed with Alchemy graphical performances (BitmapData).
I tried to play with some plasma algorithms and color palettes, and despite of what has been publicised by Adobe I could not create any demo where Alchemy code runs faster than optimized Actionscript.
At this time, the only benefit we see is that you can reuse existing C libraries.
Share on Twitter
Ha wouai, comme même. ^^
[...] two [...] Billet posté par Francis Bourre Francis Bourre’s Website While playing with Alchemy, I focused a lot on C and C++ CG resources (like this great one). Like many coders, I’ve [...]
[...] l’affichage assez lent (on s’en serait douté, souvenez-vous des conclusions de ce billet), mais l’ensemble est [...]
I used the exact same technique, but used the intermediate Byte Array to change Endian.
Good post and I’m hoping this problem can be solved. I’m sure we’ll be able to render quicker in C.
[...] Il a porté SFFE (un parseur de formules mathématiques pour sa librairie sfXaoS) en reprenant mes expérimentations sur le double-buffering avec Alchemy pour l’affichage. Une fois de plus, les résultats ne sont pas convaincants en termes de [...]
@UnitZeroOne wondering if pvx – alchemy rasterizer should follow http://tinyurl.com/7zdx82 ?
It actually seems to be possible to build a alchemy rasterizer.
500 Squares ( 200×200px) per frame using a C-Buffer bytearray. (I haven’t coded C in years, got a bit of a memory leak, it’s just a rough draft)
http://home.earthlink.net/~mattspencer1/AlchemyCBuffer.swf