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.

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.

Building 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:

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).

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.

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 the AS3_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:

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:

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:

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 the AS3::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 function threadProc in a new Flash Worker

When threadProc starts running it registers a mouseMove event listener using a function pointer to the C function mouseMoveProc. 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 simple printf.

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.

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++.