Email Updates RSS Subscribe
Line

This blog is created and maintained by the technical team at Hook in an effort to preserve and share the insights and experience gained during the research and testing phases of our development process. Often, much of this information is lost or hidden once a project is completed. These articles aim to revisit, expand and/or review the concepts that seem worth exploring further. The site also serves as a platform for releasing tools developed internally to help streamline ad development.

Launch
Line

Hook is a digital production company that develops interactive content for industry leading agencies and their brands. For more information visit www.byhook.com.

Line

Alchemy Series Part 5: Revenge of the Thiz

Line
Posted on March 23rd, 2011 by Jake
Line

This episode is a bit of a catch all for some other random things that we wanted to cover in this series. The hope is, by the time you are done reading this post (along with the last 4) you will be able to start build swcs of other libraries, or even creating your own directly in C. If this ends up being the case, please let us know, we would love to see what you guys make! Anywho, on with the show…

For any of this to make sense, you will probably want to follow along with the code in the example which you can download here:
Example Source

Multiple File Compilation and Linking
While doing my own research on Alchemy, I came across many a forum post asking about compiling and linking C libraries that were comprised of multiple files, as most are. So this week’s example has been split up into multiple files to try and demonstrate the process. In the alchemy folder bundled with the example code, this is a folder called “lib”. In there is a couple of C files and a few Bash scripts. For the purpose of this example, we are going to consider this our Library. In order get our library compiled and ready to link with our Alchemy wrapper we have to complete a few intermediate steps.

The first step is to compile each of the .c files individually and create .o (object) files from them. These object files are what is linked together in the end to create the swc. Since most C libraries out there have lots of files, its probabaly most convenient to create a bash script to handle the compile. In our case its the “compilelib.sh” file.

#!/bin/bash
optLevel=3
 
gcc -I../include -I./ -Wall -O$optLevel -c loopstart.c
gcc -I../include -I./ -Wall -O$optLevel -c cancelstate.c

The first line should look familiar to you from previous posts, but just in case you missed it, it simply tells cygwin to interpret this script with the “bash” shell located at “/bin/bash”. Next we create a variable to make it easy to alter some compile settings without having to edit each line individually. Then we have the now familiar “gcc” calls. The “-I” switches tell gcc to add these folders to its search path when looking for files and definitions, such as (.h) header files. In this case we are telling it to look in the “include” folder one level up, and to also look in its own folder. The “include” folder has our “alcexample.h” file which contains the declarations for our library functions and data structures. The -Wall tells gcc to report all types of warnings while compiling. -O is the compiler optimization setting. At one point I thought the optimization was messing with Alchemy, I was wrong. But I figured it would be good to suggest leaving the variable in there as an example. You could probably do the whole include bit with a var too. Lastly “-c” tells gcc to not run the linker, and just save out the object file. Once those files have been compiled into object files, we need to archive the library together into one file. Thus the “arclib.sh” script:

#!/bin/bash
ar csr exampleLib.a loopstart.o cancelstate.o

To build the archive we use the “ar” program. The command line settings break down like this:
c – create the archive
s – this creates an object file index in the archive which “allows routines in the library to call each other without regard to their placement in the archive” (from ranlib docs)
r – inserts the object file into the archive and replaces duplicates instead of appending

Lastly we feed it the name we want the archive to be called and a list of object files we want included.

At this point we have the library built and archived ready for use in our Alchemy wrapper. So if you pop up one folder level you will see our main Alchemy file, alcexample.c, as well as another Bash script that will finish our build called “compileandlink.sh”:

#!/bin/bash
gcc -I./include -L./lib -lexampleLib -Wall alcexample.c -swc -O3 -o alcexample.swc

This looks very similar to our “compilelib.sh” script, with a couple of notable exceptions. This time we are using the “-L” switch to add a library path to the gcc search path. We then follow that with a “-l” switch and the name of our library. The “-c” has also been replaced by a “-o” and a “-swc”. Which means that gcc will now link the project and create your brand new .swc file :)

So, basically the moral of the story is to build a multi-file library, it takes three steps:
1) Basic library compile to object files
2) Archiving of the .o files to a single archive file (with indicies)
3) Final compile and link

Great, now that we can compile the example, lets jump back into looking at code.

Bound States
So a few posts ago, I had mentioned that the first parameter for the AS3_Function() call was usually NULL, and I at the time didn’t know why. Well, its been figured out :) You can replace this NULL with a pointer to some data of whatever kind you like. This can be a handy shortcut so you don’t have to continuously pass in the pointer address from flash to your function calls when you want to access data within the C code. If you take a look at the alcexample.c file and head down to main(), you will see it looks much like the rest of the examples. However instead of passing NULL into our AS3_Functions we are now passing a pointer to a struct.

