-->

Following from my previous articles on setting up an Alchemy development environment in Flex Builder 3 and passing/returning objects to/from C++, I wanted to test some of the claims of the speed increase possible with the use of this tool.

With the particular interest in 3D Flash applications, I wanted to test specific mathematical operations using vectors and matrices, namely cross products, normalisation, rotation matrix calculations and vector transformations.

I had initially aimed to create a mathematical library where these functions can be calculated on native ActionScript objects - for example create a function to calculate the cross product of two vectors. However one aspect of Alchemy that became immediately evident is that the cost of marshaling data through the AS3-C++ API is horrendously expensive. This is quite normal so I guess I was naive to expect good results from this. But to give you an example of how expensive this is, for a simple iterative calculation of the cross product of two vectors followed by a normalisation: if the mathematical functions are performed in C++, ie iteratively calling the Alchemy compiled functions, the result is about 1000 times slower than natively performing the calculations in AS3!

So, my first advice is: limit the number of Alchemy calls!!

Anyway, in this article I’ll concentrate on performing pure C++ speed tests (called from AS3) - so computationally intensive calculations performed in a single Alchemy call - compared to the equivalent pure AS3 speed tests.

The tests performed here concentrate on vector and matrix operations. I’ve therefore created very simple Vector and Matrix classes in C++. The Vector class is used to perform dot product, normalisation and cross product operations as shown below.

Vector3D.h :

#ifndef VECTOR3D_H_ #define VECTOR3D_H_ #include "AS3.h" class Vector3D { public :   Vector3D();   Vector3D(double x, double y, double z);   Vector3D(const AS3_Val& as3Vector);   virtual ~Vector3D();   double dot(const Vector3D& v) const;   Vector3D cross(const Vector3D& v) const;   double modulus() const;   Vector3D normalise() const;   void setX(double x);   void setY(double y);   void setZ(double z);     double getX() const;   double getY() const;   double getZ() const; private :   double _x;   double _y;   double _z; }; #endif /*VECTOR3D_H_*/

Vector3D.cpp :

#include "Vector3D.h" #include <cmath> Vector3D::Vector3D() :   _x(0),   _y(0),   _z(0) { } Vector3D::Vector3D(const AS3_Val& as3Vector) {   AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &_x, &_y, &_z); } Vector3D::Vector3D(double x, double y, double z) :   _x(x),   _y(y),   _z(z) { } Vector3D::~Vector3D() { } double Vector3D::dot(const Vector3D& v) const {   return v._x*_x + v._y*_y + v._z*_z; } Vector3D Vector3D::cross(const Vector3D& v) const {   Vector3D result;   result._x = _y*v._z - _z*v._y;   result._y = _z*v._x - _x*v._z;   result._z = _x*v._y - _y*v._x;     return result; } double Vector3D::modulus() const {   return std::sqrt(_x*_x + _y*_y + _z*_z); } Vector3D Vector3D::normalise() const {   double mod = modulus();   return Vector3D(_x/mod, _y/mod, _z/mod); } void Vector3D::setX(double x) {   _x = x; } void Vector3D::setY(double y) {   _y = y; } void Vector3D::setZ(double z) {   _z = z; } double Vector3D::getX() const {   return _x; } double Vector3D::getY() const {   return _y; } double Vector3D::getZ() const {   return _z; }

One point, specific to Alchemy, is in one of the constructors for the Vector3D: the properties are extracted from the passed AS3 Vector3D object, as discussed in my previous article.

The Matrix3D C++ class is as follows.

Matrix3D.h :

#ifndef MATRIX3D_H_ #define MATRIX3D_H_ #include "Vector3D.h" class Matrix3D { public :   Matrix3D();   virtual ~Matrix3D();   void setRotationX(double degrees);   void setRotationY(double degrees);   void setRotationZ(double degrees);   void setIdentity();   Vector3D transformVector(const Vector3D& vector) const; private :   double _M00;   double _M01;   double _M02;   double _M10;   double _M11;   double _M12;   double _M20;   double _M21;   double _M22; }; #endif /*MATRIX3D_H_*/

Matrix3D.cpp :

#include "Matrix3D.h" #include <cmath> Matrix3D::Matrix3D() :   _M00(1),   _M01(0),   _M02(0),   _M10(0),   _M11(1),   _M12(0),   _M20(0),   _M21(0),   _M22(1) { } Matrix3D::~Matrix3D() { } void Matrix3D::setIdentity() {   _M00 = 1;   _M01 = 0;   _M02 = 0;   _M10 = 0;   _M11 = 1;   _M12 = 0;   _M20 = 0;   _M21 = 0;   _M22 = 1; } void Matrix3D::setRotationX(double degrees) {   setIdentity();   double radians = degrees / 180 * M_PI;     _M11 = cos(radians);   _M12 = -sin(radians);   _M21 = sin(radians);   _M22 = cos(radians); } void Matrix3D::setRotationY(double degrees) {   setIdentity();   double radians = degrees / 180 * M_PI;     _M00 = cos(radians);   _M02 = sin(radians);   _M20 = -sin(radians);   _M22 = cos(radians); } void Matrix3D::setRotationZ(double degrees) {   setIdentity();   double radians = degrees / 180 * M_PI;     _M00 = cos(radians);   _M01 = -sin(radians);   _M10 = sin(radians);   _M11 = cos(radians); } Vector3D Matrix3D::transformVector(const Vector3D& vector) const {   Vector3D result;     result.setX(_M00*vector.getX() + _M01*vector.getY() + _M02*vector.getZ());   result.setY(_M10*vector.getX() + _M11*vector.getY() + _M12*vector.getZ());   result.setZ(_M20*vector.getX() + _M21*vector.getY() + _M22*vector.getZ());     return result; }

