Wednesday, September 28, 2011

The ChatBot MegaHAL Ported to Flash


Also: Have a Talk with MegaHAL on Kongregate.

When I first created a simple Chatbot, which just searches answers for user inputs from a predefined XML file, someone pointed me to MegaHAL as an example which can be trained from users' inputs.
MegaHAL is an advanced ChatBot, created by Jason Hutchens in 1998 and won the Loebner Prize Contest. MegaHAL is based on 4th-order Markov models to construct the model of language, so it can learn from user's input. Thanks to Adobe Alchemy, porting MegaHAL is almost painless.

[1 HOW TO PLAY]
Click after the prompt ">" to get focus. Then type what you want to say after the prompt and press Enter key twice to sent your message to the Bot. Now you can get your reply. (The interface is command-like)
[Save the brains]: "right click" =>"#Save brain"
[Upload your brains]: "right click" =>"#Upload brain"=>browse for your save brain, it's a zip file=> type command "#brain user" to change the brain

[2 CHANGING PERSONALITIES]
Use MEGAHAL COMMAND “#brain YourBrainName”
{
Available Brains:
#brain aliens (Bishop from Aliens!)
#brain bill (Bill Clinton)
#brain caitsith (Cait Sith from FFVII)
#brain danish (Danish MegaHAL).
#brain dune (Alia from Dune!)
#brain ferris (Mr. Ferris Bueller himself!)
#brain german (German MegaHAL)
#brain manson (MegaMANSON, the Marylin Manson personality) #brain pulp (Marsellus Wallace from Pulp Fiction!)
#brain scream (Randy from Scream!)
#brain startrek (Data from Star Trek)
#brain starwars (Threepio from the Star Wars Trilogy)
}

I also created a forum for Flash MegaHAL, so you can upload and share your trained brains there:
http://flaswf.freeforums.org/flash-megahal-f25.html

Source Code of Flash MegaHAL:
In Game->Right Click->Download Source Code

MegaHAL Official Website:
http://megahal.alioth.debian.org/

To know more about one of the best ChatBots MegaHal:
http://en.wikipedia.org/wiki/MegaHAL

Saturday, September 24, 2011

Paint Online with Chinese Water Color Brush

I once tried to learn Chinese calligraphy and painting when I was in primary school. Unfortunately, I dropped them for lack of gifts.  However, I'm still fond of these Chinese styles of art. So I have always wanted to create something to simulate the Chinese Brush and Chinese Painting in Flash.


This is a project I made for Baidu's APP contest. This toy use automata machine to simulate the dispersion of the ink, which is explained here.
A Chinese version of this toy can be found here: http://app.baidu.com/widget?appid=138371
You can share your art and suggestions at the Forum for this toy:
http://flaswf.freeforums.org/watercolorbrush-f33.html

Monday, September 5, 2011

Full Source Code of the Game - The Feeder Released!


Description: Risk your life to feed those "lovely" hungry monsters. Feed all monsters in the level to go to next level. Be careful and good luck! It is a Wolfenstein3D like first person "shooting" game.
Objective: Feed all monsters in the level to go to next level. Enter key to view time, level, life and score. 
Instructions:
W/up: move forward
S/down: move back
left arrow key: turn left
A: strafe left
right arrow key: turn right
D: strafe right
----------
Space: shoot
M: map
Enter: pause game/view game status
----------

The Feeder is the game I made for Stanford Hackathon 2011 flash game competition. It is a 2.5D "FPS" game using ray casting technology. Now I release the full source code of the game for you.

Source Code: In Game Menu, Right Click->Download Source Code.
http://flaswf.googlecode.com/svn/trunk/Games/TheFeeder/

Special Thanks to:
http://code.dawnofthegeeks.com/2009/05/05/c-lesson-37-wolf5k-making-it-better-part-1/
http://minimalcomps.com/
http://blog.ickydime.com/2011/01/flash-game-competition-stanford-adobe.html

Thursday, August 25, 2011

Simple Ray Tracing Voxel Demo


Just a simple demo using Ray Tracing to render Voxels.
I use a 1D array - voxelData[] to represent voxels/3D points with colors. It's easier for understanding if I use a 3D array, voxelData[x][y][z], where x, y, z is the position of the voxel in 3D space and the value of the array is color for that voxel. Note that voxelData[x][y][z] = voxelData[x<<16|y<<8|z] if the dimension is set to 256 at max.

The rendering idea is simple, since we want to fill the screen using colors, for each pixel in the screen, trace a ray, and march the ray in the voxel space, until the ray hit a voxel, then we get the color and write it to the screen. This is the so-called "first-hit" algorithm.

Ray tracing is slow,  a fast way to render voxel is ray casting, such as the algorithm used in Bengine. But using ray tracing, you can easily add some reflection/shadow effect after calculate normal vectors of the voxels.

Source code: https://flaswf.googlecode.com/svn/trunk/RaytracingVoxel
(similar to the source code of the voxel ray tracing demo in my earlier post)

====================
 Update: November, 27, 2011
====================

Ray Tracing Voxel Demo using 3D DDA/Bresenham's line algorithm


Source code: https://flaswf.googlecode.com/svn/trunk/RaytracingVoxel/3DDDA
More about Bresenham's line algorithm:
http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
http://www.cobrabytes.com/index.php?topic=1150.0
http://www.jonof.id.au/forum/index.php?topic=1338.msg9213;topicseen#msg9213

Friday, August 19, 2011

Use vLib.swc to manage flash project resources and protect swf assets

====================
Update: 2012/12/21
vLib v0.15 released!
https://flaswf.googlecode.com/svn/trunk/vLib/bin/v0.15
What's new:
Fixed several bugs, disable useless traces.
Add new sound API of Flash 11.

myLib.playSound("MP3SoundName");//Play the mp3 sound from mp3 file directly! 
====================

vLib - the virtual library project, is a AS3 swc lib to handle your flash project resources, such as bitmaps, swfs, mp3 sounds, texts, xmls and binary files.
It will ease you from importing assets into your .fla's library, writing lots of Embed stuffs for the Flex project, and save your efforts of using lots of URLLoader and Loader codes.
Only need to write a XML file and markup the name and URL address for all flash resources, you can then access them using simple AS3 api provided by vLib.swc.

Tutorial of using vLib.swc, Step by Step:

Step 1[Prepare the test resources files]:
Create a folder and put all the resources(such as Binary files, mp3 sounds, swfs, text files, xml files, .JPG and .PNG pictures) into it.

Step 2[Write the description xml]:
Write a xml file of the resources' names and URLs.
The XML must begin and end with

There're 6 kinds of resources, each kind has a tag, they're:
 for all text files
 for all picture files
 for all swf files
 for all mp3 files
 for all binary files
All resource files should be written into the corresponding tag of the format
  
The details of the description XML's format are showed in the example.
Example["vLib.xml" from vLib\examples\bin\DataFiles]:




  
  



  
  




  
  















  
  





Note: Due to formatting issues, the above xmls don't display correctly, all tag names should be in upper case in the first character, for details, please see the examples in the svn.


Step 3[Add the vLib.swc to library]:
Add the "vLib.swc" to your flash/flex project, so you can use it in your AS3 code.

Step 4[Initialize the virtual library]:

First declare an instance and provide the the description xml file "vLib.xml" to it.
import Lib.*;
var myLib:Lib = new Lib();
myLib.addEventListener(Event.COMPLETE, Libloaded);
myLib.init0("./DataFiles/Lib.xml");
function Libloaded(event:Event):void
{
//All Resources Loaded!
}