typedef struct
{//LoopState
unsigned int totalLoops;
int isCancelled;
} LoopState;
//Setup main state
LoopState *mainState = initState();
mainState->isCancelled = 1;
mainState->totalLoops = 0;
 
//Virtual Function (thunk) mappings
AS3_Val setCancelStateMethod = AS3_Function(mainState, setCancelState);
AS3_Val startStateLoopMethod = AS3_FunctionAsync(mainState, startStateLoop);
AS3_Val cleanUpMethod = AS3_Function(mainState, cleanUp);

The struct itself is defined in the “alcexample.h” file, and simply included into the “alcexample.c” file. Its a fairly basic structure that simply has two members, totalLoops, and isCancelled. In main() we essentially “new up” an instance of that struct (really just allocate some memory for it) by calling initState() which basically does this:

LoopState *state = (LoopState*)malloc(sizeof(LoopState));
return (unsigned int)state;

This is a bit of a spin on what we did in the last post. Since we aren’t going to report this memory address back to Flash, we can return the pointer to the LoopState instance directly. This way we won’t have to resolve the pointer from the memory address every time we want to use it, since its already a pointer.

After we malloc some space, and grab the pointer to it, we set up some default values in the struct. We set isCancelled to 1 (which we will signify “true”) and set the totalLoops count to 0.

With our state all set up, we can pass that pointer in to our thunks. Which means that the C functions mapped in those thunks will be fed that pointer as its first argument. So now we don’t need to pass the pointer to that data in every time. It just gets bound to the thunk and we get access to it at all times in the functions. This is great for convenience, but you do give up flexibility for it. You won’t be able to change what pointer is bound to the thunk, so if you want to be able to access different data every time you call the function, you will need to pass in your own pointer, or a memory address that can be used to get the pointer, which is what we did for the imageData struct in the last post.

Lets take a look at the setCancelState() function in the cancelState.c file as an example of how to use this “state” data.

//Get loop state from data passed in
LoopState *state = (LoopState*)data;
 
//Vars to store passed in cancel state
int cancelState;
 
//Parse args for cancel state
AS3_ArrayValue(args, "IntType", &cancelState);
 
//Set new cancel state
state->isCancelled = cancelState;
 
//Debug print
fprintf(stderr, "Cancel State: %i", state->isCancelled);
 
return AS3_Null();

The first thing we do is cast and save the “data” argument into the “state” variable. This is mainly for convenience. Next we parse out the arguments passed in from flash, which in this case is either a 1 or a 0 and save that in “cancelState”. Finally we set the “isCancelled” member of state to be whatever was passed in from flash. Pretty straight forward. All of the other functions work in the same fashion with regard to getting access to the LoopState structure. When calling this function from Flash it looks like this:

//Cancel Loop by setting the LoopState->isCancelled to 1 (true)
_lib.setCancelState(1);

Async and the Thiz
The last major “feature”, if you will, in this example, is the use of the AS3_FunctionAsync(). This will allow you to set an ActionScript callback that will be called when the function finishes. Back in main() you will see the thunk definition for this:

AS3_Val startStateLoopMethod = AS3_FunctionAsync(mainState, startStateLoop);

From ActionScript the call looks like this:

//Call async function
_lib.startStateLoop(handleLoopComplete, this);

This means that when startStateLoop() completes, handleLoopComplete will be called in ActionScript. Unfortunately, that is all this means. I know what you’re thinking, “The function will run in its own thread! Finally multi-threaded flash!” Sadly, this is not the case. Then you ask “So why even make a separate Function type if it simply plays out like every other function?” The answer to that is in flyield(). This is a magical function in Alchemy that will “pause” alchemy and give up its timeslice back to Flash. This means that every time you call flyield(), flash gets to execute for another tick. Then Alchemy will execute some more until flyield() is called again. So even though its not really multi-threaded, you can let your C code churn on some data for a while without locking up your swf and its UI. This is useful for instance if you are encoding sound data or some other cpu intesive task. This way you can throw up a progress indicator of some kind and its visuals can be updated while the C code is doing its thing. A quick thing to note, is that your UI will be locked up while the C code is doing something, it will only get updated when flyield() is called. Which means that the longer you wait to call flyield() the longer the UI is unresponsive. If this is less than the time it takes to render a frame, then no one will notice. This means that you will probably need to do some experimentation on your target hardware to determine how much processing you can do in C before giving it up to Flash. The downside is that while Flash is doing stuff, your C code is not. Which means that the more often you yield to flash, the slower your number crunching in C happens.

Now, I mentioned progress bars, and initially you probably just skimmed over that without any other thoughts, but there is an issue there. If your C code is running in a timeslice, how exactly do you get the “progress” of the number crunching back to flash to display? If you pop open loopstart.c we can take a look.

The first clue is in the argument parsing. Besides the void *data argument, there is the other AS3_Val that gets passed in. This gets stored in the AS3_Val clientObj variable.

