Tom Krcha's FlashRealtime

Hey amigo!
I am Tom Krcha, Gaming Evangelist at Adobe. These are my notes


HOWTO: Transfer Custom Object - C Native Extensions in AIR

February 16th, 2012

Sometimes you want to transfer custom objects instead of predefined ones (or basic types). This is very useful, for example, when you want to construct for instance an array of positions. Position is in this case defined by an object with x, y, z properties.

Let’s initiate an Array instance. I wrote a tutorial about that here HOWTO: Transfer Array and Vector from AS3 to C with AIR Native Extensions for iOS:

uint32_t arr_len = 10; // count of positions
FREObject objectsPosition = NULL;
FRENewObject((const uint8_t*)"Array", 0, NULL, &objectsPosition, NULL);
FRESetArrayLength(objectsPosition, arr_len);

Next we will define a custom Object, basically the same way as we did with the Array

// loop through array length and fill it with data
for(uint32_t i=0;i<arr_len;i++){
 
FREObject position;
// create an instance of Object and save it to FREObject position
FRENewObject((const uint8_t*)"Object", 0, NULL, &position,NULL);
 
// populate temporary vars x, y, z
FREObject xPos;
FREObject yPos;
FREObject zPos;
FRENewObjectFromInt32(10, &xPos);
FRENewObjectFromInt32(20, &yPos);
FRENewObjectFromDouble(30, &zPos);
 
// fill properties of FREObject position
FRESetObjectProperty(position, (const uint8_t*)"x", zPos, NULL);
FRESetObjectProperty(position, (const uint8_t*)"y", yPos, NULL);
FRESetObjectProperty(position, (const uint8_t*)"z", zPos, NULL);
 
// add position to the array
FRESetArrayElementAt(objectsPosition, i, position);
}

Done. Have fun.

Love case - Valentine’s day app in Adobe AIR

February 14th, 2012

Check this pretty app by Silicon Jelly from Prague.

Fill the full name and the birth date of you and your companion and hit the buttons.

Download:
iOS: http://itunes.apple.com/us/app/love-case/id500708508
Android: https://market.android.com/details?id=com.siliconjelly.lovebox

Trailer:

HOWTO: Transfer Array and Vector from AS3 to C with AIR Native Extensions for iOS

February 8th, 2012

Last time I wrote about casting basic types from AS3 to C like Number, String, Boolean, int and uint. Now I’d like to cover two more complex types: Array and Vector.<Type>.

Array cast (AS3->C->AS3) reverse function

In this little sample, we will implement reverse function, that basically gets array like [1,2,3] and returns [3,2,1].

AS3 part:

public function reverseArray(array:Array):Array{
	var ret:Array= context.call("reverseArray",array) as Array;
	return ret;
}

C part:

This function consist of few steps, first get an array from argument, find length, create new AS3 Array instance in C, loop through original array + fill new array and return it.

FREObject reverseArray(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    FREObject arr = argv[0]; // array
    uint32_t arr_len; // array length
 
    FREGetArrayLength(arr, &arr_len);
 
    FREObject populatedArray = NULL;
    // Create a new AS3 Array, pass 0 arguments to the constructor (and no arguments values = NULL)
    FRENewObject((const uint8_t*)"Array", 0, NULL, &populatedArray, nil);
 
    FRESetArrayLength(populatedArray, arr_len);
 
    NSLog(@"Going through the array: %d",arr_len);
 
    int32_t j = 0;
    for(int32_t i=arr_len-1; i>=0;i--){
 
        // get an element at index
        FREObject element;
        FREGetArrayElementAt(arr, i, &element);
 
        // OPTIONAL: get an int value out of the element
        int32_t value;
        FREGetObjectAsInt32(element, &value);
 
        // log index and value
        NSLog(@"Get item %d: %d",i,value);
 
        NSLog(@"Set item %d: %d",j,value);
        FRESetArrayElementAt(populatedArray, j, element);
        j++;
    }
 
    return populatedArray;
}

Vector.<Type> (AS3->C->AS3) reverse function

Same thing applies for Vector.<Type>, the only difference is that the creation of the Vector.<Type> will look like this:

FRENewObject((const uint8_t*)"Vector.<int>", 0, NULL, &populatedArray, nil);

The implementation will look like this:

public function reverseVector(vector:Vector.<int>):Vector.<int>{
	var ret:Vector.<int>= context.call("reverseVector",vector) as Vector.<int>;
	return ret;
}
FREObject reverseVector(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
 
    FREObject arr = argv[0]; // array
    uint32_t arr_len; // array length
 
    FREGetArrayLength(arr, &arr_len);
 
    FREObject populatedVector = NULL;
    // Create a new AS3 Array, pass 0 arguments to the constructor (and no arguments values = NULL)
    FRENewObject((const uint8_t*)"Vector.<int>", 0, NULL, &populatedVector, nil);
 
    FRESetArrayLength(populatedVector, arr_len);
 
    NSLog(@"Going through the vector: %d",arr_len);
 
    int32_t j = 0;
    for(int32_t i=arr_len-1; i>=0;i--){
 
        // get an element at index
        FREObject element;
        FREGetArrayElementAt(arr, i, &element);
 
        // OPTIONAL: get an int value out of the element
        int32_t value;
        FREGetObjectAsInt32(element, &value);
 
        // log index and value
        NSLog(@"Get item %d: %d",i,value);
 
        NSLog(@"Set item %d: %d",j,value);
        FRESetArrayElementAt(populatedVector, j, element);
        j++;
    }
 
    return populatedVector;   
}

