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!