Step 5[Access resources from the virtual library]:
As showed in the code, once all resources are loaded, it will triger the callback function "Libloaded", that's the time you can use them.
function Libloaded(event:Event):void
{
//All Resources Loaded!
test();
}
function test():void
{
myLib.load(new DataFiles_Class());
addChild(myLib.getSwf("enemyfire"));
var test = myLib.getSwf("enemydead");
addChild(test);
test.x = 100;

trace(myLib.getXML("Xmlfile_0"));
trace(myLib.getXML("Xmlfile_1"));
   
trace(myLib.getText("Textfile_0"));
trace(myLib.getText("Textfile_1"));
   
trace(myLib.getBin("Binaryfile_0"));
trace(myLib.getBin("Binaryfile_1").length);
   
addChild(new Bitmap(myLib.getBitmapData("PNGfile")));
}//end of test

Step 6[Export Data files as compressed binary package]:
Export all resources as a single compressed binary file and protect your swf assets.
Add this line:
myLib.save("myLib.vLib"); 
in function "Libloaded".
You will get a binary file named "myLib.vLib" which contains all the resources.

Step 7[Use the compressed data file package]:
myLib.addEventListener(Event.COMPLETE, Libloaded);
myLib.init1("./DataFiles/myLib.vLib");
function Libloaded(event:Event):void
{
//All Resources Loaded!
test();
}
Or
Embed the file "myLib.vLib" as a binary asset:
[Embed(source="../bin/DataFiles/myLib.vLib",mimeType="application/octet-stream")]
private static const DataFiles_Class:Class;
myLib.load(new DataFiles_Class());
test();
You can use the data files directly after calling load().
If you Embed all resources using Embed tag or import them into .fla's library, all resources will be compiled into SWF tags. SWF decompilers can read those tags and extract the resources directly.
But in this step, because all resources are encoded into a single binary file, it's a good way to protect the swf assets.

Step 8[Export Data files as a .as class]:
Export .as Class with Embeds:
myLib.XML2AS("./DataFiles/Lib.xml", "myLibT" /*, "myPackageT"*/);
You will get a .as file named "myLibT.as" as follows:
package 
{
     import flash.display.*;
     import flash.media.*;
     import flash.text.*;
     import flash.utils.*;
//Export from vLib-v0.1 by Bruce Jawn (zhoubu1988@gmail.com)

     public class myLibT
     {
     [Embed(source="DataFiles/texts/Textfile_0.txt", mimeType="application/octet-stream")]
     private static const Textfile_0:Class;
     [Embed(source="DataFiles/texts/Textfile_1.txt", mimeType="application/octet-stream")]
     private static const Textfile_1:Class;
     [Embed(source="DataFiles/xmls/Xmlfile_0.xml", mimeType="application/octet-stream")]
     private static const Xmlfile_0:Class;
     [Embed(source="DataFiles/xmls/Xmlfile_1.xml", mimeType="application/octet-stream")]
     private static const Xmlfile_1:Class;
     [Embed(source="DataFiles/textures/JPGfile.JPG")]
     private static const JPGfile:Class;
     [Embed(source="DataFiles/textures/PNGfile.PNG")]
     private static const PNGfile:Class;
     [Embed(source="DataFiles/swfs/enemydead.swf")]
     private static const enemydead:Class;
     [Embed(source="DataFiles/swfs/enemyfire.swf")]
     private static const enemyfire:Class;
     [Embed(source="DataFiles/sounds/sound1.mp3")]
     private static const S0:Class;
     [Embed(source="DataFiles/sounds/sound2.mp3")]
     private static const S1:Class;
     [Embed(source="DataFiles/sounds/sound3.mp3")]
     private static const S2:Class;
     [Embed(source="DataFiles/bins/Binaryfile_0.bin", mimeType="application/octet-stream")]
     private static const Binaryfile_0:Class;
     [Embed(source="DataFiles/bins/Binaryfile_1.bin", mimeType="application/octet-stream")]
     private static const Binaryfile_1:Class;

        private function getClass(name:String):Class
        {
            var ClassReference:Class = getDefinitionByName("myLibT_"+name) as Class;
            return ClassReference;
        }      

  private function getInstance(name:String):Object
  {
   var ClassReference:Class = getClass(name);
   return new ClassReference();
  }
  public function getBin (name:String) : ByteArray
  {
   return ByteArray(getInstance(name));
  }
  
  public function getBitmapData (name:String) : BitmapData
  {
   return Bitmap(getInstance(name)).bitmapData;
  }

        public function getFont (name:String) : Class
  {
   return getClass(name);
   //return Font(getInstance(name));
   //Font.registerFont(EmbeddedFont); 
  }
  
  public function getSound (name:String) : Sound
  {
   return Sound(getInstance(name));
  }

  public function getSwf (name:String) : Sprite
  {
   return Sprite(getInstance(name));
  }

  public function getText (name:String) : String
  {
   return String(getInstance(name));
  }

  public function getXML (name:String) : XML
  {
   return XML(getInstance(name));
  }
 }//end of class 
}//end of package
Then you can import this class into your AS3 projects and compile everything into the final single SWF.

Links:
vLib.swc API references:
http://code.google.com/p/flaswf/wiki/vLib
vLib.swc v0.1 download:
http://flaswf.googlecode.com/svn/trunk/vLib/bin/
Source code of vLib.swc examples:
https://flaswf.googlecode.com/svn/trunk/vLib/examples

Sunday, July 10, 2011

Porting lib FANN to Flash using Alchemy

Test Environment: OS: Windows XP, Alchemy: Alchemy Toolkit Preview, Flash SDK: 3.2, Flash Player 10, FANN: 2.1.0, Cygwin,

Lib FANN(Fast Artificial Neural Network Library) is a free open source neural network library written in C. In this tutorial I will show you how to use Adobe Alchemy to port FANN to Flash, step by step.

1. Download the FANN library: http://leenissen.dk/fann/wp/download/ (fann-2.1.0beta.zip)

2. Unzip the source code to some folder("F:\alchemy\FANN\fann-2.1.0")

3. Run "Cygwin" and do the config for the source code:

cd /cygdrive/f/alchemy/FANN/fann-2.1.0
./configure
Now you should find the Makefile created in "F:\alchemy\FANN\fann-2.1.0\src"

4. First of all, as a simple test, let's compile the source code of FANN to exe:
cd src
make
ar rc libFANNLib.a doublefann.o fixedfann.o floatfann.o
ranlib libFANNLib.a
Copy the files "xor.data, xor_train.c, xor_test.c" from "examples" folder to "src" folder.

gcc -o xor_train xor_train.c -Iinclude libFANNLib.a
gcc -o xor_test xor_test.c -Iinclude libFANNLib.a
Now you can find the compiled exe "xor_train.exe, xor_test.exe" in the src folder.
Copy "cygwin1.dll"  and click to run "xor_train.exe", it  will created files "xor_fixed.data, xor_fixed.net, xor_float.net". Using the cmd to run "xor_test.exe": Windows Start -> run -> cmd -> cd F:\alchemy\FANN\fann-2.1.0\src
F:
xor_test.exe
And you will see the result.

5. Now let compile the lib using alchemy:
source /cygdrive/f/alchemy/alchemy-setup
alc-on
make