Complete C implementation: IOSExtension.m
Complete AS3 implementation: IOSExtension.as

HOWTO: Transfer Number, String, int/uint and Boolean with AIR Native Extensions for iOS back and forth

February 7th, 2012

Casting basic types from ActionScript 3 to C

Your probably first and immediate question when programming ANE for iOS is: “How to transfer data from AS3 to C and back to AS3?”. Once you break through this essential stage you enter the world of endless possibilities in Adobe AIR with native extensions.

There has been already plenty of articles on how to begin writing your native extensions, I am not going to explain that, just share the source code needed for that.
I am using Adobe Flash Builder 4.6 with ANE support for AS3 and Apple Xcode for coding the C part + packaging the static library (*.a file).
But let me quickly remind you the workflow. You need 3 projects, one is Flex Library project in FB (AS3 interface for C as *.swc), second is native library in Xcode (C interface and implementation as static library *.a), third is the actual test project in FB to run the native extension (*.ane).

Fig: Native Extension Creation Process

In this tutorial I want to illustrate how to transfer some basic types like Number, String, int/uint and Boolean from AS3 to C, process them and return back to AS3. In the next tutorial, we will look into more complex data types like Array, ByteArray and BitmapData.
*UPDATE: Casting Array and Vector from AS3 to C

Good starting point: Native C API Reference for Adobe AIR extensions. There is also a good page Coding native side with C for AIR.

But there is nothing better than samples. Let’s dig into some real code:

Number (AS3->C->AS3) Sum function

AS3 part:

public function sum(number1:Number,number2:Number):Number{
       // call C function sum with 2 arguments, number 1 and number2 and return a value
	var ret:Number = context.call("sum",number1,number2) as Number;
	return ret;
}

C part:

FREObject sum(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    // argc ... argument count, uint
    // argv ... argument values, Array
 
    // retrieve first argument and write it to a variable
    double number1;
    FREGetObjectAsDouble(argv[0], &number1);
 
    // retrieve second argument and write it to a variable
    double number2;
    FREGetObjectAsDouble(argv[1], &number2);
 
    // add first and second number together
    double sum = number1 + number2;
 
    // write computed sum to FREObject that will be returned back to AS3
    FREObject sumToReturn = nil;
    FRENewObjectFromDouble(sum, &sumToReturn);
 
    return sumToReturn;
}

int (AS3->C->AS3) Subtract function

AS3 part:

public function subtract(int1:int,int2:int):int{
	var ret:Number = context.call("subtract",int1,int2) as int;
	return ret;
}

C part:

FREObject subtract(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    int32_t int1;
    FREGetObjectAsInt32(argv[0], &int1);
 
    int32_t int2;
    FREGetObjectAsInt32(argv[1], &int2);
 
    int32_t sum = int1 - int2;
 
    NSLog(@"%d-%d=%d",int1,int2,sum);
 
    FREObject sumToReturn = nil;
    FRENewObjectFromInt32(sum, &sumToReturn);
 
    return sumToReturn;
}

uint (AS3->C->AS3) Multiply function

AS3 part:

public function multiply(uint1:uint,uint2:uint):uint{
	var ret:Number = context.call("multiply",uint1,uint2) as uint;
	return ret;
}

C part:

FREObject multiply(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    uint32_t uint1;
    FREGetObjectAsUint32(argv[0], &uint1);
 
    uint32_t uint2;
    FREGetObjectAsUint32(argv[1], &uint2);
 
    uint32_t sum = uint1*uint2;
 
    NSLog(@"%d*%d=%d",uint1,uint2,sum);
 
    FREObject sumToReturn = nil;
    FRENewObjectFromUint32(sum, &sumToReturn);
 
    return sumToReturn;
}

String (AS3->C->AS3) Concatenate function

AS3 part:

public function concatenate(str1:String,str2:String):String{
	var ret:String = context.call("concatenate",str1,str2) as String;
	return ret;
}

C/Obj-C part:
// in this sample I wanted to go even further and utilize Obj-C function for concatenating strings and also demonstrate how to pass strings between C and Obj-C