One of the objectives of using the Matrix3D class is to test the performance of the trigonometric functions. A common source of intensive calculations in 3D graphics is the rotation of vectors so this provides a useful test directly aimed at this field.

Two tests are to be examined: one for cross product calculations and another for matrix transformations. These are defined in the main.cpp file.

#include "AS3.h" #include "Vector3D.h" #include "Matrix3D.h" AS3_Val speedTest1(void* self, AS3_Val args) {   // Declare AS3 variables   AS3_Val as3Vector1;   AS3_Val as3Vector2;     // Extract variables from arguments array   AS3_ArrayValue(args, "AS3ValType, AS3ValType", &as3Vector1, &as3Vector2);     // Create native C++ objects with AS3 parameters   Vector3D vector1(as3Vector1);   Vector3D vector2(as3Vector2);     Vector3D vector3;           // Speed test : calculate cross products and normalise   for (int i = 0; i < 1000000; i++) {     vector3 = vector1.cross(vector2);     vector3 = vector3.normalise();     vector1 = vector2;     vector2 = vector3;   }   // Obtain a class descriptor for the AS3 Vector3D class   AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));   AS3_Val params = AS3_Array("");     // Construct a new AS3 Vector3D object with empty parameters   AS3_Val result = AS3_New(vector3DClass, params);     // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate   AS3_Set(result, AS3_String("x"), AS3_Number(vector3.getX()));   AS3_Set(result, AS3_String("y"), AS3_Number(vector3.getY()));   AS3_Set(result, AS3_String("z"), AS3_Number(vector3.getZ()));   // Release what's no longer needed   AS3_Release(params);   AS3_Release(vector3DClass);     // return the AS3 Vector   return result; } AS3_Val speedTest2(void* self, AS3_Val args) {   // Declare AS3 variable   AS3_Val as3Vector;     // Extract variables from arguments array   AS3_ArrayValue(args, "AS3ValType", &as3Vector);   // Create native C++ object with AS3 parameters   Vector3D vector(as3Vector);     Vector3D copy = vector;     Matrix3D rotationX;   Matrix3D rotationY;   Matrix3D rotationZ;           // Speed test : calculate rotation matrices and transform vector   for (int i = 0; i < 1000; i++) {     vector = copy;     for (double ang = 0; ang < 180; ang++) {       rotationX.setRotationX(ang);       rotationY.setRotationY(ang);       rotationZ.setRotationZ(ang);             vector = rotationX.transformVector(vector);       vector = rotationY.transformVector(vector);       vector = rotationZ.transformVector(vector);     }   }   // Obtain a class descriptor for the AS3 Vector3D class   AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));   AS3_Val params = AS3_Array("");     // Construct a new AS3 Vector3D object with empty parameters   AS3_Val result = AS3_New(vector3DClass, params);     // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate   AS3_Set(result, AS3_String("x"), AS3_Number(vector.getX()));   AS3_Set(result, AS3_String("y"), AS3_Number(vector.getY()));   AS3_Set(result, AS3_String("z"), AS3_Number(vector.getZ()));   // Release what's no longer needed   AS3_Release(params);   AS3_Release(vector3DClass);     // return the AS3 Vector   return result; } /** * Main entry point for Alchemy compiler. Declares all functions available * through the Alchemy bridge. */ int main() {   // Declare all methods exposed to AS3 typed as Function instances   AS3_Val speedTest1Method = AS3_Function(NULL, speedTest1);   AS3_Val speedTest2Method = AS3_Function(NULL, speedTest2);   // Construct an object that contains references to all the functions   AS3_Val result = AS3_Object("speedTest1:AS3ValType, speedTest2:AS3ValType", speedTest1Method, speedTest2Method);   // Release what's no longer needed   AS3_Release(speedTest1Method);   AS3_Release(speedTest2Method);   // Notify the bridge of what has been created -- THIS DOES NOT RETURN!   AS3_LibInit(result);   // Should never get here!   return 0; }

For an explanation of the code and the C++ API of Alchemy, I’ll refer you to my previous article on passing and returning objects to and from C++ using Alchemy.

The first test, speedTest1, performs 1,000,000 times the cross product of two vectors (initially passed by AS3) followed by a normalisation. The resulting vector is used in the following iteration. At the end of all the iterations, the final vector is returned to AS3.

The second test, speedTest2, calculates rotation vectors around the x, y and z axes. A vector (initially passed by AS3), is then rotated by each matrix individually. This is repeated for 180 steps, increasing the angle of rotation by 1 degree at a time. This again is repeated for a total of 1,000 iterations. The final vector is returned to AS3.

Let’s have a look now at the ActionScript class that calls these tests, and the equivalent pure AS3 tests.