6. A quick test to compile  "xor_test.c" to swfs:
(Since ar rc libFANNLib.a doublefann.o fixedfann.o floatfann.o will throw link errors"$ gcc xor_test.c -Iinclude libFANNLibfx.a libFANNLibfl.a libFANNLibdb.a -swf -O3 -Wall -o xor_test.swf
llvm-ld: error: Cannot link file 'FANNLibfl.l.bc': Linking globals named 'fann_default_error_log': symbol multiply defined!", 

I will do it this way:)
ar rc libFANNLibfx.a fixedfann.o
ranlib libFANNLibfx.a
gcc xor_train.c -Iinclude libFANNLibfx.a -swf -O3 -Wall -o xor_train_fx.swf
gcc xor_test.c -Iinclude libFANNLibfx.a -swf -O3 -Wall -o xor_test_fx.swf

ar rc libFANNLibfl.a floatfann.o
ranlib libFANNLibfl.a
gcc xor_train.c -Iinclude libFANNLibfl.a -swf -O3 -Wall -o xor_train_fl.swf
gcc xor_test.c -Iinclude libFANNLibfl.a -swf -O3 -Wall -o xor_test_fl.swf

ar rc libFANNLibdb.a doublefann.o
ranlib libFANNLibdb.a
gcc xor_train.c -Iinclude libFANNLibdb.a -swf -O3 -Wall -o xor_train_db.swf
gcc xor_test.c -Iinclude libFANNLibdb.a -swf -O3 -Wall -o xor_test_db.swf

Now make sure the compiled swfs and the files "xor.data, xor_fixed.data, xor_fixed.net, xor_float.net" are in the same folder.
run the xor_train_fx.swf, the result:
FANN Error 2: Unable to open configuration file "xor_float.net" for writing.
FANN Error 2: Unable to open configuration file "xor_fixed.net" for writing.
FANN Error 8: Unable to open train data file "xor_fixed.data" for writing.
Creating network.
Training network.
Testing network. 0.000000
XOR test (nan,nan) -> 0.000000, should be nan, difference=nan
XOR test (nan,0.000000) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000,nan) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000,0.000000) -> 0.000000, should be nan, difference=nan
Saving network.
Cleaning up.


run the xor_test_fx.swf, the result:
FANN Error 3: Wrong version of configuration file, aborting read of configuration file "xor_float.net".
Creating network.
Error creating ann --- ABORTING.


run the xor_train_fl.swf, the result:
FANN Error 2: Unable to open configuration file "xor_float.net" for writing.
FANN Error 2: Unable to open configuration file "xor_fixed.net" for writing.
FANN Error 8: Unable to open train data file "xor_fixed.data" for writing.
Creating network.
Training network.
Max epochs     1000. Desired error: 0.0000000000.
Epochs            1. Current error: 0.2960163057. Bit fail 4.
Epochs           10. Current error: 0.0559476353. Bit fail 4.
Epochs           20. Current error: 0.0005034587. Bit fail 3.
Epochs           28. Current error: 0.0000435168. Bit fail 0.
Testing network. 0.000031
XOR test (-1.000000,-1.000000) -> -0.995960, should be -1.000000, difference=0.004040
XOR test (-1.000000,1.000000) -> 0.982892, should be 1.000000, difference=0.017108
XOR test (1.000000,-1.000000) -> 0.988707, should be 1.000000, difference=0.011293
XOR test (1.000000,1.000000) -> -0.992229, should be -1.000000, difference=0.007771
Saving network.
Cleaning up.


run the xor_test_fl.swf, the result:
Creating network.
Layer / Neuron 0123456
L   1 / N    4 ZZZ....
L   1 / N    5 ZZZ....
L   1 / N    6 .......
L   2 / N    7 ...ZZZZ
L   2 / N    8 .......
Input layer                          :   2 neurons, 1 bias
  Hidden layer                       :   3 neurons, 1 bias
Output layer                         :   1 neurons
Total neurons and biases             :   8
Total connections                    :  13
Connection rate                      :   1.000
Network type                         :   FANN_NETTYPE_LAYER
Training algorithm                   :   FANN_TRAIN_RPROP
Training error function              :   FANN_ERRORFUNC_TANH
Training stop function               :   FANN_STOPFUNC_BIT
Bit fail limit                       :   0.000
Learning rate                        :   0.700
Learning momentum                    :   0.000
Quickprop decay                      :  -0.000100
Quickprop mu                         :   1.750
RPROP increase factor                :   1.200
RPROP decrease factor                :   0.500
RPROP delta min                      :   0.000
RPROP delta max                      :  50.000
Cascade output change fraction       :   0.010000
Cascade candidate change fraction    :   0.010000
Cascade output stagnation epochs     :  12
Cascade candidate stagnation epochs  :  12
Cascade max output epochs            : 150
Cascade max candidate epochs         : 150
Cascade weight multiplier            :   0.400
Cascade candidate limit              :1000.000
Cascade activation functions[0]      :   FANN_SIGMOID
Cascade activation functions[1]      :   FANN_SIGMOID_SYMMETRIC
Cascade activation functions[2]      :   FANN_GAUSSIAN
Cascade activation functions[3]      :   FANN_GAUSSIAN_SYMMETRIC
Cascade activation functions[4]      :   FANN_ELLIOT
Cascade activation functions[5]      :   FANN_ELLIOT_SYMMETRIC
Cascade activation functions[6]      :   FANN_SIN_SYMMETRIC
Cascade activation functions[7]      :   FANN_COS_SYMMETRIC
Cascade activation functions[8]      :   FANN_SIN
Cascade activation functions[9]      :   FANN_COS
Cascade activation steepnesses[0]    :   0.250
Cascade activation steepnesses[1]    :   0.500
Cascade activation steepnesses[2]    :   0.750
Cascade activation steepnesses[3]    :   1.000
Cascade candidate groups             :   2
Cascade no. of candidates            :  80
Testing network.
XOR test (-1.000000, -1.000000) -> 0.000000, should be -1.000000, difference=1.000000
XOR test (-1.000000, 1.000000) -> 0.000000, should be 1.000000, difference=1.000000
XOR test (1.000000, -1.000000) -> 0.000000, should be 1.000000, difference=1.000000
XOR test (1.000000, 1.000000) -> 0.000000, should be -1.000000, difference=1.000000
Cleaning up.


run the xor_train_db.swf, the result:
FANN Error 2: Unable to open configuration file "xor_float.net" for writing.
FANN Error 2: Unable to open configuration file "xor_fixed.net" for writing.
FANN Error 8: Unable to open train data file "xor_fixed.data" for writing.
Creating network.
Training network.
Max epochs     1000. Desired error: 0.0000000000.
Epochs            1. Current error: 0.2960163057. Bit fail 4.
Epochs           10. Current error: 0.0559476353. Bit fail 4.
Epochs           20. Current error: 0.0005034586. Bit fail 3.
Epochs           28. Current error: 0.0000435167. Bit fail 0.
Testing network. 0.000031
XOR test (0.000000,-1.875000) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000,-1.875000) -> 67114963815632994304.000000, should be 0.000000, difference=67114963815632994304.000000
XOR test (0.000000,1.875000) -> 0.000146, should be 0.000000, difference=0.000146
XOR test (0.000000,1.875000) -> 0.000000, should be 0.000000, difference=0.000000
Saving network.
Cleaning up.


