Using an Alchemy generated texture on a 3D object
Posted by Dennis on Apr 2, 2009 in 3D, ActionScript, Flash • 6 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.




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!
awsome! nice use of alchemy.
thx for sharing =)
Love the way you share code. Really cool of you.
How is the performance compared to drawTriangles?
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!
[...] on Flash, Alchemy Memory and compilers Alchemy plasma experiment (这个例子入门不错) Using an Alchemy generated texture on a 3D object [...]