<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tweenpix &#187; bitmapdata</title>
	<atom:link href="http://blog.tweenpix.net/tag/bitmapdata/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tweenpix.net</link>
	<description>Behind the mask</description>
	<lastBuildDate>Wed, 02 Mar 2011 22:54:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>old school fire effect</title>
		<link>http://blog.tweenpix.net/2009/01/04/old-school-fire-effect/</link>
		<comments>http://blog.tweenpix.net/2009/01/04/old-school-fire-effect/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 17:26:39 +0000</pubDate>
		<dc:creator>Francis Bourre</dc:creator>
				<category><![CDATA[tech]]></category>
		<category><![CDATA[bitmapdata]]></category>
		<category><![CDATA[experiment]]></category>
		<category><![CDATA[fire]]></category>

		<guid isPermaLink="false">http://blog.tweenpix.net/?p=857</guid>
		<description><![CDATA[After my last plasma experiments, I feel motivated to play again with pixels and old school demoscene effects. I continued to explore the same great C++ CG resource So, here&#8217;s another one effect that I&#8217;m glad to share. This is the old shool fire effect. No tricks deployed this time to optimize Flash rendering. That&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>After my last <a href="http://blog.tweenpix.net/2008/12/16/smooth-plasma-experiment/">plasma experiments</a>, I feel motivated to play again with pixels and old school demoscene effects. I continued to explore the same great <a href="http://student.kuleuven.be/~m0216922/CG/fire.html">C++ CG resource</a><br />
So, here&#8217;s another one effect that I&#8217;m glad to share. This is the old shool fire effect.</p>
<p>No tricks deployed this time to optimize Flash rendering. That&#8217;s a standard implementation.</p>
<p>[kml_flashembed movie="http://www.tweenpix.net/files/fire.swf" width="450" height="175"/]<br />
</br></p>
<p>Here&#8217;s the source code. Enjoy !</p>
<pre lang="actionscript3">
package
{
	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.filters.BlurFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	[SWF( width="450", height="175", frameRate="25" , backgroundColor="0x000000")]
	public class Fire
		extends Sprite
	{
		protected const w : int = 450;
		protected const h : int = 175;

		protected var bd : BitmapData;
		protected var p : Point;
		protected var rect : Rectangle;
		protected var blur : BlurFilter;

		protected var palette : Vector.<int>;
		protected var fire : Array;

		public function Fire()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.LOW;

			p = new Point(0, 0);
			rect = new Rectangle( 0, 0, w, h );
			blur = new BlurFilter( 4, 4, 1 );
			bd = new BitmapData( w, h, false, 0xFFFFFF );
			addChild( new Bitmap( bd ) );

			var x : int, y : int;
			palette = new Vector.<int>( 256, false );
			fire = [];
			for ( x = 0; x < w; x++ ) fire[x] = new Vector.<int>( h, false );
		    for ( x = 0; x < w; x++ )
		    	for ( y = 0; y < h; y++ )
					fire[x][y] = 256;
			for ( x = 0; x < 256; x++ )
				palette[x++] = HSLtoRGB( x/(3 * 256), 1, Math.min( 256, x * 2 )/256 );

			addEventListener( Event.ENTER_FRAME, enterFrame );
		}

		protected function enterFrame( e : Event ) : void
		{
			bd.lock();
			var x : int, y : int;
		    for ( x = 0; x < w; x++ ) fire[x][h - 1] = Math.random()*32768 % 256;
		    for ( y = 0; y < h - 1; y++ )
    			for ( x = 0; x < w; x++ )
			      fire[x][y] = ((fire[(x - 1 + w) % w][(y + 1) % h]
					+ fire[(x) % w][(y + 1) % h]
			        + fire[(x + 1) % w][(y + 1) % h]
			        + fire[(x) % w][(y + 2) % h]) * 32) / 129;
		    for ( x = 0; x < w; x++ )
			    for ( y = 0; y < h-1; y++ )
			    	bd.setPixel( x, y, palette[fire[x][y]]);
			bd.applyFilter( bd, bd.rect, p, blur );
			bd.unlock();
		}

		public static function HSLtoRGB( h :Number, s : Number , l : Number ) : Number
		{
		    var r : Number = 0, g : Number = 0, b : Number = 0, v1 : Number, v2 : Number;
		    if ( s == 0 )
		    {
		       r = l * 255;
		       g = l * 255;
		       b = l * 255;

		    } else
		    {
		       v2 = ( l < .5 ) ? l * ( 1 + s ) : ( l + s ) - ( s * l );
		       v1 = 2 * l - v2;
		       r = 255 * HueToRGB( v1, v2, h + ( 1 / 3 ) );
		       g = 255 * HueToRGB( v1, v2, h );
		       b = 255 * HueToRGB( v1, v2, h - ( 1 / 3 ) );
		    }
		    return ((r << 16)|(g << 8)|b);
		}

		private static function HueToRGB( v1 : Number, v2 : Number, vH : Number ) : Number
	    {
		    if ( vH < 0 ) vH += 1;
		    if ( vH > 1 ) vH -= 1;
		    if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH );
		    if ( ( 2 * vH ) < 1 ) return ( v2 );
		    if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 );
	    	return ( v1 );
		}
	}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.tweenpix.net/2009/01/04/old-school-fire-effect/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>smooth plasma experiment</title>
		<link>http://blog.tweenpix.net/2008/12/16/smooth-plasma-experiment/</link>
		<comments>http://blog.tweenpix.net/2008/12/16/smooth-plasma-experiment/#comments</comments>
		<pubDate>Tue, 16 Dec 2008 15:05:12 +0000</pubDate>
		<dc:creator>Francis Bourre</dc:creator>
				<category><![CDATA[tech]]></category>
		<category><![CDATA[bitmapdata]]></category>
		<category><![CDATA[double-buffering]]></category>
		<category><![CDATA[experiment]]></category>
		<category><![CDATA[plasma]]></category>

		<guid isPermaLink="false">http://blog.tweenpix.net/?p=259</guid>
		<description><![CDATA[While playing with Alchemy, I focused a lot on C and C++ CG resources (like this great one). Like many coders, I&#8217;ve always been fascinated by old school demoscene effects. ^^ Inspiration finally came, and I had good time producing some little experiments to play with. Here&#8217;s one of them that I&#8217;m glad to share [...]]]></description>
			<content:encoded><![CDATA[<p>While playing with <a href="http://blog.tweenpix.net/2008/12/04/full-double-buffering-alchemist/">Alchemy</a>, I focused a lot on C and C++ CG resources (like this great <a href="http://student.kuleuven.be/~m0216922/CG">one</a>).<br />
Like many coders, I&#8217;ve always been fascinated by old school demoscene effects. ^^</p>
<p>Inspiration finally came, and I had good time producing some little experiments to play with.<br />
Here&#8217;s one of them that I&#8217;m glad to share with you.<br />
That&#8217;s two animated plasmas mixed together using same color palette. Color palette is splitted in 3 collections, one for red channel, another for green. Blue is unused. The last one is for handling pixels transparency.</p>
<p>[kml_flashembed movie="http://www.tweenpix.net/files/plasma.swf" width="400" height="400"/]<br />
</br><br />
Some optimizations tricks deployed to get display smoothness:<br />
- Plasmas are mixed together without blending. I&#8217;m drawing one pixel of each (with boolean checker) while generation.<br />
- I use ByteArray (as video ram like low-level languages do) with BitmapData.setPixels for rendering. I discover it&#8217;s faster to not compute each channel if you don&#8217;t need it.<br />
- As often, few as3 optimizations tips (Vector collections, int indexes, binary shifting for arithmetical operations, while loop without coordinates&#8230;)</p>
<p>Here&#8217;s the source code. Enjoy !</p>
<pre lang="actionscript3">
package
{
	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.filters.BlurFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;

	[SWF( width="400", height="400", frameRate="25" , backgroundColor="0x000000")]
	public class Plasma
		extends Sprite
	{
		protected const w : int = 400;
		protected const h : int = 400;

		protected var bd : BitmapData;
		protected var ba : ByteArray;
		protected var position : uint;
		protected var p : Point;
		protected var rect : Rectangle;
		protected var shifter : int;
		protected var blur : BlurFilter;

		protected const A : Vector.<int> = new Vector.<int>( 256, true );
		protected const R : Vector.<int> = new Vector.<int>( 256, true );
		protected const G : Vector.<int> = new Vector.<int>( 256, true );
		protected var plasma : Vector.<int>;

		public function Plasma()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.LOW;

			ba = new ByteArray();
			p = new Point(0, 0);
			rect = new Rectangle( 0, 0, w, h );
			bd = new BitmapData( w, h, true, 0 );
			blur = new BlurFilter( 4, 4, 1 );
			addChild( new Bitmap( bd ) );

			// generate palette
			var i : int = 256;
			while( --i > - 1 )
    		{
    			A[i] = int(128 + 128 * Math.sin( 3.1415 * i / 32));
        		R[i] = int(128 + 128 * Math.sin( 3.1415 * i / 16));
        		G[i] = int(128 + 128 * Math.sin( 3.1415 * i / 64));
    		}

    		// generate plasma
    		var x : int, y : int, l : int = w*h, b : Boolean = true;
    		plasma = new Vector.<int>( l, false );

			while(  --l > - 1 )
			{
  				x = l % w;
				y = (l - x) / w;
				var color : Number;

				if ( b )
					color = (128+(128*Math.sin(x/128))+128
					+(128*Math.sin(y/128)))/2;
				else
					color = (128+(128*Math.sin(x/16))+128
					+(128*Math.sin(y/8))+128
					+(128*Math.sin((x+y)/16))+128
					+(128*Math.sin(Math.sqrt(x*x+y*y)/8)))/4;

        		plasma[l] = color;
        		b = !b;
    		}

			// init screen
			for( x = 0; x < w; x++ )
			{
				for( y = 0; y < h; y++ )
				{
					var pos : Number = (x+(y*w))*4;
					ba[pos] = 255;
					ba[pos+1] = 0;
					ba[pos+2] = 0;
					ba[pos+3] = 0;
				}
			}

			addEventListener( Event.ENTER_FRAME, enterFrame );
		}

		protected function enterFrame( e : Event ) : void
		{
			bd.lock();
			var t : int = ++shifter, pos : int = w*h, palID : int, ID : int;
			while ( --pos > - 1 )
			{
					palID = int((plasma[pos] + t) % 255);
					// to process ARGB channels, same as pos *= 4;
					ID = int(pos << 2);
					ba[ID]	= A[palID];
					ba[ID+1]= R[palID];
					ba[ID+2]= G[palID];
        	}
			ba.position = 0;
			bd.setPixels( rect, ba );
			bd.applyFilter( bd, bd.rect, p, blur );
			bd.unlock();
		}
	}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.tweenpix.net/2008/12/16/smooth-plasma-experiment/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>full double-buffering alchemist</title>
		<link>http://blog.tweenpix.net/2008/12/04/full-double-buffering-alchemist/</link>
		<comments>http://blog.tweenpix.net/2008/12/04/full-double-buffering-alchemist/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 12:56:54 +0000</pubDate>
		<dc:creator>Francis Bourre</dc:creator>
				<category><![CDATA[tech]]></category>
		<category><![CDATA[alchemy]]></category>
		<category><![CDATA[bitmapdata]]></category>
		<category><![CDATA[double-buffering]]></category>

		<guid isPermaLink="false">http://blog.tweenpix.net/?p=208</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>As you maybe know, <a title="Alchemy" href="http://labs.adobe.com/technologies/alchemy/">Alchemy</a> is out on the labs.</p>
<p>Quoting the official announcement: <em>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).</em></p>
<p>I decided to provide an example of <a href="http://en.wikipedia.org/wiki/Double_buffering">double-buffering</a> beetween C code and ActionScript code for people who need it.</p>
<div class="captionfull"><img src="http://blog.tweenpix.net/wp-content/gallery/general/fma.jpg" alt="Full Metal Alchemist" />
</p>
</div>
<p>There are few traps to avoid.</p>
<p><a title="Alchemy AS3 API" href="http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:AS3_API">Documentation</a> on Adobe labs says to use <strong>GLEByteArrayProvider</strong> to get the ByteArray used as RAM by your C library directly. I tried it, but this class wasn&#8217;t public with my configuration.<br />
If you experience the same, you have to reference it dynamically as shown below (like you did with Dictionary class during AS3 beta 2).</p>
<pre lang="actionscript3">
	var ns : Namespace = new Namespace( "cmodule.MyModule" );
	var ba : ByteArray = (ns::gstate).ds;
</pre>
<p>With this workaround, it works like a charm, except GLEByteArrayProvider.get() returns a byte array with a little endian sealed.</p>
<p>This code gives me an error:</p>
<pre lang="actionscript3">
var ns:Namespace = new Namespace("cmodule.CGraphicFilter");
baMem = (ns::gstate).ds;
baMem.endian = Endian.BIG_ENDIAN;
lib = (new CLibInit()).init();
</pre>
<p><strong>LEByteArray endian set attempted<br />
at LEByteArray/set endian()[56201.achacks.as:50]<br />
at AlchemyTest()</strong></p>
<p>You can use an intermediate byte array with big indian to get data as expected by Flash API (as shown below):</p>
<pre lang="actionscript3">
protected function enterFrame( e : Event ) : void
{
baMem.position = position;
var ba : ByteArray = new ByteArray();
baMem.readBytes( ba, 0, size );
bd.setPixels( rect, ba );
}
</pre>
<p>Finally, I felt more comfortable to hack endianness during ram writing on c side . I&#8217;m writing bytes values in reverse order (bgra instead of argb).</p>
<p>Here&#8217;s C code:</p>
<pre lang="c">
#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;
}
</pre>
<p>Here's Flash code to work with C code to update screen.</p>
<pre lang="actionscript3">
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 );
		}
	}
}
</pre>
<p>I had a conversation with <a href="http://www.quasimondo.com/">Mario</a>, and like him, I felt really disappointed with Alchemy graphical performances (BitmapData).</p>
<p>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.</p>
<p>At this time, the only benefit we see is that you can reuse existing C libraries.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tweenpix.net/2008/12/04/full-double-buffering-alchemist/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