run the xor_test_db.swf, the result:
Creating network.
Layer / Neuron 0123456
L   1 / N    3 ZZZ....
L   1 / N    4 ZZZ....
L   1 / N    5 ZZZ....
L   1 / N    6 .......
L   2 / N    7 ...ZZZZ
L   2 / N    8 .......
Input layer                          :   2 neurons, 1 bias
  Hidden layer                       :   3 neurons, 1 bias
Output layer                         :   1 neurons
Total neurons and biases             :   8
Total connections                    :  13
Connection rate                      :   1.000
Network type                         :   FANN_NETTYPE_LAYER
Training algorithm                   :   FANN_TRAIN_RPROP
Training error function              :   FANN_ERRORFUNC_TANH
Training stop function               :   FANN_STOPFUNC_BIT
Bit fail limit                       :   0.000
Learning rate                        :   0.700
Learning momentum                    :   0.000
Quickprop decay                      :  -0.000100
Quickprop mu                         :   1.750
RPROP increase factor                :   1.200
RPROP decrease factor                :   0.500
RPROP delta min                      :   0.000
RPROP delta max                      :  50.000
Cascade output change fraction       :   0.010000
Cascade candidate change fraction    :   0.010000
Cascade output stagnation epochs     :  12
Cascade candidate stagnation epochs  :  12
Cascade max output epochs            : 150
Cascade max candidate epochs         : 150
Cascade weight multiplier            :   0.400
Cascade candidate limit              :1000.000
Cascade activation functions[0]      :   FANN_SIGMOID
Cascade activation functions[1]      :   FANN_SIGMOID_SYMMETRIC
Cascade activation functions[2]      :   FANN_GAUSSIAN
Cascade activation functions[3]      :   FANN_GAUSSIAN_SYMMETRIC
Cascade activation functions[4]      :   FANN_ELLIOT
Cascade activation functions[5]      :   FANN_ELLIOT_SYMMETRIC
Cascade activation functions[6]      :   FANN_SIN_SYMMETRIC
Cascade activation functions[7]      :   FANN_COS_SYMMETRIC
Cascade activation functions[8]      :   FANN_SIN
Cascade activation functions[9]      :   FANN_COS
Cascade activation steepnesses[0]    :   0.250
Cascade activation steepnesses[1]    :   0.500
Cascade activation steepnesses[2]    :   0.750
Cascade activation steepnesses[3]    :   1.000
Cascade candidate groups             :   2
Cascade no. of candidates            :  80
Testing network.
XOR test (0.000000, -1.875000) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000, -1.875000) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000, 1.875000) -> 0.000000, should be 0.000000, difference=0.000000
XOR test (0.000000, 1.875000) -> 0.000000, should be 0.000000, difference=0.000000
Cleaning up.


Well, still buggy, but from the prints we see that the lib works. The errors are partially caused by that it can't find the needed files, and some linking errors, too. A better way to make the port useful is to write some wrapper functions using the Alchemy API and compile everything to a swc.

Finally, the Compiled SWFs: https://flaswf.googlecode.com/svn/trunk/flaswfblog/Tutorials/ALCFANN

Friday, May 6, 2011

Simple Fast Bilinear Color Interpolation


Simple, fast implementation of bilinear color interpolation.
The purpose of this snippet is to fill a rectangle with smooth colors interpolated from the four vertices.
This snippet is ripped from my Bengine voxel raycaster, where it is used to scale a single voxel and fill the gap of screen. Color differences are calculated to avoid multiplies, so there are only adds in the for loop. Certainly, the code can be optimized further, I leave it what it is because it's easier for understanding the algorithm.
If you only want to interpolate one single pixel use its neighbours, like the height interpolation in a terrain raycaster, try to find the implementation in this code.
By the way, the simple maths behind the algorithm:
http://en.wikipedia.org/wiki/Bilinear_interpolation

Source Code:
https://flaswf.googlecode.com/svn/trunk/Snippets/SimpleFastBilinearColorInterpolation/

Monday, March 28, 2011

Donating One FDT 4 Pure License Key(expired)

Everyone,

The license key has been sent to the lucky one. I wish I had more keys to share... Thanks for everyone who sents me emails. For the others, I suggest you to try the open source alternative Emacs and FlashDevelop.

Best Wishes!
Bruce
==========

As a participant of Stanford Hackathon 2011 flash game competition, I got one FDT 4 Pure license key donated by Bruno Fonzi of FDT ($129 value).

However, I have no plan to use this software since I work along well with Emacs and FlashDevelop. So I decide to donate this license key for who really needs it.

Just sent me a request email(you can find my email address in my blog profile) if you are interested in FDT. I will randomly sample one from those who send me emails and this one will get the license key for free!

I will stop accepting request emails after 2011 April 15, so be quick if you need it. Good luck!

More about FDT 4: (The Eclipse plugin for Flash/ActionScript/MXML)
http://www.fdt.powerflasher.com/developer-tools/fdt/features/

Update 2011/09/05: Full source code of my game for Stanford Hackathon 2011 flash game competition released!

Molehill with HaXe/HxSL

Last update: Nov. 10, 2011, Upgraded to Flash Player 11.
Finally I decide to use HaXe, because it grants me what I can't reject-HxSL, the haXe Shader Language, which can let you write your shaders more efficiently.
First, follow the instructions to install HaXe for Flash Player 11:
http://haxe.org/doc/advanced/flash3d

Now some HaXe codes to get started(forked from the cube example):

/*
  Forked from http://haxe.org/doc/advanced/flash3d: Example 0 - Cube
  Nov. 10, 2011; BY Bruce Jawn
  [http://bruce-lab.blogspot.com]
*/
import format.agal.Tools;

typedef K = flash.ui.Keyboard;

class Shader extends format.hxsl.Shader {

  static var SRC = {
    var input : {
      /*input vertex format: 
 pos.x:float; pos.y:float; pos.z:float; color.r:float; color.g:float; color.b:float;
 should be consistent with the input vertexbuffer*/
    pos : Float3,/*vertex position as input*/
    col : Float3,/*vertex color as input*/
    };
    var color : Float3;/*temp color variable for output*/
    function vertex( mpos : M44, mproj : M44 ) {
      out = pos.xyzw * mpos * mproj;/*set vertex transformation*/
      color = col;/*set temp color as input color*/
    }
    function fragment() {
      out = color.xyzw;/*set output color*/
    }
  };

}

class Test {

  var stage : flash.display.Stage;
  var s : flash.display.Stage3D;
  var c : flash.display3D.Context3D;
  var shader : Shader;
  var pol : Polygon;
  var t : Float;
  var keys : Array;

  var camera : Camera;
  var vertexbuffer : flash.display3D.VertexBuffer3D;
  var indexbuffer : flash.display3D.IndexBuffer3D;
  function new() {
    t = 0;
    keys = [];
    stage = flash.Lib.current.stage;
    s = stage.stage3Ds[0];
    s.addEventListener( flash.events.Event.CONTEXT3D_CREATE, onReady );
    stage.addEventListener( flash.events.KeyboardEvent.KEY_DOWN, callback(onKey,true) );
    stage.addEventListener( flash.events.KeyboardEvent.KEY_UP, callback(onKey,false) );
    flash.Lib.current.addEventListener(flash.events.Event.ENTER_FRAME, update);
    s.requestContext3D();

    trace("Click the screen to get Focus!");
    trace("Arrow Keys: Rotation"); 
    trace("Z/X: Zoom in/out");   
  }//end of function new

  function onKey( down, e : flash.events.KeyboardEvent ) {
    keys[e.keyCode] = down;
  }//end of function onKey

