Samples
Contained within the samples folder are several samples demonstrating how to use Crossbridge. Techniques and functionality are introduced gradually so it's worth following them in ascending order. As well as the samples there are also several fully working examples that use real open source applications and code.
- Hello World - as simple as it sounds.
- Interop - shows basic interop with AS3 APIs from C, and more advanced C++ interop using the Flash++ API.
- Drawing - building on the interop sample this shows how to draw to the stage.
- Animation - creating a runloop involves writing a custom Console.as.
- SWC - how to manually expose some C++ functions to AS3 in a SWC.
- SWIG - how to use SWIG to automatically generate the wrapper code needed for a SWC.
- Filesystem - how to package up local files into a virtual filesystem that can be embedded within a SWF and accessed using normal libc file IO.
- GDB - A simple C program that demonstrates how you can debug it running in the Flash Player using GDB.
- Pthreads - Shared memory multi-threading is available in Flash Player 11.5. This app shows how you can spawn a thread but still interact with the Flash display list from that thread using the helpers in AS3++.h.
- MessageChannel - This Flash API lets you communicate easily between Flash workers including serializing and sending ActionScript objects between threads.
- OpenMP - This library includes many constructs to make it easier to write multi-threaded code in C/C++. This example shows how you can use its constructs to automatically parallelize a simple mandelbrot fractal rendering app. Clicking on the swf adds more threads into the threadpool.
- Stage3D - This simple example shows how to use the Flash++ interop to talk directly to the Stage3D API in Flash Player to render to the GPU.
Working Examples:
https://github.com/crossbridge-communityBuilding the samples
Each sample comes with a makefile, and there is a makefile in the root samples folder that will build all of the samples. The makefile needs to be told where your Crossbridge SDK is located and also where your Flex SDK is located. The samples should be compiled with Flex SDK 4.6 or higher:
Mac> make FLASCC=~/flascc/sdk FLEX=/path/to/flexsdk Win> make FLASCC=/cygdrive/c/flascc/sdk FLEX=/cygdrive/c/path/to/flexsdk
Sample 1: Hello World
This is a simple, traditional, Hello World example, that you use to ensure you can compile and have the correct paths to the Crossbridge and Flex SDK. Open hello.c and you'll find a standard hello world example containing a main function that uses printf
to display the string "Hello World".
The makefile invokes gcc twice, once to produce a projector binary and again to produce a SWF. A projector binary is a native executable that contains both the ActionScript VM and the compiled ActionScript byte code (ABC).
Here is an example of the output when making on Windows:
user@WINMACHINE /cygdrive/c/flascc/samples/01_HelloWorld $ make FLEX=/cygdrive/c/path/to/flexsdk FLASCC=/cygdrive/c/flascc/sdk -------- Sample 1 -------- First let's compile it as a projector: "/cygdrive/c/flascc/sdk/usr/bin/gcc" -Werror -Wno-write-strings -Wno-trigraphs hello.c -o hello.exe Now lets compile it as a SWF: "/cygdrive/c/flascc/sdk/usr/bin/gcc" -Werror -Wno-write-strings -Wno-trigraphs hello.c -emit-swf -swf-size=200x200 -o hello.swf
Sample 2: AS3 Interop
Basic Interop
Like the previous example this sample just has one main function. But in addition to printf, this example shows how to interleave snippets of ActionScript code with your C/C++ code. You can pass variables from C/C++ into the ActionScript code, and ActionScript code can be used to update C/C++ variables.
Crossbridge uses GCC's inline asm syntax, which lets you write arbitrary ActionScript inside your C/C++ code. This allows for very easy interop between AS3 and C/C++.
For a complete guide to the asm statement and how it is used read the GCC documentation. These resources on extended asm and inline assembly may be useful.
Crossbridge converts each function or method in your C/C++ code into an AS3 function. This limits what AS3 you can put in an inline asm statement inside a function. You can't write an AS3 class declaration inside an inline asm statement inside a C/C++ function. You can, however, write a class declaration outside any C/C++ function.
For more information, see the code comments in hellointerop.c.
This sample also introduces the CModule helper class, which is linked into all Crossbridge code. CModule contains functions to read and write to the Crossbridge heap, invoke malloc/free and lookup and invoke symbols. The full CModule documentation can be found here.
Flash++ Interop
The Flash++ library makes it easy for C++ developers to interact with AS3 classes in the Flash Runtime. Flash++ exposes all of the Flash APIs as strongly typed C++ classes. The c++interop.cpp file demonstrates an example of how to use this library to draw a series of circles on the screen.
BitmapData example
Flash has a BitmapData
class that can be used in conjunction with the Bitmap
class to display RGBA bitmap data in the Flash display list. Flash++ makes it easy to efficiently copy data between a BitmapData
object and C memory.
The bitmapdata.cpp example starts by using Flash drawing primitives to render some vector graphics into a BitmapData
object. Whenever the user clicks on the screen the C++ code in mouseDownHandler
copies the RGBA data out of the BitmapData
object using the copyPixelsToByteArray
API, performs a transformation on the pixel data, and then copies it back to the BitmapData
object using the setPixels
API.
For maximum efficiency you could also keep a copy of the pixel data in C memory and then you would only need to copy the data once into the BitmapData
object to display it, although this would obviously require more memory.
Sample 3: Drawing

