The FlasCC toolchain is closely modeled after a typical native C/C++ development toolchain. It contains all of the tools you would expect from such a toolchain, including a compiler (with preprocesser), an assembler, a linker, an nm symbol lister, an ar archiver, etc.
As with many such toolchains, FlasCC uses the preprocess, compile, assemble, link model. Each is an individual step, although the compiler driver may perform multiple steps with a single invocation.
In the following example, the compiler driver is used to go from a simple .c file to a final executable in a single command:
/* everyone's favorite C program: hello.c */ int main() { printf("Hello, world!\n"); return 0; }
# preprocess, compile, assemble, link, resulting in final executable
> flascc/sdk/usr/bin/gcc hello.c –o hello.exe
Under the hood, it’s going through 4 distinct stages.
Stage 1: Preprocessing
The preprocessing stage works the same way with FlasCC as with a conventional native toolchain. It processes
#include directives, expands macros, etc.
# preprocess hello.c resulting in preprocessed C in hello.i
> flascc/sdk/usr/bin/gcc –E hello.c –o hello.i
Stage 2: Compilation
The compilation stage compiles the preprocessed C code into “assembly code.” In a native toolchain, this would result in x86, arm, etc. assembly code. For FlasCC, “assembly code” is ActionScript 3 (AS3) code.
# compile hello.i resulting in “assembly code” in hello.s
> flascc/sdk/usr/bin/gcc –S hello.i –o hello.s
Stage 3: Assembly
The assembly stage “assembles” the ActionScript 3 code generated in the previous stage into “object code.” In actuality, it is doing a full compile of the AS3 code using the ASC2 compiler, resulting in an ActionScript Bytecode (or ABC) file. There is some additional work done to compile the single file into multiple AS3 “scripts” to allow lazy initialization of FlasCC modules at runtime. While the resulting file is actually ABC, the nm and ar utilities have been extended to understand them.
# assemble hello.s resulting in object code in hello.o
> flascc/sdk/usr/bin/gcc –c hello.s –o hello.o
The nm tool can be used to list symbols of an ABC “object file.”
# list C symbols in hello.o
> flascc/sdk/usr/bin/nm hello.o
00000000 T _main
U _puts
00000000 W abort
00000000 W memcpy
00000000 W memmove
00000000 W memset
The ar tool can be used to build an archive containing ABC “object files”
# create an archive containing hello.o
> flascc/sdk/usr/bin/ar cr hello.a hello.o
# list the C symbols in the hello.a archive
> flascc/sdk/usr/bin/nm hello.a
hello.o:
00000000 T _main
U _puts
00000000 W abort
00000000 W memcpy
00000000 W memmove
00000000 W memset
Stage 4: Link
Finally, we can link hello.o into a standalone executable.
# link hello.o into an executable
> flascc/sdk/usr/bin/gcc hello.o –o hello.exe
# execute the exe
> ./hello.exe
Hello, world!
This blog post describes why you might want a standalone executable built using FlasCC. But in most cases, you would want to build a SWF instead.
# link hello.o into a SWF
> flascc/sdk/usr/bin/gcc hello.o –emit-swf –o hello.swf
FlasCC is built on the LLVM Compiler Infrastructure and is therefore able to take advantage of LLVM’s powerful link time optimization features. LTO can, in many cases, result in substantially faster and smaller SWFs. LTO is enabled on a file-by-file basis by passing the
–flto flag to the compiler driver for each source file that is to participate.
Using the
–flto flag (or the
–O4 optimization level which implies
–flto) when compiling source into object code results in an LLVM bitcode file instead of an ABC.
# compile hello.c into LLVM bitcode
> flascc/sdk/usr/bin/gcc hello.c –c –flto –o hello.o
The relevant tools can consume both ABC and LLVM bitcode files.
# nm still works
> flascc/sdk/usr/bin/nm hello.o
00000000 T _main
U _puts
00000000 W abort
00000000 W memcpy
00000000 W memmove
00000000 W memset
# ar still works
> flascc/sdk/usr/bin/ar cr hello.a hello.o
# contents of archives still accessible
> flascc/sdk/usr/bin/nm hello.a
hello.o:
00000000 T _main
U _puts
00000000 W abort
00000000 W memcpy
00000000 W memmove
00000000 W memset
# build a LTO-ed version of hello.exe
> flascc/sdk/usr/bin/gcc –flto hello.o –o hello.exe
FlasCC comes with both ABC and LLVM bitcode flavored standard libraries. So a fully LTO build (
–flto or
–O4 passed to the compiler driver for each source file and for the link step) will do link time optimization of the standard C and C++ libraries as well as object files generated from user code.
One big difference between LTO and non-LTO builds in FlasCC is where AS3 generation and compilation happens. In a non-LTO build, AS3 is generated and compiled to ABC as each source file is compiled. Subsequently, the generated ABCs are combined in the link step to create a SWF or executable. Compared to compiling AS3, combining ABCs is a relatively inexpensive operation. So compiling each source file is relatively expensive, but linking is relatively cheap. Changing a single source file in a project means recompiling that source file and relinking.
In an LTO build, each source file is compiled to LLVM bitcode. In the link step, the LLVM bitcode files generated from source are linked together into a single aggregate bitcode file. That bitcode file can then be optimized. Since bitcode from various source files have been combined into this single unit, optimizations can be applied across functions and data from multiple source files.
After optimization, the bitcode is then used to generate a single AS3 file that is then compiled with ASC2. This results in compile time characteristics that are the opposite of non-LTO builds. Here, compilation of source is cheap and linking in expensive. This also means that, since the generated AS3 depends on the aggregate LLVM bitcode file, and the aggregate LLVM bitcode file depends on each LLVM bitcode file derived from source (as well as bitcode for the C/C++ standard libraries in a fully LTO build), all AS3 must be regenerated and recompiled every time any source file in a project is changed!
So, as a general rule, it makes sense to use LTO for release-type builds because the longer compile time will result in smaller/faster SWF files. On the other hand if you are creating debug-type builds it makes sense to avoid LTO for faster compile times making it easier to iterate on the code.
A bit more on this topic can be found in the reference guide in the Optimizing SWFs and SWCs subsection of the Compiling With GCC section.]]>
Fl)
The.
The Neverball project is an open source computer game written in C++ using OpenGL. The goal is to tilt the floor to roll a ball around picking up coins and getting to the exit. You can download the native executable to try the game yourself from the Neverball Downloads page.
The Neverball Downloads page also allows you to download the source code for the game. You can try downloading the source code and using a native g++ toolchain to build a native executable.
Learn how to port this game to run in the browser by reading the extensive article on the Adobe Developer Center that describes how to compile OpenGL games with the Flash C++ Compiler (FlasCC).
The FlasCC engineering team has already built a version of the game and hosted it online for you to try yourself.
Neverball Live Demo
This screencast demonstrates the game in action across various web browsers:]]>
A:
#include
#include "AS3/AS3.h" void doSomething() __attribute__((used, annotate("as3sig:public function doSomething():void"), annotate("as3package:MyLibrary"))); void doSomething() { printf("SUCCESS\n"); } int main() { // The SWC still needs a main() function. // See the code comments in samples/05_SWC for more details. AS3_GoAsync(); }:
package { import flash.display.Sprite; import flash.text.TextField; import flash.events.Event; import MyLibrary.CModule; import MyLibrary.vfs.ISpecialFile; public class SampleApplication extends Sprite implements ISpecialFile { private var tf:TextField; public function SampleApplication() { addEventListener(Event.ADDED_TO_STAGE, initCode); } private function initCode(e:Event):void { tf = new TextField(); addChild(tf); tf.appendText("SWC Output:\n"); // set the console before starting MyLibrary.CModule.vfs.console = this; // start the FlasCC library MyLibrary.CModule.startAsync(this); // call a C++ function that calls printf MyLibrary.doSomething(); } /** * The PlayerKernel implementation will use this function to handle * C IO write requests to the file "/dev/tty" (e.g. output from * printf will pass through this function). See the ISpecialFile * documentation for more information about the arguments and return value. */ public function write(fd:int, bufPtr:int, nbyte:int, errnoPtr:int):int { var str:String = CModule.readString(bufPtr, nbyte); tf.appendText(str); trace(str); return nbyte; } /** See ISpecialFile */ public function read(fd:int, bufPtr:int, nbyte:int, errnoPtr:int):int { return 0; } public function fcntl(fd:int, com:int, data:int, errnoPtr:int):int { return 0; } public function ioctl(fd:int, com:int, data:int, errnoPtr:int):int { return 0; } } }
The other
ISpecialFile methods are not fully implemented and left as an exercise to the reader. See the documentation of
ISpecialFile and the FlasCC reference guide for more information on working with a custom Console.
This.]]>
Learning.
These projects can be found in the /samples/ folder of the FlasCC SDK which can be downloaded from the Adobe Gaming Tools page.
The Box2D example creates a SWC from the C++ Box2D library. SWIG is used to automate the process of generating all of the wrapper code which is incredibly helpful as it avoids you writing lots of tedious and bug-prone wrapper code by hand. Having the ActionScript API auto-generated like this can be an important timesaver if you need to update the underlying C++ code.
Bullet is a large C++ library with roughly 130 thousand lines of code. It is used throughout the industry for both offline and real-time physics simulations. It not only supports basic rigid-body physics, but also more advanced soft-body physics for simulating deformable objects such as cloth. Creating a SWC with an ActionScript API for Bullet is a trivial process and allows ActionScript developers high-performance access to this great library. The demo we ship with the FlasCC SDK shows how to create a simple 3D scene using the Away3D library and how Bullet can be used to provide physical simulation for the objects in the Away3D scenegraph.
Live Demo:
Due to its small size and how easy it is to embed within other environments a lot of people are choosing Lua as their scripting language of choice. The reference implementation of the Lua interpreter is written in C and is designed to be compiled as a library and linked into other projects. As with the other examples we used SWIG here to automatically generate the AS3 bindings. We also write some interop code by hand that reflects the AS3 API into Lua so that Lua programs can be run within the Flash Player and can interoperate with the Flash API set. We wrote a simple real-world example that shows a Starling-based AS3 application that is controlled by a Lua script that can be updated while the SWF is executing.
Live Demo:
Click “Run Script” to execute the Lua script. Note that you can edit the script live and click “Run Script” again to execute your latest changes. For example try changing the line “gravity = 5” to “gravity = 0.01” and click Run Script again to see your changes.
This was the killer demo for the original Alchemy prototype and showed that complex C code could be compiled correctly into a SWF with excellent runtime performance. The game might be old, but it still looks surprisingly good and performs better when compiled with FlasCC than it did with the old Alchemy prototype.
For a more modern killer demo take a look at the FlasCC-compiled Unreal Engine live demo.]]>
This.]]>
Stage3D allows GPU accelerated 3D content to run in the Flash Player accross operating systems and browsers. We have a number of interesting libraries that will help you bring your OpenGL C/C++ code to the web with FlasCC.
The GLS3D library is an open source project we started to provide a basic OpenGL implementation for FlasCC users targeting Stage3D.
Source Code:
Live Demo:
The GLUT library was created to make it easier to write cross-platform OpenGL based apps. I’ve implemented a Stage3D backend for the FreeGLUT library and used it in conjunction with the GLS3D project to compile some of the popular NeHe OpenGL tutorials.
Source Code:
Live Demo:
If you’ve investigated the Stage3D API you’ll know that the shader format is a custom bytecode format designed to be easily compiled down to DirectX bytecode or GLSL depending on the platform the Flash Player is running on. Sadly this makes it hard for humans to write. This project is based on the open-source Mesa codebase and contains a full GLSL parser and optimizer hooked up to a custom AGAL backend so that GLSL shaders can be compiled and optimized down to AGAL bytecode. It can be used offline as a pre-processing step within your applications asset creation workflow or at runtime by compiling the library to a SWC with FlasCC and using it in your SWF.
The repository also includes a precompiled SWC so that you can get started with it immediately.
Source Code:
Live Demo:
Starling 1.2 supports AGAL based filters that can be applied to any Sprite to alter the way they render. Rather than writing the filter by hand with AGAL asm its possible to hook up the GLSL2AGAL project to Starling so that these Filters can be written using GLSL. Modifying the shader in the UI causes the filter to update in realtime.
Source Code:
Live Demo:
Fl the value of a property of an ActionScript object is pretty straightforward by using the
getproperty() function.
In the sample code below the
getDelta() C++ function demonstrates this.
Setting the value of a property is also straightforward by using the
setproperty() function.
In the sample code below the
setDelta() C++ function demonstrates this..
Here is a sample C++ library that demonstrates how to do each of these operations.
When compiling this library using g++ remember to set the
-lAS3++ flag as described in the AS3++ documentation.
#include
#include "AS3/AS3.h" #include "AS3/AS3++.h" //// // // Get a property of an ActionScript object in C++ // //// void getDelta() __attribute__((used, annotate("as3import:flash.events.MouseEvent"), annotate("as3sig:public function getDelta(m:MouseEvent):int"), annotate("as3package:MyLibrary"))); void getDelta() { // marshall the AS3 parameter into a C++ variable AS3::local::var mouseEvent; AS3_GetVarxxFromVar(mouseEvent, m); // now that we have it in C++ let's get a property on that object AS3::local::var propertyName = AS3::local::internal::new_String("delta"); AS3::local::var outputValue = AS3::local::internal::getproperty(mouseEvent, propertyName); // convert the var to a scalar int output = AS3::local::internal::int_valueOf(outputValue); // return that scalar value AS3_Return(output); } //// // // Set a property on an ActionScript object in C++ // //// void setDelta() __attribute__((used, annotate("as3import:flash.events.MouseEvent"), annotate("as3sig:public function setDelta(m:MouseEvent):void"), annotate("as3package:MyLibrary"))); void setDelta() { // marshall the AS3 parameter into a C++ variable AS3::local::var mouseEvent; AS3_GetVarxxFromVar(mouseEvent, m); // now that we have it in C++ let's set a property on that object AS3::local::var propertyName = AS3::local::internal::new_String("delta"); AS3::local::var newValue = AS3::local::internal::new_int(5); AS3::local::internal::setproperty(mouseEvent, propertyName, newValue); } //// // // Call a method of an ActionScript object in C++ // //// void getString() __attribute__((used, annotate("as3import:flash.events.MouseEvent"), annotate("as3sig:public function getString(m:MouseEvent):String"), annotate("as3package:MyLibrary"))); void getString() { // marshall the AS3 parameter into a C++ variable AS3::local::var mouseEvent; AS3_GetVarxxFromVar(mouseEvent, m); // demonstrate how to call a function of that object from C++ AS3::local::var functionName = AS3::local::internal::new_String("toString"); // first get the property of the object called "toString" which is a Function var AS3::local::var function = AS3::local::internal::getproperty(mouseEvent, functionName); // then call that Function object (in this case it takes no parameters) AS3::local::var output = AS3::local::internal::call(function, AS3::local::internal::_null, 0, NULL); // Since AS3_Return (as shown in getDelta()) can only accept a scalar value we need // to marshall this C++ object into an ActionScript String and return it using AS3_ReturnVar AS3_DeclareVar(asOutputString, String); AS3_CopyVarxxToVar(asOutputString, output); AS3_ReturnAS3Var(asOutputString); } int main() { // The SWC still needs a main() function. // See the code comments in samples/05_SWC for more details. AS3_GoAsync(); }
And here is a sample ActionScript application that demonstrates how to call the methods in the SWC generated from that C++ library:
package { import flash.display.Sprite; import flash.text.TextField; import flash.events.Event; import flash.events.MouseEvent; import MyLibrary.CModule; public class demo extends Sprite { public function demo() { addEventListener(Event.ADDED_TO_STAGE, initCode); } private function initCode(e:Event):void { var tf:TextField = new TextField(); addChild(tf); // start the FlasCC library MyLibrary.CModule.startAsync(this); // a sample ActionScript object var me:MouseEvent = new MouseEvent("click"); // // Get a property // tf.appendText("delta=" + MyLibrary.getDelta(me) + "\n"); // // Set a property // MyLibrary.setDelta(me); tf.appendText("delta=" + me.delta + "\n"); // // Call a method // tf.appendText("toString=" + MyLibrary.getString(me) + "\n"); } } }]]>
The Adobe Flash C++ Compiler (FlasCC).
FlasCC 1.0 was officially released today as part of the Game Developer tools in the Adobe Creative Cloud.
Download the FlasCC SDK as part of a Creative Cloud subscription.
If you have questions about the FlasCC SDK check out the FlasCC community forums.
Also check out these other game developer tools that shipped today:
Adobe Scout – an advanced profiling tool designed to help you optimize performance of your SWF content.
The Adobe Gaming SDK – a simple starting point for creating ActionScript-based games using popular open source 2D and 3D frameworks (Starling, Feathers, and Away3D).]]>