  function onReady( _ ) {
    c = s.context3D;
    c.enableErrorChecking = true;
    c.configureBackBuffer( stage.stageWidth, stage.stageHeight, 0, true );

    shader = new Shader(c);
    camera = new Camera();
    /*
      Let's draw a plane, which contains 12 triangles:

      0------1------2------3
      |     /|     /|     /|
      | t0 / | t2 / | t4 / |
      |   /  |   /  |   /  |
      |  /   |  /   |  /   |
      | / t1 | / t3 | / t5 |
      |/     |/     |/     |
      4------5------6------7
      |     /|     /|     /|
      | t6 / | t8 / | t10/ |
      |   /  |   /  |   /  |
      |  /   |  /   |  /   |
      | / t7 | / t9 | / t11|
      |/     |/     |/     |
      8------9-----10-----11
      0-11: vertex index
      t0-t11: triangle index
    */
    vertexbuffer = c.createVertexBuffer(12,6);

    var myVertexes:flash.Vector = new flash.Vector(0,false);
    for(j in 0...3)
      for(i in 0...4)
 {
   //set the vertex's position
   myVertexes.push(i);//vertex.x
   myVertexes.push(j);//vertex.y
   myVertexes.push(0.0);//vertex.z
   //set the vertex's color(random)
   myVertexes.push(Math.random());//color.r
   myVertexes.push(Math.random());//color.g
   myVertexes.push(Math.random());//color.b
 }
    vertexbuffer.uploadFromVector(myVertexes,0,12);
    indexbuffer = c.createIndexBuffer(36);

    var myIndexes:flash.Vector = new flash.Vector(0,false);
    for(i in 0...2)
      for(j in 0...3)
 {
   //up:t0
   myIndexes.push(i*4+j);//triangle.a:0
   myIndexes.push(i*4+(j+1));//triangle.b:1
   myIndexes.push((i+1)*4+j);//triangle.c:4
   //down:t1
   myIndexes.push((i+1)*4+j);//triangle.a:4
   myIndexes.push(i*4+(j+1));//triangle.b:1
   myIndexes.push((i+1)*4+(j+1));//triangle.c:5
 }
    indexbuffer.uploadFromVector(myIndexes,0,36);

  }//end of function onReady

  function update(_) {
    if( c == null ) return;

    t += 0.01;

    c.clear(0, 0, 0, 1);
    c.setDepthTest( true, flash.display3D.Context3DCompareMode.LESS_EQUAL );
    c.setCulling(flash.display3D.Context3DTriangleFace.BACK);

    if( keys[K.UP] )
      camera.moveAxis(0,-0.1);
    if( keys[K.DOWN] )
      camera.moveAxis(0,0.1);
    if( keys[K.LEFT] )
      camera.moveAxis(-0.1,0);
    if( keys[K.RIGHT] )
      camera.moveAxis(0.1, 0);
    if( keys[88] )
      camera.zoom /= 1.05;
    if( keys[90] )
      camera.zoom *= 1.05;
    camera.update();

    var project = camera.m.toMatrix();
    var mpos = new flash.geom.Matrix3D();
    mpos.appendRotation(t * 10, flash.geom.Vector3D.Z_AXIS);

    shader.init(
  { mpos : mpos, mproj : project },
  {}
  );
    //draw the triangles  
    shader.bind(vertexbuffer);
    c.drawTriangles(indexbuffer,0,-1);
    c.present();
  }//end of function update

  static function main() {
    haxe.Log.setColor(0xFF0000);
    var inst = new Test();
  }//end of function main

}//end of class

Result:(Flash Player 11 needed!)



Source Code:
https://flaswf.googlecode.com/svn/trunk/flaswfblog/Tutorials/HaXeMolehillTest/

Links:

Announcing HxSL:
http://ncannasse.fr/blog/announcing_hxsl

Using Flash 3D API(lighting/texture examples):
http://haxe.org/doc/advanced/flash3d

HxSL Documentation:
http://haxe.org/manual/hxsl

Flash 11 API Doc:
http://www.flash3v.com/doc/flash11/

Wednesday, March 9, 2011

Quake3 has been ported to Flash!

Update(2012/12/15):
===========================   
Quake3 using FlasCC:
https://github.com/alexmac/alcexamples/tree/master/Quake3
===========================  
 
Update(2011/10/12):
===========================  
Updated source code for Flash Player 11:
https://the-backup-project.googlecode.com/svn/trunk/quake3_flash/
=========================== 

I'm sure this will happen sooner or later, but never expected that it will be so quick.
Quake3 has already been ported to Flash!
This port use alchemy and molehill API and is fully playable.
More details & Play it online:
http://q3fl.impulse12.com/