Building on the previous interop sample, this sample illustrates slightly more complex interop, which draws to the stage. This example consists of two cpp files, so review the makefile to see how this impacts invoking g++.
If you aren't familiar with Voronoi diagrams you can read more about them on Wikipedia, but this is not necessary for the sample. The actual implementation of the Voronoi diagram algorithm (VoronoiDiagramGenerator.*) was taken from http://www.skynet.ie/~sos/mapviewer/voronoi.php and hasn't been modified so it can safely be ignored. For the purposes of this sample you only need to look inside voronoi.cpp to review the Flash interop.
If you look at the code in voronoi.cpp you'll see a reference to a class called
Console
. The source code for this class is located in
sdk/usr/share/Console.as. The purpose of Console.as is to provide
implementations of various low level system calls that libc expects to be
available in its host environment.
Console.as also acts as the root sprite for your SWF and sets up the stage. The default
implementation that ships with Crossbridge puts a TextField
on the stage and redirects
any stdout or stderr messages into this TextField. For a real SWF/SWC you will most
likely want to replace this class completely. Replacing Console.as will be shown
in the next sample, but for this simple drawing example we just grab the
current instance of Console from its public static current
property and
draw some lines using its graphics object, as you would with any Sprite.
When compiled using the default SWF version of 18 Crossbridge will attempt to run the code in a background worker. But for this sample we are directly talking to the Stage object and attempting to draw on it which needs to be done in a certain way from a background thread. We will introduce more about threading in later tutorials, so for now this tutorial just specifies a SWF version of 17 in the Makefile so that the code is run synchronously on the main Flash thread.
Sample 4: Animation