FREObject concatenate(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    // To be filled
    uint32_t string1Length;
    const uint8_t *string1;
    FREGetObjectAsUTF8(argv[0], &string1Length, &string1);
 
    uint32_t string2Length;
    const uint8_t *string2;
    FREGetObjectAsUTF8(argv[1], &string2Length, &string2);
 
    // Convert C strings to Obj-C strings
    NSString *string1ObjC = [NSString stringWithUTF8String:(char*)string1];
    NSString *string2ObjC = [NSString stringWithUTF8String:(char*)string2];
 
    // Concat strings
    NSString *returnString = [string1ObjC stringByAppendingString:string2ObjC];
 
    // Convert Obj-C string to C UTF8String
    const char *str = [returnString UTF8String];
 
    // Prepare for AS3
    FREObject retStr;
	FRENewObjectFromUTF8(strlen(str)+1, (const uint8_t*)str, &retStr);
 
    // Return data back to ActionScript
	return retStr;
}

Boolean (AS3->C->AS3) Opposite function

AS3 part:

public function opposite(bool:Boolean):Boolean{
	var ret:Boolean = context.call("opposite",bool) as Boolean;
	return ret;
}

C part:

FREObject opposite(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    uint32_t boolean;
    FREGetObjectAsBool(argv[0], &boolean);
 
    uint32_t oppositeValue = !boolean;
 
    FREObject retBool = nil;
    FRENewObjectFromBool(oppositeValue, &retBool);
 
    return retBool;   
}

Full C-part source code: IOSExtension.m
Download whole C-project for Xcode

Complete AS3 SWC lib part: IOSExtension.as

Test project source (SWF/IPA): IOSExtensionTest.as

For compiling native extension (*.ane) I use this command in Terminal.app.

compileExtension.sh file/script

unzip -o IOSExtension.swc
 
/PATH/TO/FLEX_AIR_SDK/bin/adt -package -target ane IOSExtension.ane extension.xml -swc IOSExtension.swc -platform iPhone-ARM library.swf libIOSExtension.a

extension.xml looks like this:

<extension xmlns="http://ns.adobe.com/air/extension/2.5">
    <id>com.krcha.IOSExtension</id>
    <versionNumber>1</versionNumber>
    <platforms>
      <platform name="iPhone-ARM">
        <applicationDeployment>
          <nativeLibrary>libIOSExtension.a</nativeLibrary>
          <initializer>ADBEExtInitializer</initializer>
          <finalizer>ADBEExtFinalizer</finalizer>
        </applicationDeployment>
      </platform>
    </platforms>
</extension>

HOWTO: Join multiple SWF files into one with AIR for iOS

February 3rd, 2012

A while back, I promised to write some of the backstage tips that made it possible for Machinarium (1 GB sources!, 28 SWFs!) to run on an iPad with AIR, which requires only a single SWF.

One of the issues you run into is how to join/concatenate 28 SWFs into single SWF. I wrote an article about using SWC libraries for that here Compiling big Flash/AIR projects with lot of SWFs for iOS. This sometimes works, but very often the workflow is more complex and you want to keep the same SWF files for Android and iOS and use them at least in a bit similar way. On Android you can however load SWF files at the runtime and this is very effective for the memory usage. On iOS you have to watch this, especially when you have everything in a single SWF. So, ideally you place all assets into separate files and load them and dispose them on-demand. But that’s more of a general problem you should keep in mind - every asset that doesn’t contain AS3 (pictures, videos, music), put aside. But back to the topic.

Now comes the magic by David ‘Oldes’ Oliva (the lead developer of Machinarium) from Amanita Design, who made it all possible and wrote a script which can be used for joining SWFs together.

Note: This solution allows you to use multiple SWF files containing AS3 script and logic in each of them, not only for assets. That’s why it’s so powerful.

*prerequisite: you’ll need to understand how to work with the command-line on Mac or Windows.

Steps:

1) Prepare SWFs like you were using them the standard way, but instead of loading them dynamically via the Loader class, SWFLoader or a similar mechanism, each SWF has to be Class (or contain at least one, can contain more), which you can instantiate. That’s because once you join all SWFs together, you will be instantiating it’s contents, not loading.

2) Download the samples package rswf-join-example.7z (for unzipping use 7-zip compatible tool) / UPDATE: the file has been updated to support bitmap reduction

3) Download the REBOL script view environment http://www.rebol.com/download-view.html

Using the tool:

4) Navigate to the samples folder. There are three scripts that you might want adjust to fit your workflow:

compile-and-run.r
- this is the rebol script that does part of the job and runs Game.bat

Game.bat
- here you want to adjust the path to your Flex/AIR SDK so it points to the adl command

cd ./public/
/path/to/AIR_SDK/bin/adl Game.xml

Game.rswf
- here you specify the SWFs you want to compile together, in the samples, you can see FLAs and it’s content to understand how to prepare your own workflow.

5) Run the compilation (of course change the path to rebol to the directory, where you have downloaded it or stored it)

/path/to/REBOL/rebol compile-and-run.r

*At this point, if you get permission denied on some of the files, make sure all the processing files have the proper rights; you can set the rights using chmod, for instance:

chmod 777 filename.bat

also 777 is pretty open rule, so consider 755 or 775 or similar.

6) Once the compilation is done, the SWF will open and you can successfully use it with adt command from the Flex/AIR SDK to compile the final IPA for iOS.

If you have any questions, please ask in the comments.

Good luck!