And I uploaded everything, the compiled swf, source code from the author and quake3 demo data files, in a zip to rayfile,
you can download it here(144MB):
http://www.rayfile.com/en/files/ca1ad8fd-4a58-11e0-8ddb-0015c55db73d/ 
The above link is dead. You can now use Mirror Link provided by [http://code.flaswf.tk/] to download the all-in-one zip package:
http://code.flaswf.tk/2014/05/q3fl-quake-3-flash-port-using-alchemy.html

You may need
Flash Player Incubator Debugger Standalone Version(win32/EXE)
http://code.google.com/p/flaswf/downloads/detail?name=FlashPlayerIncubatorDebugger.exe

Wednesday, February 23, 2011

Pixel Bender, Molehill - Updates and Future Plans for Bengine

The new low-level Flash 3D API Molehill is about to launch, I don't know what it means for Bengine. For Bengine's voxel rendering, I only need a fast way to push all Screen Buffer to the Screen, though, a fast rendering algorithm is more important. Here I want to share some new demos and plans for Bengine.

First,  the game BengineRace. I added submit scores function, now you can submit three kind of scores: Best Racer for the time you spent to complete the game, High Scores for the total score you earn and Best Destructor estimate how many voxels you destroy or more specifically, voxels left in total. You must make through the game to submit scores for the first two and you can submit the score of voxels left in total at any time during the play. Press "X" to enter destroyer mode, energy required for destroying walls is limited. After you fell in holes or died, click "continue" to respawn, then voxels destroyed last time will still be contained in your final score.

Second, I made a 8-bit version of BengineRace and now have given up that idea. The advantage of 8-bit is that the screen looks "better" in a higher resolution because of fewer colors used, maybe it's more like a solid fill engine. Besides, less memory needed for storing the voxel data when you use a palette. The disadvantage is limited color choice and the trouble to design and make the palette. You can find the early build of the game in 8-bit here:
https://flaswf.googlecode.com/svn/trunk/Bengine/demo/8-bit/Bengine-8bit.swf
Some pictures:


Third, my attempt to render Voxelstein3D/Voxlap .vxl maps in Flash!
Bengine can render those maps in a low res at a slow speed.
Voxlap demo map:

demo:
https://flaswf.googlecode.com/svn/trunk/Bengine/demo/vxl/Bengine_voxlap.swf

Cave demo map:
demo:
https://flaswf.googlecode.com/svn/trunk/Bengine/demo/vxl/Bengine_cave.swf

Voxelstein3D map:
demo:
https://flaswf.googlecode.com/svn/trunk/Bengine/demo/vxl/Bengine_wolf.swf

And finally, new plan for Bengine. Bengine will be renamed to PBengine, which initially means PixelBender+Bengine but now represents for PreBengine(Editors)+PlayBengine(Game Core)+Benigne(Voxel Rendering Core)+PostBengine(PixelBender Post-Processing).
It will be a bigger project. I hope to exploit the advantage of Molehill through PixelBender in the future.
But what can PixelBender do with Bengine? Many many things, I have to say. I will mainly use PixelBender for various Post-Processing effects for Bengine. Here is a simple example showing what it will be like:
https://flaswf.googlecode.com/svn/trunk/PBengine/demo/water/PBengineWater_buggy.swf
Make sure try to interact with the water surface with your mouse.


In this demo, I use Bengine for rendering the voxels and PixelBender for the water effect. It is still buggy, the reflection is not correct. And it is terribly slow, only about 10fps in my test. I hope Molehill can make it faster. Optimazions of Post-Processing are needed, but it will be done when Molehill is available.

But how fast can Bengine be? I don't know. I'm still improving it. The rendering algorithm has been written for several times. In the past, after each written, I always thought may be it can not be faster any more. But I proved I'm wrong. Before I wrote this engine, I never expect a voxel engine like this can run at real time in flash, let alone making a playable game. So no one knows how fast it can be and how fast it will be. I will continue optimizing it. Here is the latest demo testing the rendering speed, with a slightly different rendering algorithm from BengineRace. In my laptop, it can render the same map from Bengine Race at/above 30fps.
The demo:
https://flaswf.googlecode.com/svn/trunk/Bengine/demo/speed-test/BengineSpeedTest.swf

PS: Controls for all demos mention above:
==========
W/up: move forward
S/down: move back/recharge speed
A/left: turn left
D/right: turn right
Q: look down
E: look up
----------
Z: max speed(speed*2)
X: max armor(to destroy walls)
C: max power(to fly)
----------
Space: fly
Enter: pause

Sunday, January 23, 2011

[Adobe Alchemy Hacks] Compile *.as Source Files Assembly to SWF and SWC

With alchemy, we can compile AS3 source files assembly, which means we can use some AVM2 inline assembly language in our AS3 source file. Here is the code snippet for using inline asm and accessing memory in AS3:

/*
[Adobe Alchemy Hacks]
AlchemyAD_hack.as
{Simple example for using inline asm and 
accessing memory in AS3}
By Bruce Jawn (January/23/2011)
[http://bruce-lab.blogspot.com]

To compile this source file with Alchemy: 
cd /cygdrive/f/alchemy/
java -Xms16M -Xmx196M -jar F:/alchemy/bin/asc.jar -AS3 -strict -import F:/alchemy/flashlibs/global.abc -import F:/alchemy/flashlibs/playerglobal.abc -config Alchemy::Debugger=false -config Alchemy::NoDebugger=true -config Alchemy::Shell=false -config Alchemy::NoShell=true -config Alchemy::LogLevel=0 -config Alchemy::Vector=true -config Alchemy::NoVector=false -config Alchemy::SetjmpAbuse=false -swf AlchemyAD_hack,800,600,60 AlchemyAD_hack.as
*/
package
{    
 import flash.display.Sprite;
 import flash.text.TextField;
 import flash.utils.ByteArray;
 import flash.utils.Endian;
 import flash.system.ApplicationDomain;
 public class AlchemyAD_hack extends Sprite{

public function AlchemyAD_hack () 
{ 
  /*Create the print shell*/
  var MyShell:TextField=new TextField();
  MyShell.height=600;
  addChild(MyShell);
  function print(output:*):void
  {
   MyShell.appendText(String(output));
   MyShell.appendText("\n");
  }
  
  /*Test Memory Write*/
  //ByteArray for the test
  var testData:ByteArray = new ByteArray();
  testData.endian = Endian.LITTLE_ENDIAN;
  testData.length=0xffff*4;
  //select testdata in memory
  ApplicationDomain.currentDomain.domainMemory=testData;
  var AdrInt:int=0;
  //the test value we will write into testData via memory
  var testValue:int=123;
  //write the testValue into testData
  ApplicationDomain.currentDomain.domainMemory[0] = testValue;
  //Check if testValue has been written into testData
  print(testData[0]);//should print 123
  
  /*Test Memory Read*/
  var readedValue:int=ApplicationDomain.currentDomain.domainMemory[0];
  print(readedValue);//should print 123 
  
  /*Test Inline ASM*/
  //label and jump
  __asm(jump, target('myLable'));
  print("not jumped!");//this line will be skipped
  __asm(label, lbl('myLable'));
  print("jumped!"); 
  //switch jump
  var myState:int=1;
  __asm(push(myState), switchjump('state0','state1','state2'));
  __asm(lbl('state0'));
  print("This is state0.");
  __asm(lbl('state1'));
  print("This is state1.");
  __asm(lbl('state2'));
  print("This is state2.");
  //iftrue jump
  var temp:int=1;
  __asm(push(temp!=0), iftrue, target('turejump'));
  print("iftrue not jumped!");//this line will be skipped
  __asm(label, lbl('turejump'));
  print("iftrue jumped!"); 
  
  /*Test Alchemy Memory Instructions*/
  //All memory opcodes listed here:
  /*
  Get a 32 bit value at the location addr and return as an int:
  _mr32(addr:int):int{ return __xasm(push(addr), op(0x37)); }

  Get a 16 bit unsigned value at the location addr and return as an int:. 
  _mru16(addr:int):int { return __xasm(push(addr), op(0x36)); }

  Get a 16 bit signed value at the location addr and return as an int: 
  _mrs16(addr:int):int { return __xasm(push(addr), op(0x36)); } // li16

  Get a 8 bit value at the location addr and return as an int:
  _mru8(addr:int):int { return __xasm(push(addr), op(0x35)); }
  
  Get a 8 bit value at the location addr and return as an int: 
  _mrs8(addr:int):int { return __xasm(push(addr), op(0x35)); }

  Get a float value at the location addr and return as an Number:
  _mrf(addr:int):Number { return __xasm(push(addr), op(0x38)); }

  Get a double value at the location addr and return as an Number:
  _mrd(addr:int):Number { return __xasm(push(addr), op(0x39)); }

  Write an int as a 32 bit value at the location addr: 
  _mw32(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3c)); }

  Write an int as a 16 bit value at the location addr: 
  _mw16(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3b)); }

  Write an int as a 8 bit value at the location addr: 
  _mw8(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3a)); }

  Write a Number as a float at the location addr: 
  _mwf(addr:int, val:Number):void { __asm(push(val), push(addr), op(0x3d)); }

  Write a Number as a double at the location addr:
  _mwd(addr:int, val:Number):void { __asm(push(val), push(addr), op(0x3e)); }
  */
  
  //Write an int 654321 as a 32 bit value at the location 1000
  __asm(push(654321),push(1000),op(0x3c));
  //Trace the memory
  ApplicationDomain.currentDomain.domainMemory.position=1000;
  print(ApplicationDomain.currentDomain.domainMemory.readInt());//should print 654321
  //Get a 32 bit value at the location 1000 and return as an int
  var temp:int=__xasm(push(1000), op(0x37));
  print(temp);//should print 654321

  /*Test some AVM2 Instructions*/
  //More AVM2 Instructions can be found at:
  //http://www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html
  
  //test add: 0xA0 
  var var1:int=123;
  var var2:int=321;
  //write (var1+var2)=444 to testData[0] via memory
  //ApplicationDomain.currentDomain.domainMemory.position=AdrInt;
  //ApplicationDomain.currentDomain.domainMemory.writeInt(var1+var2);
  __asm(push(var1), push(var2), op(0xA0), push(AdrInt), op(0x3c));
  testData.position=0;
  print(testData.readInt());//should print 444
  
  //test subtract: 0xA1
  var result:int=__xasm(push(var1), push(var2), op(0xA1));//var result=var1-var2;
  print(result);//should print -198
  //write (var1-var2)=-198 to testData[1] via memory in a different way
  __asm(push(result),push(AdrInt+4),op(0x3c));
  testData.position=4;
  print(testData.readInt());//should print -198
  
}//end of function AlchemyAD_hack

}//end of class
}//end of pacakge
/*
References:
http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:AS3_API
http://unitzeroone.com/blog/2009/05/22/another-scream-on-flash-alchemy-memory-and-compilers/
http://blog.frankula.com/?p=211
http://forums.adobe.com/message/2616985
http://forums.adobe.com/message/3001861
Special thanks to Bernd Paradies (http://forums.adobe.com/people/Bernd%20Paradies)
*/
======
Update: 20, Feb., 2011
All AVM2 Opcode names for Alchemy can be found here:(ASC source code)
http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/modules/asc/src/java/macromedia/abc/Opcodes.java
so for example, the following code
var result:int=__xasm(push(var1), push(var2), op(0xA1));
can be also writen as
var result:int=__xasm(push(var1), push(var2), subtract);
======
The output:
123
123
jumped!
This is state2.
iftrue jumped!
654321
654321
444
-198
-198

And when we compile C/C++ code to swf or swc, we can manuly modify the *.as file generated during the compilation process, for optimization and then use Alchemy asc to compile the modified *.as to swf or swc. By default the temp *.as file will be deleted, to get that file, we can simply copy and paste that file before it deleted during the compilation, or modify the "gcc" file in "alchemy\achacks" folder, remove/commentize the last two lines:
# remove junk TODO failure leaves stuff around!
if(!$ENV{ACHACKS_TMPS})
{ sys("rm", "-f", &lt;$$.achacks.*>) }
Now we have the generated *.as files from the compiler, something like "19048.achacks.as".
It's easy to compile the *.as to a swf, use the command in the code snippet above.

To compile the *.as to swc, there are several ways.
First way, you can compile the *.as to swf, unzip the swc compiled before and replace the "library.swf" with the new swf. I've tried this but there are some problems I haven't solved.
Second way, modify the gcc file, you can follow this post: http://blog.frankula.com/?p=211.
Third way, use the makefile from this project:
http://alchemy-hacks.googlecode.com/svn/trunk/tricks/
Fourth way, follow this post
http://unitzeroone.com/blog/2009/05/22/another-scream-on-flash-alchemy-memory-and-compilers/
Fifth way, mentioned by Bernd Paradies, can be found here: http://forums.adobe.com/message/3001861
Final way, this is what I recommend, use the wrapper by Ed McManus.
Ed McManus posted the script here: http://forums.adobe.com/message/2616985,
but there are some errors caused by the forum formatting. I fixed the errors,
one obvious error is extra spaces in "nbsp;", another big problem is when you try to use the compiled swc, flashdevelop will throw the error "Target Matching “[xX][mM][lL]” is Not Allowed", thanks to this post http://www.anujgakhar.com/2009/02/17/the-processing-instruction-target-matching-xxmmll-is-not-allowed/, I figure out this problem is caused by the spaces before
catalog.xml's header. I made changes to the script and now it works properly.

You can download the fixed version(alc-asc) here: http://flaswf.googlecode.com/svn/trunk/QuickAlchemy/Hack/SWC/
To use it, put it into your "alchemy/achacks" folder, go to cygwin use command
such as "alc-asc modifiedAlchemy.as outputLib.swc".

Links:
http://forums.adobe.com/message/2616985
http://forums.adobe.com/message/3001861
http://blog.frankula.com/?p=211
http://www.anujgakhar.com/2009/02/17/the-processing-instruction-target-matching-xxmmll-is-not-allowed/
http://unitzeroone.com/blog/2009/05/22/another-scream-on-flash-alchemy-memory-and-compilers/
And Ed McManus wrote some very good documents on Alchemy -
General Porting Tips:
https://github.com/emcmanus/flashsnes/blob/master/docs/General_Porting_Tips
Alchemy VM Architecture:
https://github.com/emcmanus/flashsnes/blob/master/docs/Alchemy_VM_Architecture.txt
Performance:
https://github.com/emcmanus/flashsnes/blob/master/docs/Performance

Thursday, January 13, 2011

Adobe Alchemy Hacks - access memory and use inline asm in C

It's not a short time since Alchemy emerged in 2008.
To my disapointment, scarcely any more great C projects ported to Flash after doom and quake.
And there is no updates for this great tool.I like alchemy and use it a lot because it allows you to do flash in C. Alchemy is much more than the new fast memory opcodes, it is a C virtual machine, which wraps the standard C lib for ActionScript. Do flash in C, makes porting C programs easy and also makes your flash program portable. Moreover, the gcc and llvm compilers can optimaize your code a lot. That's why although there are both powerful tools like apparat, yogda and handy tools like azoth which let you to use those alchemy memory opcodes in pure AS3, I'm still using alchemy. Actually, if there is no alchemy, I was already a Haxer in 2008.

The obvious disadvantage to use alchemy is this tool has lots of bugs and it is very hard to debug. As far as I know most bugs are with C++(broken string.h, can't use cin/cout, the class initialization function will never initialize), so don't try to port a C++ program with alchemy now unless you're ready to port the C++ program to C first. What's more, it lacks documentations and developing resources. Although the official forum is a good place to discuss alchemy, it' not easy to find some advanced and detailed things. There is no instructions for inline asm and memory manipulation which many people may be intereted in.
After some search, finally I got some useful things.
So I wrote this little code snippet, hope to help those who want to know more about how to use alchemy. I hope Adobe can give more emphasis on alchemy, update it, remove the bugs, make it stable and make the developing process easier. It is a great thing and should not only be an experimental project, which be played with for some moment, then thrown into some dark corner of the lab and let it decay. I even wish Adobe could make C/C++ an official alternative for ActionScript to develop flash.

/*
[Adobe Alchemy Hacks]
AlchemyVM_hack.c
{Simple example for using inline asm and 
accessing memory of Alchemy Virtual Machine in C}
By Bruce Jawn (January/14/2011)
[http://bruce-lab.blogspot.com]

To compile this source file with Alchemy: 
cd /cygdrive/f/alchemy/
source /cygdrive/f/alchemy/alchemy-setup
alc-on
gcc AlchemyVM_hack.c -O3 -Wall -swf -o AlchemyVM_hack.swf
*/
#include 
#include 
//get the Alchemy C Virtual Machine memory
//use asm to embed AS3 code
asm("var ALCVM_Memory:ByteArray = gstate.ds;");
int main () 
{ 
  /*Test Memory Write*/
  //array of int for the test
  int* testData = malloc(0xff * sizeof(int));
  //get the address of testdata in memory
  AS3_Val Adr=AS3_Ptr(testData);
  int AdrInt=AS3_IntValue(Adr);
  //the test value we will write into testData via memory
  int testValue=123;
  //write the testValue into testData
  //gcc AT&T inline assembly used here
  asm("ALCVM_Memory[%0] = %1;" : : "r"(AdrInt), "r"(testValue)); //ALCVM_Memory[AdrInt] = testValue;
  //Check if testValue has been written into testData
  printf("%d\n",testData[0]);//should print 123
  
  /*Test Memory Read*/
  int readedValue;
  asm("%0 ALCVM_Memory[%1];" : "=r"(readedValue) : "r"(AdrInt));
  printf("%d\n",readedValue);//should print 123
  
  /*Test Inline ASM*/
  //label and jump
  asm("__asm(jump, target('myLable'))");
  printf("%s\n","not jumped!");//this line will be skipped
  asm("__asm(label, lbl('myLable'))");
  printf("%s\n","jumped!"); 
  //switch jump
  asm("var myState:int=1;");
  asm("__asm(push(myState), switchjump('state0','state1','state2'));");
  asm("__asm(lbl('state0'))");
  printf("%s\n","This is state0.");
  asm("__asm(lbl('state1'))");
  printf("%s\n","This is state1.");
  asm("__asm(lbl('state2'))");
  printf("%s\n","This is state2.");
  //iftrue jump
  asm("var temp:int=1;");
  asm("__asm(push(temp!=0), iftrue, target('turejump'));");
  printf("%s\n","iftrue not jumped!");//this line will be skipped
  asm("__asm(label, lbl('turejump'))");
  printf("%s\n","iftrue jumped!"); 
  
  /*Test Alchemy Memory Instructions*/
  //All memory opcodes listed here:
  /*
  Get a 32 bit value at the location addr and return as an int:
  _mr32(addr:int):int{ return __xasm(push(addr), op(0x37)); }

  Get a 16 bit unsigned value at the location addr and return as an int:. 
  _mru16(addr:int):int { return __xasm(push(addr), op(0x36)); }

  Get a 16 bit signed value at the location addr and return as an int: 
  _mrs16(addr:int):int { return __xasm(push(addr), op(0x36)); } // li16

  Get a 8 bit value at the location addr and return as an int:
  _mru8(addr:int):int { return __xasm(push(addr), op(0x35)); }
  
  Get a 8 bit value at the location addr and return as an int: 
  _mrs8(addr:int):int { return __xasm(push(addr), op(0x35)); }

  Get a float value at the location addr and return as an Number:
  _mrf(addr:int):Number { return __xasm(push(addr), op(0x38)); }

  Get a double value at the location addr and return as an Number:
  _mrd(addr:int):Number { return __xasm(push(addr), op(0x39)); }

  Write an int as a 32 bit value at the location addr: 
  _mw32(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3c)); }

  Write an int as a 16 bit value at the location addr: 
  _mw16(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3b)); }

  Write an int as a 8 bit value at the location addr: 
  _mw8(addr:int, val:int):void { __asm(push(val), push(addr), op(0x3a)); }

  Write a Number as a float at the location addr: 
  _mwf(addr:int, val:Number):void { __asm(push(val), push(addr), op(0x3d)); }

  Write a Number as a double at the location addr:
  _mwd(addr:int, val:Number):void { __asm(push(val), push(addr), op(0x3e)); }
  */

  //Write an int 654321 as a 32 bit value at the location 1000
  asm("__asm(push(654321),push(1000),op(0x3c));");
  //Trace the memory
  asm("ALCVM_Memory.position=1000");
  asm("trace(ALCVM_Memory.readInt());");//should trace 654321 in flashlog.txt
  //Get a 32 bit value at the location 1000 and return as an int
  asm("var temp:int=__xasm(push(1000), op(0x37));");
  asm("trace(temp)");//should trace 654321 in flashlog.txt

  /*Test some AVM2 Instructions*/
  //More AVM2 Instructions can be found at:
  //http://www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html
  
  //test add: 0xA0 
  int var1=123;
  int var2=321;
  //write (var1+var2)=444 to testData[0] via memory
  //ALCVM_Memory.position=AdrInt;
  //ALCVM_Memory.writeInt(var1+var2);
  asm("__asm(push(%0), push(%1), op(0xA0), push(%2), op(0x3c))" : : "r"(var1), "r"(var2), "r"(AdrInt));
  printf("%d\n",testData[0]);//should print 444

  //test subtract: 0xA1  
  asm("var result:int=__xasm(push(%0), push(%1), op(0xA1));" : : "r"(var1), "r"(var2));//var result=var1-var2;
  //write (var1-var2)=-198 to testData[1] via memory in a different way
  asm("__asm(push(result),push(%0),op(0x3c));":: "r"(AdrInt+4));
  printf("%d\n",testData[1]);//should print -198

  return 0;
} 
/*
References:
http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:AS3_API
http://blog.frankula.com/?p=211
http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
http://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
Special thanks to zazzo9 (http://forums.adobe.com/people/zazzo9)
http://forums.adobe.com/thread/660099
http://forums.adobe.com/message/2101303
http://forums.adobe.com/message/1059161
http://forums.adobe.com/message/1915605
http://forums.adobe.com/message/2101405
http://forums.adobe.com/message/1914780
*/
The compiled swf will display:
123
123
jumped!
This is state2.
iftrue jumped!
444
-198
The flashlog(C:\Documents and Settings\Administrator\Application Data\Macromedia\Flash Player\Logs\flashlog.txt)
654321
654321
[object AlchemyExit]
at global/shellExit()
at cmodule.AlchemyVM_hack::CSystemLocal/exit()
at cmodule.AlchemyVM_hack::CRunner/work()
at ()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick

[Update 2012/Jan/06]
Alchemy GOODIES: The C and AS3 mixed syntax using ASM.
It is not a good habit to mix C code with AS3, but this can be handy sometimes:
//AS3 values to C
int myINT = 0;
asm("var ASvar1 = 1; var ASvar2 = 2;");//Embed AS3 code in C
asm("%0 ASvar1+ASvar2" : "=r"(myINT) : );//myINT=ASvar1+ASvar2;
AS3_Trace(AS3_String("myINT="));
AS3_Trace(AS3_Int(myINT));//will print 3

//C values to AS3
int myINT0 = 123456;
asm("var ASvar0:int;");
asm("ASvar0 = %0" :: "r" (myINT0) );
asm("trace('ASvar0=');");
asm("trace(ASvar0);");//will print 123456

Tuesday, January 4, 2011

Ken Silverman's GROUFST2 Terrain Raycaster Ported to AS3


Simple nice heightmap terrain raycaster, a good start for your own voxel engine.
Fork it here:
http://wonderfl.net/c/7d41
or
http://flaswf.googlecode.com/svn/trunk/GROUFST2/
==========
Update: April, 4,2011
GROUFST2 Ported to HaXe(Supporting targeting swf and cpp both):
Source Code: https://flaswf.googlecode.com/svn/trunk/GROUFST2/Groufst2HXNME
==========
Update: 11, 11,2011
Add HTML5 support:
Source Code: https://flaswf.googlecode.com/svn/trunk/GROUFST2/Groufst2HXNME/Groufst2NME_HTML5/
DEMO:  https://flaswf.googlecode.com/svn/trunk/GROUFST2/Groufst2HXNME/Groufst2NME_HTML5/Export/html5/bin/index.html (Very, very slow.)
==========

Original source code can be found at Ken's website:
Qbasic: http://www.advsys.net/ken/voxlap.htm (GROUFST2.BAS)
EVALDRAW: http://www.advsys.net/ken/download.htm (evaldraw.zip\demos\groufst2b.kc)

And

Happy Coding 2011!

Sponsors