package {   import cmodule.vector.CLibInit;     import flash.display.Sprite;   import flash.display.StageAlign;   import flash.display.StageScaleMode;   import flash.geom.Matrix3D;   import flash.geom.Vector3D;   import flash.text.TextField;   import flash.text.TextFieldAutoSize;   import flash.utils.getTimer;   public class AlchemySpeedTest extends Sprite {     private var vectorUtils:Object;     public function AlchemySpeedTest() {       // Set up the stage       stage.align = StageAlign.TOP_LEFT;       stage.scaleMode = StageScaleMode.NO_SCALE;       // Create the Alchemy bridge to C++ methods       var loader:CLibInit = new CLibInit;       vectorUtils = loader.init();       // Create a text field                  var timerText:TextField = new TextField();       timerText.autoSize = TextFieldAutoSize.LEFT;       addChild(timerText);               // Initialise a timer       var time0:int = getTimer()       // Perform the speed test       var vector:Vector3D = speedTest1();       //var vector:Vector3D = speedTest2();       //var vector:Vector3D = nativeSpeedTest1();       //var vector:Vector3D = nativeSpeedTest2();             // Calculate the elapsed time       var time1:int = getTimer()       var totalTime:int = time1 - time0;             // Display elapsed time and final vector       timerText.text = "Time taken = " + totalTime + " vector = (" + vector.x + ", " + vector.y + ", " + vector.z + ")";     }     /**     * Speed test using C++ to iteratively calculate the cross products of two vectors     */     private function speedTest1():Vector3D {       var vector1:Vector3D = new Vector3D(0.123, 0.456, 0.789);       var vector2:Vector3D = new Vector3D(0.987, 0.654, 0.321);       return vectorUtils.speedTest1(vector1, vector2);     }     /**     * Speed test using C++ to iteratively calculate rotation matrices and apply these to a vector     */     private function speedTest2():Vector3D {       var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);             return vectorUtils.speedTest2(vector);          }     /**     * Speed test using AS3 to iteratively calculate the cross products of two vectors     */     private function nativeSpeedTest1():Vector3D {       var vector1:Vector3D = new Vector3D(0.123, 0.456, 0.789);       var vector2:Vector3D = new Vector3D(0.987, 0.654, 0.321);       var vector3:Vector3D;             var time0:int = getTimer()             for (var i:int = 0; i < 1000000; i++) {         vector3 = vector1.crossProduct(vector2);         vector3.normalize();         vector1 = vector2;         vector2 = vector3;       }             return vector3;     }     /**     * Speed test using AS3 to iteratively calculate rotation matrices and apply these to a vector     */     private function nativeSpeedTest2():Vector3D {       var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);       var copy:Vector3D = vector.clone();       var rotationX:Matrix3D = new Matrix3D();       var rotationY:Matrix3D = new Matrix3D();       var rotationZ:Matrix3D = new Matrix3D();       for (var i:int = 0; i < 1000; i++) {         vector = copy.clone();         for (var ang:Number = 0; ang < 180; ang++) {           rotationX.identity();           rotationX.appendRotation(ang, Vector3D.X_AXIS);           rotationY.identity();           rotationY.appendRotation(ang, Vector3D.Y_AXIS);           rotationZ.identity();           rotationZ.appendRotation(ang, Vector3D.Z_AXIS);                     vector = rotationX.transformVector(vector);           vector = rotationY.transformVector(vector);           vector = rotationZ.transformVector(vector);                   }       }             return vector;     }   } }

Without going into too many details of the code, you’ll see that in the constructor we can choose one of four tests: speedTest1 and speedTest2, as discussed above, and nativeSpeedTest1 and nativeSpeedTest2 which perform the same calculations but using pure ActionScript classes. The time taken to perform the calculations is then displayed along with the final vector so that we can be sure that the results are the same in a TextField.

To make reasonable comparisons I’ve tried to make the object creation in both ActionScript and C++ relatively equal: creating objects takes time so can obfuscate the obtained timing results. If you find any glaring differences between the C++ and ActionScript versions then please let me know and I’ll modify this post.

If you’d like to take a look at the whole project (set up using automake and ant as shown in my previous article on setting up a development environment for Alchemy in Flex Builder 3) then you can find all the files here.

Results
The native and Alchemy speed tests were compared initially to ensure that they both produce the same results. One surprising result was that for the matrix rotation test, the resulting vector diverged progressively as the number of iterations increased. This is presumably because of rounding errors being different between C++ (which uses double floating point values) and ActionScript. To limit this, you’ll notice that the vector is reset before the inner iteration over the 180 angles.

More important are the timing results… and the winner is… !

For speedTest1 (vector cross product and normalisation) I obtained the following:
Alchemy : 1309ms (averaged from 4 runs: 1346, 1285, 1284, 1322)
Native : 1192ms (averaged from 4 runs: 1232, 1147, 1176, 12123)

For speedTest2 (rotation matrix creation and vector transformation) the following times were obtained:
Alchemy : 814ms (averaged from 4 runs: 803, 826, 814, 813)
Native : 792ms (averaged from 4 runs: 774, 787, 789, 816)

Conclusion
As you can see, even with computationally intensive calculations, native ActionScript beats Alchemy compiled C++. Shame - I was expecting huge improvements! And don’t forget that calling Alchemy code is very expensive - these tests have minimised this cost.

But is it really surprising? After all, we’re not executing natively compiled C++ code: we’re executing C++ bytecode compiled for the ActionScript virtual machine. Plus the native ActionScript functions have already been optimised.

Going to some extent to explain this, this article at Automata Studios on Understanding Adobe Alchemy (who used Alchemy to port OggVorbis to ActionScript 3) provides very interesting reading. As they say in the article:

“… Knowing that Alchemy is just spitting out the same AVM2 bytecode that Flash and Flex spit out it is pretty confusing how Alchemy code could be faster than standard ActionScript. In fact, it is not faster across the board - just in specific types of operations and when the length of a task can be used to overcome Alchemy’s intrinsic overhead….

And also:

“… Now, what are these operations that Alchemy does so well? Memory access and function calls. Alchemy compiled code utilizes new bytecodes added to FP10 for working with ByteArrays - which as you’ll remember are what make up the “RAM” in Alchemy. …”

So the result seems somewhat less attractive than that claimed by Adobe (“… Ideally suited for computation-intensive use cases (…) performance can be considerably faster than ActionScript 3.0 …”) and much more specific to the type of operations being performed.

The tests shown here are of course very limited in their scope: the idea is to provoke some discussion about where Alchemy can be beneficial rather than just stating that Alchemy will produce pure gold in all situations.

One area which may be of interest is that of green threads as stated in the above article. However these threads are platform independent and are executed in the virtual machine rather on the native OS. This limitation means that the benefits of multi-core processors cannot be tapped into… so can they really produce reasonable results when calculations are performed in parallel?

Anyway, I hope this has been of interest and of some use - as always comments, suggestions and questions are welcome!

Following from my last article on setting up an Alchemy development environment in Flex Builder 3, I wanted to illustrate briefly how objects can be passed to C++ methods using Alchemy (and similarly how the ActionScript properties can be extracted) and how we can return objects to the calling AS3 code.

This article has been prompted since I found very little useful documentation on the web, so hopefully this’ll be useful for other beginners! Other than the C++ API for Alchemy provided by Adobe (which is essential), I’ve found the following links very useful in providing concrete examples of getting started in Alchemy:

These provided the essential lines of code necessary to understand the API, and be able to pass objects to C/C++ and similarly return objects to ActionScript.

The following is some C code to illustrate this. Essentially a flash.geom.Vector3D object is passed to a function, foo, which then returns a copy of the object to the calling function.

#include "AS3.h" AS3_Val foo(void* self, AS3_Val args) {   // declare local variables   double x;   double y;   double z;     // ******* Passing objects as parameters to C++ *******     // Declare AS3 variable   AS3_Val as3Vector;     // Extract variables from arguments array (in this case a flash.geom.Vector3D)   AS3_ArrayValue(args, "AS3ValType", &as3Vector);   // Extract properties from object and store in local variables   AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &x, &y, &z);   // ******* Returning objects to AS3 *******   // Obtain a class descriptor for the AS3 Vector3D class   AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));   AS3_Val params = AS3_Array("");     // Construct a new AS3 Vector3D object with empty parameters   AS3_Val result = AS3_New(vector3DClass, params);     // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate   AS3_Set(result, AS3_String("x"), AS3_Number(x));   AS3_Set(result, AS3_String("y"), AS3_Number(y));   AS3_Set(result, AS3_String("z"), AS3_Number(z));   // Release what's no longer needed   AS3_Release(params);   AS3_Release(vector3DClass);     // return the AS3 flash.geom.Vector3D object   return result; } /** * Main entry point for Alchemy compiler. Declares all functions available * through the Alchemy bridge. */ int main() {   // Declare all methods exposed to AS3 typed as Function instances   AS3_Val fooMethod = AS3_Function(NULL, foo);   // Construct an object that contains references to all the functions   AS3_Val result = AS3_Object("foo:AS3ValType", fooMethod);   // Release what's no longer needed   AS3_Release(fooMethod);   // Notify the bridge of what has been created -- THIS DOES NOT RETURN!   AS3_LibInit(result);   // Should never get here!   return 0; }

Let’s take a look at this bit by bit. Starting with the function foo, all functions visible to ActionScript have to be declared in the same way:

AS3_Val foo(void* self, AS3_Val args) {

The return value is always an AS3_Val type and a function always receives a pointer along with an AS3_Val type argument. AS3_Val can be thought of as the Object type in AS3 - all concrete types inherit from this so utilities are needed to extract useful information from them.

First of all: extracting objects from the args parameter. Whatever, and however many, arguments are passed we always use the method AS3_ArrayValue to extract the real arguments: arguments are always passed in the form of an Array. In the example we do the following:

  // Declare AS3 variable   AS3_Val as3Vector;     // Extract variables from arguments array (in this case a flash.geom.Vector3D)   AS3_ArrayValue(args, "AS3ValType", &as3Vector);

Here we declare an AS3_Val variable (implying that we are expecting an AS3 Object). If the types passed are primitive types (or String types) we could do the following:

int arg0 = 0; char* arg1 = NULL; double arg2 = 0.0; AS3_ArrayValue(arr, "IntType, StrType, DoubleType", &arg0, &arg1, &arg2);

Here the primitive AS3 types are converted to native C++ primitives.

Coming back to our example, we now have an AS3 Object (stored as an AS3_Val type) and we’d like to extract data from it. This is done by making an AS3_ObjectValue call.

  // Extract properties from object and store in local variables   AS3_ObjectValue(as3Vector, "x:DoubleType, y:DoubleType, z:DoubleType", &x, &y, &z);

Here we pass the extracted Object, declare the identifiers and types of properties and a list of local variables to store the value in. For the Vector3D we want to obtain the x, y and z properties which are converted to local DoubleType values.

To return an ActionScript object, we need to perform a lookup for the class name with the relevant namespace. From this we can get a class descriptor which can then be instantiated.

  // Obtain a class descriptor for the AS3 Vector3D class   AS3_Val vector3DClass = AS3_NSGet(AS3_String("flash.geom"), AS3_String("Vector3D"));

Here, for example, we obtain an AS3_Val representing the class flash.geom.Vector3D, using the AS3_NSGet function. We can then create an object from this.

  AS3_Val params = AS3_Array("");     // Construct a new AS3 Vector3D object with empty parameters   AS3_Val result = AS3_New(vector3DClass, params);

This object is create with no parameters using the AS3_New function. Again, the result is stored in the base AS3_Val type. Having created a new object we can then modify its properties.

  // Set the x, y and z properties of the AS3 Vector3D object, casting as appropriate   AS3_Set(result, AS3_String("x"), AS3_Number(x));   AS3_Set(result, AS3_String("y"), AS3_Number(y));   AS3_Set(result, AS3_String("z"), AS3_Number(z));

The AS3_Set function takes an AS3 Object, a property identifier and a value, correctly cast to the required AS3 value type, in this case an AS3_Number type. Note that I’ve tried to pass these values in the params Array but have never been successful - if anyone has any tips on doing this I’d be happy to hear from you.

So, now we have an AS3 object created and its properties set. Now we need to do a bit of memory management before returning the object. This is done using the AS3_Release function.

  // Release what's no longer needed   AS3_Release(params);   AS3_Release(vector3DClass);

Finally, we return the created object:

  // return the AS3 flash.geom.Vector3D object   return result;

To export the function foo to ActionScript, the following main function is called - the Alchemy compiler always looks for this function, so its here that we always declare our interface. For the above example the following is necessary:

int main() {   // Declare all methods exposed to AS3 typed as Function instances   AS3_Val fooMethod = AS3_Function(NULL, foo);   // Construct an object that contains references to all the functions   AS3_Val result = AS3_Object("foo:AS3ValType", fooMethod);   // Release what's no longer needed   AS3_Release(fooMethod);   // Notify the bridge of what has been created -- THIS DOES NOT RETURN!   AS3_LibInit(result);   // Should never get here!   return 0; }

Without going into too many details, essentially we create Function objects containing the native C/C++ methods. These are then given an AS3 interface using the AS3_Object function and then passed to the AS3_LibInit function which provides the entry point from ActionScript.

The following ActionScript class shows how we call the Alchemy compiled functions, passing a Vector3D object and obtaining another one in return.

package {   import cmodule.vector.CLibInit;     import flash.display.Sprite;   import flash.geom.Vector3D;   public class Test extends Sprite {     public function Test() {       // Create the Alchemy bridge to C++ methods       var loader:CLibInit = new CLibInit;       var alchemyTest:Object = loader.init();       var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);       var returnVector:Vector3D = alchemyTest.foo(vector);             trace("Return vector = (" + returnVector.x + ", " + returnVector.y + ", " + returnVector.z + ")");           }   } }

Our connection to the C/C++ code is performed by creating a new CLibInit function and calling init.

      // Create the Alchemy bridge to C++ methods       var loader:CLibInit = new CLibInit;       var alchemyTest:Object = loader.init();

This creates a basic ActionScript Object. The functions cannot be seen at the time of compilation (at least not in Flex Builder) but are obtained at run time. The resulting function call on foo is shown as follows:

      var vector:Vector3D = new Vector3D(0.123, 0.456, 0.789);       var returnVector:Vector3D = alchemyTest.foo(vector);

As required, we pass a Vector3D and get a new Vector3D object in return.

And that’s it! If you’d like to have a look at the source and the project set-up together (using the same automake and ant files as discussed in the previous article) then you can find them here.

This is a very quick introduction to passing and returning objects using Alchemy. The API provides many more possibilities but this articles aims to illustrate some of the basic, but essential, functions available - for other beginners I hope this is useful! In my next article I’ll look at some of the capabilities of Alchemy.

-->
Friday, December 12th, 2008

Setting up an Alchemy development environment in Flex Builder 3

I’ve recently been reading a lot of articles recently about the new Alchemy research project at Adobe Labs. At first glances this looks very exciting: compile optimised C/C++ code to be executed within an ActionScript 3 Flash movie. As quoting from the Alchemy home page :

“… Ideally suited for computation-intensive use cases, such as audio/video transcoding, data manipulation, XML parsing, cryptographic functions or physics simulation, performance can be considerably faster than ActionScript 3.0 and anywhere from 2-10x slower than native C/C++ code.”

Sounds good! Ideal even when thinking about 3D graphics that are heavily dependent on vector and matrix calculations…

So, I decided to take a look and see how easy it was to integrate C++ code into an ActionScript project and what the benefits were. I discovered fairly quickly that documention on the web is fairly limited which has prompted this blog entry. Also, I’m a fan of the eclipse development environment and like all my work to be concentrated within the same window so wanted the Alchemy development to be done in parallel to the ActionScript development.

First off, it should be noted that this article is aimed mainly at Mac users: Hopefully there are things along the way that will be useful for Windows but I’m going to be looking at an automake utility to compile the Alchemy code which may not work on Windows (maybe under Cygwin, but I’ve not tried it).

Here are a few links to get started anyway:

First of all download Alchemy Toolkit from Adobe. Personally I copied the extracted directory to the Applications folder in my home directory. Then follow the instruction given on the Getting Started page.

NOTE !! I had huge trouble to start with because I was running a shell with tcsh: you must have bash (which is anyway the default for Mac) running for this to work!

Once I managed to compile the C code using the Alchemy tools, I went straight to Flex Builder 3 to try to integrate the ActionScript and compiled swf together.

In Flex Builder (or the Eclipse plugin as I’m using), create a new ActionScript project called EchoTest, as is the case for the ActionScript class shown on the Alchemy Getting Started page. Now we need to ensure that the project is compiled for Flash Player 10 (this is easily possible if you have Flex Builder 3.0.2 installed). Go to the project Properties menu item, select ActionScript Compiler and for Require Flash Player version enter 10.0.0 and click OK.

In the newly created EchoTest class, copy the code from the GettingStarted page that is linked to compiled C.

package {   import flash.display.Sprite;   import cmodule.stringecho.CLibInit;     public class EchoTest extends Sprite {       public function EchoTest() {         var loader:CLibInit = new CLibInit;       var lib:Object = loader.init();       trace(lib.echo("foo"));     }   } }

This won’t compile because we need to link to the Alchemy-compiled C code. Create a bin directory at the root of the project and copy stringecho.swf, compiled before, here. Go into the project Properties menu item, select ActionScript Build Path, go to the Library Path tab and select Add SWC…. Browse to the bin directory and select stringecho.swf. Now when you click on OK you should find that the project compiles.

To see anything happen you need to run in debug mode… even then its not very exciting: you’ll just see foo written in the Console.

The main objective (for me at least) is to set up an environment where we can compile the C/C++ code with Alchemy within the Flex environment. For this I’m going to be combining some automake files with shell scripts and link them to Eclipse with an ant build file.

Lets first of all copy the alchemy source in the project. Create a directory called alchemy at the root of the project. Into this, copy the C file from the Alchemy samples (ALCHEMY_HOME/samples/stringecho/stringecho.c).

For automake we need a configure.in file and (depending on the project) several Makefile.am files.

At the project root, copy the following into configure.in :

dnl Process this file with autoconf to produce a configure script. AC_INIT(alchemyTest, 0.0.1) AC_CONFIG_AUX_DIR(config) AC_CONFIG_SRCDIR(alchemy/stringecho.c) AM_INIT_AUTOMAKE dnl Compiler AC_PROG_CXX AC_PROG_CC AC_LANG(C++) AC_LANG(C) CFLAGS="" AM_CFLAGS="-Wall -O3 -swc " AC_SUBST(AM_CFLAGS) CXXFLAGS="" AM_CXXFLAGS="-Wall -O3 -swc " AC_SUBST(AM_CXXFLAGS) dnl Initialise top_srcdir top_srcdir=. AC_OUTPUT([ Makefile alchemy/Makefile ])

Create a Makefile.am file at the project root as well containing the following line (indicating simply which is the main alchemy source directory):

SUBDIRS = alchemy

Finally in the alchemy directory, copy the following also into a Makefile.am file :

INCLUDES = -I$(top_srcdir)/alchemy bin_PROGRAMS = stringecho.swc stringecho_swc_SOURCES = \   stringecho.c

That’s all that’s needed for the automake part. Now we need a couple of shell scripts to be called from ant and that take into account the environment variables necessary for the Alchemy tools.

At the root, create a file called init and copy the following:

#!/bin/sh if [ ! -d config ] then   mkdir config; fi if [ ! -x AUTHORS ] then   touch AUTHORS;   touch README;   touch NEWS;   touch ChangeLog; fi aclocal -I config autoconf automake --gnu --add-missing if [ ! -d obj ] then   mkdir obj; fi path=`pwd` cd obj ../configure --prefix=`pwd`/.. cd $path

Once it is created, make sure it is executable by changing the file permissions (chmod +x init). This will essentially create any necessary directories and files (for automake) and launch the configuration process. This will then create all the necessary Makefiles.

In the same directory (the root) create a file called build (that should also be executable) and copy this:

#!/bin/bash ALCHEMY_HOME=$HOME/Applications/Alchemy source $ALCHEMY_HOME/alchemy-setup PATH=$ALCHEMY_HOME/achacks:$PATH export PATH cd obj make -e install

Here we specify the home of Alchemy (so, obviously, change the directories accordingly) and we then launch the compilation, passing the environment variables at the same time (with the -e flag).

Finally, we come to the ant build file. The following should be copied into build.xml at the project root.

<project name="EchoTest" basedir=".">   <property name="builddir" value="."/>   <target name="compile alchemy">     <exec executable="${builddir}/build"/>   </target>   <target name="init alchemy">     <exec executable="${builddir}/init">     </exec>   </target>   <target name="remove obj">     <exec executable="rm">       <arg line="-fr"/>       <arg line="obj"/>     </exec>   </target>   </project>

This includes a couple of targets to initialise the compilation (create the Makefiles) and compile the C source. A final target just removes the compiles object files.

in the end you should have a project structure that looks something like this:

So let’s test this. Open the Ant view in eclipse by selection the menu Window, Show View, Other… and then searching for the Ant view. Drag and drop build.xml into this view and you should find the targets compile alchemy and init alchemy available.

NOTE !!! For this to work you need to lauch eclipse from the command line using the command tcsh -e ./eclipse from the installed eclipse directory. I don’t know why, but ant behaves differently - I presume because environment variables are passed to it! If you could tell me why, or how to avoid this, I’d be very happy to hear from you!

So, back again, assuming that eclipse is launched as tcsh -c ./eclipse, double click on the init alchemy target. You should hopefully see the configuration process in the console terminated with BUILD SUCCESS! This means that the Makefiles are ready. You can now double click on build alchemy to compile the C code. If it works you should see output that resembles that shown of the compilation on the Getting Started page.

The init process is typically necessary only once. From now on when modifying the C code just launch the build target.

This has now compiled stringecho.swc in the bin directory. Refresh the workspace (fn_key + F5 on a Mac) if it doesn’t refresh automatically which then recompiles the ActionScript if a change has occurred. In this case, I’m simply showing a build process so there’s no difference to the result. However, in future projects, you’ll find that every time you recompile using the Alchemy tools you’ll need to refresh the workspace otherwise the ActionScript project isn’t updated.

Also to note, when editing the C or C++ files, I’d recommend using the CDT plugin for eclipse rather than an external editor - again it avoids switching application for compiling the same project!

Anyway, hope this is of some use to people getting started with Alchemy (like me!). If you find any problems then please let me know… same if you have any comments. Next I’ll be looking at testing some of what Alchemy is supposed to be capable of!

Tuesday, November 11th, 2008

Downloading and compiling Away3D sources with SVN in Eclipse

Away3D can be installed either from the latest releases on the Away3D downloads page or from the SVN repository located on the googlecode site.

I’ve chosen the second method so that I can easily and regularly update the source to be up to date with the latest fixes and enhancements. I’m using the same technique that I showed downloading and compiling Papervision3D using SVN in eclipse. Since I use eclipse as my development environment (with the Flex Builder 3 plugin), I like to keep all my sources together in the same environment and the SVN plugin for eclipse works very well.

In eclipse select Import… from the File menu. You’ll see the following window appear.

Under the SVN item, select Projects from SVN and click Next. You’ll then be requested to enter details for the SVN repository.

For the URL enter http://away3d.googlecode.com/svn. Leave the user details empty - we’ll use anonymous access to obtain the source. Click Next to continue. Eclipse will examine the SVN repository and show the repository structure.

We’ll download everything from the trunk (which includes the source, docs and examples), so select trunk and click on Finish. You’ll then be asked how you want to check out the source.

We want to create a Flex Library project so select Check out as a project configured using the New Project Wizard.

Under Flex Builder, choose Flex Library Project and click Next.

Enter Away3D as the Project name (or any other name you’d like…) then select Next to configure the source directory.

Click next to src under Classes to include in the library. The Main source folder should show src, and the Output folder should show bin. Sometimes selecting the source folder here doesn’t always work and we’ll have to explicitly give the source folder again after the project has been created, as shown below.

You should now see in the Flex Navigator in eclipse a new project called Away3D with the latest revision number next to it. If you have the error nothing was specified to be included in the library shown in the Problems view, then you need to re-specify the source directory as I mentioned above. Simply right-click on the Away3D project and select Properties.

Under Flex Library Build Path, once again click next to src in the Classes to include in library box. After clicking OK you should see that eclipse is compiling the sources.

The final result is the Away3D.swc Flex library, located in the bin directory, that can be used with other Away3D projects that you create afterwards. Similarly, with eclipse, you can compile Away3D projects by linking directly to this project. Personally I prefer the second method simply because it makes developing and debugging easier as you can directly look at the source for a particular Away3D class.

Hope this is of some use. I’ll be taking a look, as I did with Papervision3D, at producing a few simple examples just to get a feel of the library… more soon I hope!

-->
Sunday, July 27th, 2008

Downloading and compiling Papervision3D v2.0 (Great White) sources with SVN in Eclipse

In this post I aim to show you how to download the Papervision3D v2.0 (codenamed Great White) sources from their Subversion repository within Eclipse and compile them as an Actionscript 3 library.

For this I’m assuming that you have the Flex Builder 3 plugin installed (see a previous post on using this plugin with Eclipse 3.4) and, if you need to, read my last post on installing the SVN plugin (Subversive) in eclipse. Another source of information can be found on the Papervision3D FAQ.

In Eclipse, select Import… from the File menu item


From the popup that appears, select Projects from SVN in the SVN node of the tree - thanks to the Subversive Eclipse plugin - and click Next.

You’ll then be requested information on the SVN repository. We need to create a new one for the the Papervision3D source so select the Create a new repository location radio button and click Next.


In the following window we need to enter information about the Papervision3D respository location. Enter http://papervision3d.googlecode.com/svn/ in the text field next to the URL: label and click Next. Note that the URL given on the Papervision3D FAQ is http://papervision3d.googlecode.com/svn/trunk/. Eclipse automatically searches for the trunk directory, as you can see if you click on the Advanced settings tab, so we don’t need to give it here.

Eclipse then searches for the repository and provides a listing of available directories. You can browse through the trunk branches and you’ll see that there is the Great White branch as well as the previous version of Papervision3D (v1.5 ?) shown here for Actionscript 3. Select GreatWhite and click on Finish.

Eclipse starts to scan the repository and then requests how you would like to check out the project. Select Check out as a project configured using the New Project Wizard and click on Finish.

In the New Project wizard select Flex Library Project from the Flex Builder tree node and click Next.

Enter the name of the project you’d like to create - for example Papervision3D as I show below and click Next to set up the main source directory.


Enter src in the field next to the Main source folder label and select the radio button next to src under Classes to include in the library then click on Finish.

Eclipse will then start to check out the Great White branch from the Papervision3D repository and place them in a new project which can take several minutes. You should then see the new project in the Flex Navigator.


If, like me, you see the error message nothing was specified to be included in the library, then simply right-click on the project, select Properties and select Flex Library Build Path from the menu and click on the check box next to src under Classes to include in the library and click on OK.

You’ll see at the bottom right of the Eclipse window that it starts to compile the sources and when its finished if you open up the bin directory of the project in the Navigator you’ll see a newly created libary file called Papervision3D.swc that you can use in your Papervision3D projects (or otherwise link your other projects to the Papervision3D one when you configure them).


Also included in the import are some examples of using Papervision3D v2.0. These are useful to get started on Papervision3D projects. Similarly useful is to perform the same procedure as above and check out the previous version of Papervision3D (check out from a different branch from the repository as shown above when importing an SVN project). The API has changed quite a lot, but not completely. There are a lot of useful examples showing the different features. The source code is also well documented and its useful exploring the different Actionscript classes.

Anyway, I hope to provide some simple, concrete examples of using Papervision3D in the near future. In the meantime I hope this has provided a useful step in obtaining the source code using SVN in Eclipse (*) and please let me know if there’s anything missing.

(* by the way, I presume the same steps in installing SVN and obtaining the Papervision3D source code can be performed directly within the Flex Builder 3 application since it uses the Eclipse architecture - it’d be useful to know if you’ve tried it)

Sunday, July 27th, 2008

Installing Subversion (SVN) plugin for Eclipse

To download Papervision3D v2.0 (Great White) we need to have Subversion (SVN) installed (see the pv3d wiki). I’ve seen a number of posts on the web doing this using a separate SVN client (for example using TortoiseSVN in Windows, (shown here in a YouTube video tutorial), and svnX for the Mac). However, I’m a fan of Eclipse and have not come across a CVS client that works as well as that which is included with Eclipse so wanted to see how well SVN plugin compared. Plus with Eclipse being multi-platform I can move from Mac to Linux to Windows and have exactly the same interface for all of them - I guess my motto is be lazy because I’d really rather not repeat the same tasks using different applications wherever I go. What’s more, I use the Flex Builder 3 plugin for Eclipse and, as with my other projects, like to have the version control integrated into my development environment. For SVN, we need to install the Subversive plugin for eclipse.

To integrate SVN into eclipse I simply followed the instructions given on the Subversive download page. Before using the Subversive plugin we need to however download the SVN Connectors. The following illustrates how to do this using Eclipse Software Updates.

In Eclipse, selected the Help menu item, then Software updates… Click on the Available Software tab.

We first need to install the SVN Connectors that are available from polarion.com, from where the Subversive plugin originates. Click on Add Site… and type the following address : http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/

When you click OK you’ll see a new list of components available for installation.

Click on the check box next to the polarion to select all the components and then click on Install…

NOTE : If you’re using a Mac you must deselect both the JavaHL Win32 Binaries otherwise there are unresolved conflicts when it comes to installing the Subversive plugin.

You should now be presented with a summary of all the components to be installed.

Click Next and accept the terms of the license agreement. The components are then downloaded and installed. You’ll then be asked whether you want to restart eclipse - its probably a good idea to do this.

When Eclipse restarts we need to go through the same procedure to install the Subversive plugin. As before, select Software Updates… from the Help menu item and then click on Add Site… Now type the address of the Eclipse Subversive update site : http://download.eclipse.org/technology/subversive/0.7/update-site/

Click OK and select the newly proposed components for Subversion :

Click on Install… and you’ll get a summary of the new components to install.

Click Next and agree to the terms of the license agreement and Eclipse will start to download and install the Subversion plugin. As for the SVN Connectors, restart Eclipse when prompted.

And that’s it ! You should now have SVN fully working within Eclipse. Just to check, if you select
Import… from the File menu item you should have the possibility of importing a project from SVN.

So now that we have Subversive up and running in Eclipse, we can now move onto the main objective of installing Papervision3D v2.0 (Great White) from its SVN repository.

Sunday, July 27th, 2008

Installing Flex Builder 3 plugin with Eclipse 3.4 (Ganymede)

At the time of writing, the Adobe Flex Builder 3 plugin is not compatible with Eclipse 3.4 (Ganymede). Flex Builder requires a version 3.3 of Eclipse during its installation and will report an error when you point it to a 3.4 version. However you can force it to continue with the installation and then install a patch, available with thanks to Tekool.net. For the patch to work fully you need to cleanly restart Eclipse (as mentioned in the comments on the linked post) :

eclipse -clean (on windows, or)
./eclipse -clean (on mac/linux)

This is needed only once - after this the plugin works fine with the latest version of Eclipse.