Using an Alchemy generated texture on a 3D object

Posted by Dennis on Apr 2, 2009 in 3D, ActionScript, Flash6 comments

Here’s how a texture that is generated by Alchemy can be used by a 3D engine like Sandy.

Watch the example here.

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 / 32.0);
        g = (int)128.0 + 128 * sin(3.1415 * x / 16.0);
        b = (int)128.0 + 128 * sin(3.1415 * x / 64.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;
}

The ActionScript code:


package {
	import cmodule.plasma.CLibInit;

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

	import sandy.core.Scene3D;
	import sandy.core.scenegraph.Camera3D;
	import sandy.core.scenegraph.Group;
	import sandy.materials.Appearance;
	import sandy.materials.BitmapMaterial;
	import sandy.primitive.Box;

	[SWF(width="900", 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 PlasmaTest3D 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;
		protected var scene 			: Scene3D;
		protected var box1				: Box;
		protected var box2				: Box;
		protected var plasmaSize		: int;

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

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

			plasmaSize = 400;

			bmd = new BitmapData( plasmaSize, plasmaSize );

			generatePlasma();

			create3DScene();

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

		protected function create3DScene() : void
		{
			var camera : Camera3D = new Camera3D( stage.stageWidth, stage.stageHeight );
 			camera.x = 0;
			camera.y = 0;
			camera.z = 150;
			camera.lookAt( 0, 0, 0 );

			scene = new Scene3D( "scene", this, camera, new Group( "rootGroup" ) );
			var bmm : BitmapMaterial = new BitmapMaterial( bmd );
			bmm.smooth = true;
			var appearance : Appearance = new Appearance(
				bmm
			);

			box1 = new Box( "box1", 50, 50, 50, "tri", 2 );
			box1.x = -45;
			box1.appearance = appearance;

			box2 = new Box( "box2", 50, 50, 50, "tri", 2 );
			box2.x = 45;
			box2.appearance = appearance;

			scene.root.addChild( box1 );
			scene.root.addChild( box2 );
		}

		/**
		 * 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(plasmaSize, plasmaSize);
			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();

			box1.rotateZ++;
			box1.rotateY++;
			box2.rotateZ--;
			box2.rotateY--;

			scene.render();
		}
	}
}

Download all the files here.



Tags: , , ,


6 comments

» Comments RSS Feed
  1. Very in depth post you have here. I will have too look at this code again, I have some ideas for how I could use this in my own works.
    Many thanks for that!

  2. awsome! nice use of alchemy.
    thx for sharing =)

  3. Love the way you share code. Really cool of you.

  4. How is the performance compared to drawTriangles?

  5. WOW! I was really excited about alchemy, but I didn’t know it was ready for use in the public. This makes me so excited.. so much potential mixing c/c++ and flash. I’m working on some 3d games in flex, and this has inspired me. Thanks!

  6. [...] on Flash, Alchemy Memory and compilers Alchemy plasma experiment (这个例子入门不错) Using an Alchemy generated texture on a 3D object [...]

Leave a comment