//var to hold a reference to the Thiz
AS3_Val clientObj;
 
//Parse passed in arguments and get ref to Thiz
AS3_ArrayValue(args, "AS3ValType", &clientObj);

If you’ll notice, from ActionScript we make this call

//Call async function
_lib.startStateLoop(handleLoopComplete, this);

Notice the “this”? That is an actionScript reference to an actionScript object. When that is brought into C and converted to an Alchemy Data Type, its called a “Thiz”. A thiz is essentially a virtual object much like a tunk is a virtual function, which is not to be confused with a C++ virtual function. Now that we have this thiz we can do some cool things directly to our running Flash code. In our case we are going to update the flash code with the current progress of our C code.

//Build an array of parameters to pass to the ActionScript
//Method call
AS3_Val params = AS3_Array("IntType", state->totalLoops);
 
//Call method on Thiz
AS3_CallS("updateFromAlc", clientObj, params);

The AS3_CallS() takes three arguments, a const char* (C string) of the name of the method you want to call, the thiz you want to call the method on, and a list of params to pass to the method you are calling. In our case, all we are passing is the totalLoop count from the LoopState. In actionScript our updateFromAlc() method looks like this:

public function updateFromAlc($totalLoops:int):void
{//updateFromAlc
	//Update the UI (happens during a yield)
	_textView.numLoopsText.text = $totalLoops.toString();
}//updateFromAlc

As you can see the method is expecting an integer to be passed to it, and it gets that from the state->totalLoops member from the C code. So now we have full communication from the C code to Flash, and also from Flash to the C code. Its worth mentioning that if you check out the Alchemy docs you will see you can also get and set properties on ActionScript objects that are passed in to the C functions.

Async Cancellation
There is one final interesting bit to this example. If you check out the while loop in the startStateLoop() method, you will see this:

while(state->isCancelled == 0)

This essentially means that the loop is going to keep running until something changes in the LoopState data. Specifically when isCancelled becomes non-zero. If you think about it a bit, it at first seems impossible to change that state data while the loop is running. However, as it turns out, during a flyield() you can actually call other functions on the C code while Flash has control! Crazy right? So in the Alchemy C code, the execution pointer is sitting at the flyield() call. Flash gets its time slice, and then calls another function, in our case setCancelState(1), and changes the state data. On the next tick, the Alchemy Code gets its next time slice and then continues on from original point of execution, one line after the flyield() call. Now, the next time through the loop, state->isCancelled is now 1, and the loop exits. Execution continues to the bottom of the function where the total number of loops is returned. When this return is hit, guess what is called… our ActionScript method handleLoopComplete(), and to it is passed the total number of loops. Yay! This means we have full control of our C based async functions directly from Flash! I mean what else can you ask for from a single threaded virtual machine? :)

Fin
Welp, that about wraps it up. There will probably be one more post in this series, but it won’t be so much of a tutorial as a information on our Ogg Vorbis library :) So for those of you following along at home, thanks for reading about our Alchemy Adventures! As always, if you get around to making something cool with any of this info, let us know, we would love to see it!

Also remember to like us on Facebook if you want to stay updated, or even just to show your support:

And/Or you can follow me on Twitter:
Follow JakeCallery on Twitter

Line
5 Responses to “Alchemy Series Part 5: Revenge of the Thiz”
  1. The last two examples achieve the same result; calling the function through a pointer. Using the syntax provided from the last example helps to better document the code so that a programmer can see that the function is in fact being invoked through a pointer.

  2. >plz explain me with syntax “how to pass pointer to a function or pointers to a function ” For each level of indirection in the function argument list, add an asterisk. If the argument isn’t already a pointer of the same type as the argument list, dereference or add & as necessary.

  3. Damon Gogul says:

    Hi,
    I am wondering how much experimentation you did with C++ (not just C)?
    I know there are a few bugs with alchemy and C++, and I am not sure if using alchemy to convert a huge C++ program into a flash object is still a good idea.

  4. Jake says:

    @Matthieu Labas, you are very welcome, we are glad someone is finding this stuff useful :) If you are looking into multicast stuff you might want to check out the new netgroup stuff and the other P2P flash classes for using rtmfp, such as: http://www.flashrealtime.com/videotutorial-remote-device-controller/ or http://www.flashrealtime.com/local-flash-peer-to-peer-communication-over-lan-without-cirrus/

    Good luck, and thanks again for the kind words!

  5. Thanks A LOT for all these info about Alchemy, this is just the Gold Mine I’ve been looking for! I wish Adobe had such tutorial (or this directly linked on the official Alchemy page ;) ).

    You just saved me a month of research! :)

    I was willing to implement IP multicast for Flash on UDP sockets (I already did a lot of C code for that) but it won’t create the socket. Too bad…

    Anyway, great deal of info here, thanks again and keep up the good work! :)

    Matthieu


Leave a Reply

*

Line
Line
Pony