Alchemy plasma experiment

Posted by Dennis on Apr 1, 2009 in Uncategorized5 comments

Note: this can be done quicker with pure ActionScript by using paletteMap(). This example is merely an Alchemy example.

Watch the example here.

Here’s an example of how this can be used on a 3D object.

Here’s the C code:


#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "AS3.h"

int* palette;
int* plasma;
int* newPlasma;
int width;
int height;

AS3_Val generatePlasma(void* self, AS3_Val args)
{
	int x, y, r, g, b, index;

	AS3_ArrayValue(args, "IntType, IntType", &width, &height); 

	palette = malloc(256 * sizeof(int));
	plasma = malloc(width * height * sizeof(int));
	newPlasma = malloc(width * height * sizeof(int));

	for(x=0; x<256; x++)
	{
		r = (int)128.0 + 128 * sin(3.1415 * x / 16.0);
        g = (int)128.0 + 128 * sin(3.1415 * x / 128.0);
        b = 0;
        palette[ x ] = 0xff << 24 | r << 16 | g << 8 | b;
	}

	for(x=0; x<width; x++)
	{
		for(y=0; y<height; y++)
		{
			int color = (
				128.0 + ( 128.0 * sin( x / 16.0 ) ) +
				128.0 + ( 128.0 * sin( y / 8.0 ) ) +
				128.0 + ( 128.0 * sin( ( x + y ) / 16.0 ) ) +
				128.0 + ( 128.0 * sin( sqrt( x * x + y * y ) / 8.0 ) )
			) / 4;
			plasma[index++] = 0xff << 24 | color;
		}
	}

	return AS3_Ptr( plasma );
}

AS3_Val shiftPlasma(void* self, AS3_Val args)
{
	int shift, x, y, index, paletteIndex;
	AS3_ArrayValue(args, "IntType", &shift);

	for(x=0; x<width; x++)
	{
		for(y=0; y<height; y++)
		{
			paletteIndex = (unsigned int)(plasma[index] + shift) % 256;
			newPlasma[index] = palette[paletteIndex];
			index++;
		}
	}			

	return AS3_Ptr(newPlasma);
}

int main()
{
	AS3_Val generatePlasmaMethod = AS3_Function( NULL, generatePlasma );
	AS3_Val shiftPlasmaMethod = AS3_Function( NULL, shiftPlasma );
	AS3_Val result = AS3_Object(
		"generatePlasma: AS3ValType,shiftPlasma: AS3ValType",
		generatePlasmaMethod, shiftPlasmaMethod
	);
	AS3_Release( generatePlasmaMethod );
	AS3_Release( shiftPlasmaMethod );
	AS3_LibInit( result );

	return 0;
}

Here’s the ActionScript code:


package {
	import cmodule.plasma.CLibInit;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;

	[SWF(width="600", height="600", backgroundColor="#000000", frameRate="30")]

	/**
	 * Adobe Alchemy performance test.
	 * Inspired by:
	 * - http://student.kuleuven.be/~m0216922/CG/plasma.html
	 * - http://www.unitzeroone.com/blog/2009/03/18/flash-10-massive-amounts-of-3d-particles-with-alchemy-source-included/
	 *
	 * @author Dennis.Ippel / http://www.rozengain.com
	 *
	 */
	public class PlasmaTest extends Sprite
	{
		/**
		 * The bitmapdata which will be used to draw
		 * the plasma on
		 */
		protected var bmd 				: BitmapData;
		/**
		 * The ByteArray that holds Alchemy's memory.
		 * We will use this to access the generated
		 * palette and plasma data
		 */
		protected var alchemyMemory 	: ByteArray;
		/**
		 * The Alchemy object
		 */
		protected var plasmaLib			: Object;

		/**
		 * Constructor
		 *
		 */
		public function PlasmaTest()
		{
			addEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );
		}

		/**
		 * Initialisation
		 *
		 * @param event
		 *
		 */
		protected function addedToStageHandler( event : Event ) : void
		{
			removeEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );

			bmd = new BitmapData( stage.stageWidth, stage.stageHeight );
			var bitmap : Bitmap = new Bitmap( bmd );
			addChild( bitmap );

			generatePlasma();

			// -- start rendering
			addEventListener( Event.ENTER_FRAME, enterFrameHandler );
		}

		/**
		 * Generates the plasma pattern and the palette
		 *
		 */
		protected function generatePlasma() : void
		{
			var loader:CLibInit = new CLibInit();
			plasmaLib = loader.init();

			// -- get Alchemy's memory ByteArray
			var ns : Namespace = new Namespace( "cmodule.plasma");
			alchemyMemory = (ns::gstate).ds;

			// -- generate the palette & plasma pattern
			//    and get the memory position (Alchemy)
			var plasmaPointer : int = plasmaLib.generatePlasma(stage.stageWidth, stage.stageHeight);
			alchemyMemory.position = plasmaPointer;
		}

		/**
		 * Render the plasma and shift the palette
		 *
		 * @param event
		 *
		 */
		protected function enterFrameHandler( event : Event = null ) : void
		{
			var shift : int = getTimer() / 10;

			bmd.lock();

			// -- Alchemy palette shifting
			alchemyMemory.position = plasmaLib.shiftPlasma(shift);
			// -- write the ByteArray straight to the bitmap data
			bmd.setPixels( bmd.rect, alchemyMemory );

			bmd.unlock();
		}
	}
}

Download all the files here.






5 comments

» Comments RSS Feed
  1. Hey,

    Just letting you know, I have ported this example to c# where my jsc compiler will allow to recompile it to actionscript and ansi c.

    http://zproxy.wordpress.com/2009/04/06/c-to-actionscript-and-alchemy/

  2. [...] by old school MS DOS demos and this Flash Alchemy experiment.. Found out that someone already ported some code from the Alchemy experiment to C#. So after some [...]

  3. [...] by old school MS DOS demos and this Flash Alchemy experiment. Found out that someone already ported some code from the Alchemy experiment to C#. So after some [...]

  4. [...] Alchemy plasma experiment (这个例子入门不错) [...]

  5. It’s taken me ages to get Alchemy set up correctly, but is now compiling the swc correctly. I still can’t get the thing to run though. Am instantiating PlasmaTest in mxml, but nothing is visible onscreen. Any ideas?

Leave a comment