The last sample showed how to inter-operate with the stage during main()
, but
what if you want to drive an animation from C++? Because AS3 is single threaded, you can't simply put a while(true)
loop in main as that would block the main
Flash player thread and block screen updates, input events, and sound.
Instead, you need to structure the code so that a small amount of work is done every frame. You can do this with either an Enter Frame handler or a timer. This sample replaces the default Console implementation with one that uses an Enter Frame handler to call a function.
Open up Console.as. First you'll notice a call to CModule.startAsync
in the
Console constructor; this is a helper method that invokes main. But before
main runs, code for all of the C++ static initializers will run. And when
main returns, C++ static destructors will be run. This is important to understand
because when using Crossbridge-compiled code as a library or driving an animation, main
must return without running these destructors. To prevent the destructors from running,
throw an AS3 exception at the very end of main. For an example, see main()
in
GameOfLife.cpp.
In GameOfLife.cpp, you will also see a function called updateUniverse
that is
marked extern "C"
. This prevents the C++ compiler from
mangling the name so that it is a easier to look up from Console
.
However, as you will see in the next sample, you can control
generated function names without using this technique.
Returning to Console.as, you will see a function called frameBufferBlit
that
is hooked up to an Enter Frame event listener. In this function the getPublicSymbol
helper is used to find the address of the updateUniverse
function,
which is then passed to the callFunI
helper along with any necessary arguments
(in this case the function needs no arguments).
In summary, to implement a simple run loop you do the following:
- Replace
Console
with one that has an enter frame/timer based loop. - Call main using the
startAsync
helper and throw out of it using theAS3_GoAsync()
macro defined in AS3.h - Call your C/C++
tick
function using the CModule helpers.
Open the makefile in a text editor to see how the replacement Console
is compiled
and how it is passed to gcc using the -symbol-abc option.
Sample 5: SWC
Now that you can compile code into SWFs and implement a run loop using a mixture of C++ and AS3, the next step is to compile code as a SWC library, so it can be easily distributed and used in standard AS3 workflows. This sample uses a hashing library called MurmurHash. The implementation is public domain and is hosted at http://code.google.com/p/smhasher/
Review the header. This library is very simple and
defines only three different hash functions. In this sample we expose just one
of these functions:MurmurHash3_x86_32
.
The files MurmurHash3.cpp/.h are unmodified. The wrapper code is located in as3api.cpp. This file shows how to use the as3sig annotation syntax that Crossbridge provides to control the resulting AS3 function signature for a given C/C++ function.
This syntax offers a good way to write the interface functions that sit between the AS3 and C/C++ codebases, performing any necessary marshaling and conversion.
For an interface like this one, you might imagine that the wrapper functions could be generated automatically. As you will see in the next sample Crossbridge comes with a modified version of SWIG (Simplified Wrapper and Interface Generator), which can do just that.
As with the animation sample, you must provide a simple main
method that
throws out via AS3 so that C++ static init code is run, but the destructors are
not. The client code that uses the generated MurmurHash.swc in swcdemo.as
calls startAsync
first to run the static inits. The MurmurHash3 function that
was defined in as3api.cpp can then be imported from the sample.MurmurHash
namespace and used.
The makefile for this sample compiles a native executable using the code in demo.cpp, which uses the MurmurHash library the same way that the code in swcdemo.as does. Running the generated SWF in the Flash Player and running the native executable on the command line should produce the same results.
Sample 6: SWIG
This sample contains four examples using SWIG:
- MurmurHash - Demonstrates using SWIG to automatically wrap the functions in the MurmurHash library that was manually wrapped in the previous sample
- PassingData - Demonstrates how to pass different data types between ActionScript and C
- LodePNG - Demonstrates wrapping an existing library that has many functions and types
- Typemaps - Demonstrates how to use SWIG's typemap directives to make the ActionScript API of your SWC easier to use
Choosing between SWIG and manual wrapping is a trade-off between convenience and control. Manually coding the wrapper code lets you produce more natural idiomatic AS3 interfaces for a library, but takes more time. SWIG can produce a full AS3 interface for a large library very quickly with minimal manual intervention, but it might not produce the cleanest interface.
SWIG is a complex system and offers lots of control over the generated interfaces, but there is too much to mention in this short sample. For more information, review the SWIG documentation for a deeper explanation of SWIG functionality.
At a high level what happens is that you invoke SWIG with a file containing header files and SWIG processing directives. SWIG inspects these headers to find Class/Struct and function definitions. Given no directives it tries to generate wrappers for all of these types, but these wrappers can be modified or hidden by various directives to SWIG (see SWIG documentation for more info).
SWIG generates both a C file and an AS file. The C file contains wrapper functions, similar to the one written in the previous sample. The AS file exposes these functions on a class and contains additional code to make the wrappers work correctly.
Compile the generated C file with gcc/g++ as though it were a normal source file in the project. If you are wrapping a library that is compiled to a ".a" static archive by its build system, then this generated C file should be compiled along with that archive to produce the final SWC.
The generated AS file must be compiled with ASC and then passed on the command line to gcc/g++ when producing the final SWC. ABC files given on the gcc/g++ command line are linked into the SWF/SWC being produced.
Further Examples
The version of SWIG provided with the Crossbridge SDK can generate ActionScript
wrapper classes for C structs. This is useful when you'd like to manipulate
or read the contents of a struct in your own ActionScript code. In order to
use this feature, the SWIG input file must be valid C code, which means that
SWIG directives can't appear in the file unless enclosed within an ifdef
. For example:
#ifdef SWIG // SWIG directives go here %typemap(in) foo {...}; #endif // C struct definitions, function prototypes, and so on, go here struct foobar { int foo; char bar; };
When SWIG processes this file, it preprocesses and parses it twice, once with the SWIG macro defined, and then without that macro defined. The first pass determines what wrappers will be generated and how types will be converted. The second pass determines how structs will be wrapped.
In general, it's good practice to always surround SWIG directives with ifdefs, so that the SWIG interface file is valid C code.
The ActionScript SWIG module generally respects the standard SWIG typemaps, and adds a few new typemaps that you can use, as appropriate. See sdk/usr/share/swig/2.0.4/as3/as3.swg for examples of typemap use. Note that defining typemaps is an advanced use of SWIG, and is unnecessary in many situations. For more information on typemaps, see: http://www.swig.org/Doc2.0/Typemaps.html
Sample 7: Filesystem
When using the Crossbridge compiler to generate standalone projector executables, the resulting code runs inside the AVM shell. Unlike the Flash Runtime, the AVM shell has special extensions that allow unrestricted access to the local filesystem.
When compiling applications or libraries to either SWF or SWC, the AVM shell extensions are no longer available, so compiled code will be unable to access or inspect the local filesystem.
By default, the low level filesystem APIs in the standard library are routed to
a virtual filesystem (VFS), which you can populate by embedding the actual files into your SWF or by implementing the IBackingStore
interface and handling filesystem requests in a custom way. The genfs
tool that ships with the Crossbridge SDK can be used to generate embedded, zipped, web-based or LSO-based VFS implementations (see the Reference guide for more information on how to use the genfs tool).
If the type is "http" then the output will be a manifest file that is designed to be included by the code in sdk/usr/share/HttpBackingStore.as. You will need to construct this class and listen for the complete event before being able to use the http based VFS.
In this example there is a single file, vfs/rocks.txt, which appears in the VFS as /rocks.txt because the vfsroot path is stripped off the resulting paths in the VFS. The VFS supports nested directories.
It's also possible to load files from the web rather than embedding them in your SWF. The sample demonstrates "mounting" a URLLoader-based filesystem at /web in the SWF's VFS. The single file inside of this filesystem is available to your application as /web/remote.txt.
Sample 8: GDB
This sample demonstrates how to start a GDB debugging session and execute some simple GDB commands. Before continuing with this sample you will need to follow the Setting up GDB instructions in the reference guide.
To run a Crossbridge SWF in GDB, you compile with the -g -O0 flags, for example:
/path/to/sdk/usr/bin/gcc -g -O0 -emit-swf -o debuggingexample.swf debuggingexample.c
Then launch GDB with the output SWF as a parameter:
/path/to/sdk/usr/bin/gdb debuggingexample.swf
This launches GDB and passes it the debuggingexample.swf file as the target application. This displays the GDB prompt, which looks something like this:
GNU gdb (GDB) 7.3 Copyright (C) 2011 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-apple-darwin10 --target=avm2-elf". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... (gdb)
At the GDB prompt, issue the break main
command to set a breakpoint at main():
(gdb) break main
To start the SWF, issue the run
command:
(gdb) run
At this point you are now in the SWF and ready to start debugging, stepping through
code, inspecting variables, listing source code, and so on. This example steps through
a few lines of code using the step
command:
(gdb) step 0xf0000032 21 int t = 1; (gdb) step 0xf0000034 24 for (i = 0; i < 8; i++){ (gdb) step 0xf0000037 25 t *= 2; (gdb) step 0xf0000039 24 for (i = 0; i < 8; i++){ (gdb) step 0xf0000037 25 t *= 2;
Use the info
command to check the values of the local variables:
(gdb) info locals s = 2 t = 2 i = 1
Use the continue
command to run to the end of the C code:
(gdb) continue
Notice that the SWF is now shown.
See the section in the Crossbridge reference guide and the GDB documentation to learn more about debugging using GDB.
Sample 9: Pthreads
With Flash player 11.5 Pthreads based multi-threading is fully supported via Crossbridge. Existing pthread-based code should run without any need to modify it. When running in the background not all Flash APIs are available (see the Reference guide for a full list of APIs that are not supported in the background) so you may need to communicate with the primary worker that does have full access to the Flash API set to perform certain operations.
Remember to compile your SWF with the option -pthread to enable pthread support. This will require the SWF version to be at least 18 (the default value) because the features of the Flash Player used by concurrency are only available to SWF 18 and higher.
pthreads.cpp explained
In this example a background thread is started that sleeps until it receives a mouseMove event from the foreground thread at which point it updates the position of a circle on the stage. This demonstrates how you can use the automatic marshaling support in AS3++.h to interact with objects on different threads.
Here's a breakdown of what takes place on each Thread/Worker in this example:
main
runs in a new Flash Worker by default when targeting SWF version 18.- Using the call to
get_Stage()
from theAS3::ui
namespace returns a reference to the Flash Stage that will automatically marshal any property access or method calls to the main Flash Worker regardless of what C thread is using it. - A new thread is spawned using
pthread_create
that runs the C functionthreadProc
in a new Flash Worker - When
threadProc
starts running it registers a mouseMove event listener using a function pointer to the C functionmouseMoveProc
. Again the automatic marshaling will ensure that this function is run from the main Flash Worker but run with the current C thread's ID so that it has full access to the Flash API set when running and access to the correct thread-local variables (while correctly ensuring no two workers are running the same C thread concurrently). - The background thread
threadProc
sits in a loop waiting to be woken up by the mouseMove event handler, at which point it does a simpleprintf
.
Sample 10: MessageChannel
This example shows how to combine the use of pthreads with the event-based communication that the Flash Player exposes via the MessageChannel API.
Thibault Imbert has a good introduction to this API from a pure AS3 point of view on his blog.
Sample 11: OpenMP

The OpenMP library is an attempt at bringing high-level multi-threaded primitives to low-level pthread-based programs. The OpenMP library handles thread pooling and task scheduling and lets the developer write what looks like single threaded code that is then automatically parallelized. This is done using various compiler pragmas to annotate which loops are suitable for parallel execution.
In this particular example a simple Mandlebrot fractal zoomer is automatically parallelized by using a for loop pragma so that multiple lines in the image can be rasterized in parallel. Clicking on the SWF increase the number of available threads by calling the omp_set_num_threads
API. When multiple threads are used the pixels will each have a blue tint based on which thread is being used to render them. You will see that this isn't consistent across frames because of the dynamic load balancing that OpenMP uses to allocate work to different threads.
When compiling code to use OpenMP make sure to pass -fopenmp to gcc/g++. This enables the OpenMP pragmas and links against the GNU OpenMP support library.
Some good reference material on OpenMP can be found here: http://www.nic.uoregon.edu/iwomp2005/iwomp2005_tutorial_openmp_rvdp.pdf and here http://gcc.gnu.org/onlinedocs/libgomp/.
Sample 12: Stage3D
This sample shows how you can use the as3wig (AS3 wrapper interface generator) tool that is included with the Crossbridge SDK to let you automatically generate strongly typed C++ bindings for pure AS3 libraries. In this example we use as3wig on the AGALMiniAssembler which is an ActionScript library that compiles AGAL assembly into AGAL bytecode suitable for use with the Stage3D API in the Flash Runtime.
This sample also demonstrates how the Flash++ bindings to Stage3D can be used to render 3D content with the gpu in the Flash runtime. Although this isn't any different from previous interop samples in its scope it is something a lot of Crossbridge users will be doing.
There is also a larger example called Space Triangle that shows a more complete game being developed purely in Flash++.