#
這個例子是建立在上一個interop示例的基礎上的,這個例子演示了一些更復雜的交互。(繪制到舞臺)。 這個例子由兩個CPP文件組成,所以,可以去看它的makefile文件,看它們是如何用G++打包的(如果不熟悉G++的話,可以通過這個學習一下用法)。
如果你不太熟悉Voronoi圖,可以自己百度,但是,這不是本示例的重點。這個例子主要是想向大家展示的是一些在voronoi.cpp使用到的FLASH交互內容。
如果你查看voronoi.cpp源代碼,你可以看見一個叫console的類。 這個類的源代碼放在了sdk/usr/share/Console.as位置。 這個類的目的就是提供一些libc的調用實現,比如printf什么的。
Console.as除了提供基礎調用以外,也是作為你編譯為SWF文件的主類,大家都知道的,如果在AS3中想生成一個項目,必須是要有一個活動AS3文檔,派生自Sprite作為入口函數的。 Console.as提供了一個TextField來接受所有的標準C/C++輸出。 而在一個真正的SWF或者SWC中,你可能需要替換Console.as來實現自己的需求,比如輸出重定向什么的。 下一個例子就會向你演示如何來實現一個自己的Console.as。
但是,在這個例子中,大家只要把注意力集中在它的current變量上就可以了。
當使用默認的SWF版本(-swf-version-18)編譯時。FLASCC將會嘗試在后臺運行代碼。 但是,在這個例子中,我們直接將想要繪制的東西繪制到舞臺上。 因為舞臺上的東西,在后臺運行時,也會得到相應的處理。 至于 多線程的東西, 后面的教程會提到,所以,這個例子就沒有必要演示得太多了。
最后,這個例子使用了SWF 17進編譯,它會運行在Flash的主線程中。
上幾個例子向我們展示了,如何在main()函數里用C++和AS3進行交互。 但是,如果我們想在C++中實現一些動畫效果(循環播放的),怎么辦呢? AS3是單線程的,所以,我們不可能說放一個while(true)在main函數里。因為這會把Flash Player的線程阻塞,所有的圖像,聲音和輸入就都不能被處理了。
所以,我們需要組織我們的代碼,然后每幀進行調用。 這就需要用到enter frame或者timer事件。 這個示例就替換了默認的console實現, 而增加了一個enter frame處理器,來調用函數。
例子中的console.as這個AS文件,是本例子的實現,FLASCC內部有一個默認實現,用于處理一些輸出,比如printf等。 根據不同的需要,可以像本例一樣,替換這個console.as文件。從而實現自己的功能。
打開Console.as,你可以在Console的構造函數中發現一個叫CMoulde.startAsync的函數。這是一個幫助函數,它會調用main函數。 在繼續講一些內容之前,需要注意以下兩個特點
1、在main函數運行之前,所有的C++靜態變量(基礎類型)會先運行并初始化
2、而在main函數運行時,C++中的靜態構造函數會運行。一些靜態全局實例
上面的兩點很重要,因為在使用FLASCC將代碼編譯為SWC庫,或者想要驅動一個動畫時,main函數在返回時,不能執行上面兩種代碼的析構函數。 為了防止析構執行,我們在main函數結尾處拋出一個AS3異常,通知AS3。
在GameOfLife.cpp最后一行,可以發現 AS3_GoAsync(); 這個調用,它就是干這個事情的。
在GameOfLife.cpp中,你會發現一個叫updateUniverse的函數,它被標記為了 extern “C”. 這個是防止C++編譯器對它的名字進行改動(C++因為支持函數重載,所以會把函數名加上一些標記,標記為C函數后,則不會做此改動)。 這樣,AS3代碼想調用這個函數的時候,才能夠在符號表中,通過名字正確地找到它。 (不過,下一個例子你可以使用另外的方式來控制C++代碼向AS3導出的名字,也就是說,你可以自己指定一個名字)。
讓我們回到Console.as,我們還可以發現一個叫frameBufferBlit的函數。 這個函數就是enter frame事件的處理函數,在這個函數里,使用了一個叫getPublicSymbol的函數。 用腳也能想到了,這個函數肯定是拿來查找C/C++函數的了。 果不其然,可以發現,它查找的正是前面說到的updateUniverse
函數。
最后,簡單總結一下,要在FLASCC中實現你自己的主循環,你需要做下面的事。
1、替換Console.as,改為一個帶enter frame或者timer的版本。
2、在Console構造函數中使用startAsync函數,在main函數結尾使用AS3_GoAsync()
3、使用CModule幫助函數調用你的更新函數。
另外,這個例子也向我們展示了AS3代碼和C++代碼混編的方法。 參考04_Animation中的Makefile可以知道,需要結合編譯,得先將AS3代碼編譯為abc,然后再使用 -symbol-abc 參數一起編譯。
這個例子收獲較多啊。上個圖吧。以作紀念。

這個例子主要是向大家展示 voronoi 圖的繪制方法。
Voronoi圖,又叫泰森多邊形或Dirichlet圖,其具體介紹可以參見這里http://baike.baidu.com/view/501103.htm,這不是本例子的重點。
這個例子并沒有向大家展示太多的東西,AS3相關的調用和C API的使用,也和先前沒有太多區別。 唯 一不同的是,這個例子的voronoi圖的生成,使用了C++ class. 也就是說,這個例子,讓大家看到FlasCC對C++的支持。
下面的代碼,是例子原生代碼,中間并沒有注釋。 這是因為,已經不需要注釋了。所用到的,都是前面 Interop中已經介紹了的內容。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "VoronoiDiagramGenerator.h"
#include "AS3/AS3.h"
int main(int argc,char **argv)
{
int stagewidth, stageheight;
inline_as3(
"import flash.display.Stage;\n"
"import flash.display.Graphics;\n"
"import com.adobe.flascc.CModule;\n"
"var gfx = CModule.rootSprite.graphics;\n"
"gfx.lineStyle(1, 0);\n"
"gfx.beginFill(0, 0.0);\n"
"%0 = CModule.rootSprite.stage.stageWidth;\n"
"%1 = CModule.rootSprite.stage.stageHeight;\n"
: "=r"(stagewidth),"=r"(stageheight) :
);
const int cellcount = 512;
float xvals[cellcount], yvals[cellcount];
for(int i=0; i<cellcount; i++) {
xvals[i] = stagewidth * ((float)rand()/(float)RAND_MAX);
yvals[i] = stageheight * ((float)rand()/(float)RAND_MAX);
}
VoronoiDiagramGenerator vdg;
vdg.generateVoronoi(xvals, yvals, cellcount, 0, stagewidth, 0, stageheight, 3);
vdg.resetIterator();
float x1,y1,x2,y2;
while(vdg.getNext(x1,y1,x2,y2))
{
inline_as3("gfx.moveTo(%0,%1);\n" : : "r"(x1), "r"(y1));
inline_as3("gfx.lineTo(%0,%1);\n" : : "r"(x2), "r"(y2));
}
inline_as3("gfx.endFill();\n");
}
來個圖!

bitmapdata是FlasCC官方例子02_Interop中的例子。這例子比起c++interop來說,多了一個鼠標事件監聽。
我們逐行分析一下吧。
#include <AS3/AS3.h>
#include <Flash++.h>
using namespace AS3::ui;
static const int COORDBITS = 7; // 7 bits => dim of 128
static const int DIM = 1 << COORDBITS;
這個函數主要是根據一個給出的offset值,返回一個計算后的值
static int swizzleOffset(int offs)
{
int result = 0;
int coordBits = COORDBITS;
int offsHi = offs >> COORDBITS; // take the higher order bits
int coordBits2 = COORDBITS * 2;
while(coordBits--)
{
// put the lowest bit in the "lo" offset bits
// into the highest bit of the result...
// it'll get shifted into a lower position
// as the loop executes
result |= ((offs & 1) << coordBits2);
offs >>= 1;
result >>= 1;
// same for the "hi" offset bits
result |= ((offsHi & 1) << coordBits2);
offsHi >>= 1;
result >>= 1;
}
return result;
}
// 將一個圖像的像素進行混淆
static void swizzlePixels(unsigned *dst, unsigned *src)
{
int offs = DIM * DIM;
while(offs--)
{
int swiz = swizzleOffset(offs);
dst[swiz] = src[offs];
}
}
//監聽鼠標點擊事件,然后混淆BitmapData的像素值
static var mouseDownHandler(void *arg, var args)
{
flash::events::MouseEvent event = flash::events::MouseEvent(args[0]);
flash::display::Sprite sprite = flash::display::Sprite(event->target); // the container Sprite
flash::display::Bitmap bitmap = flash::display::Bitmap(sprite->getChildAt(0)); // Bitmap is the only child
flash::display::BitmapData bitmapData = bitmap->bitmapData;
// ByteArray corresponding to our ram!
// C ptrs are equivalent to offsets into this ByteArray
flash::utils::ByteArray ram = internal::get_ram();
// allocate space for the pixels
unsigned *src = new unsigned[DIM * DIM];
unsigned *dst = new unsigned[DIM * DIM];
// copy current pixels directly to ram
bitmapData->copyPixelsToByteArray(bitmapData->rect, ram, src);
// swizzle them!
swizzlePixels(dst, src);
// write new pixels directly from ram
bitmapData->setPixels(bitmapData->rect, ram, dst);
// clean up
delete dst;
delete src;
return internal::_undefined;
}
int main()
{
//取得舞臺
flash::display::Stage stage = internal::get_Stage();
//創建一個Shape
flash::display::Shape myShape = flash::display::Shape::_new();
flash::display::Graphics graphics = myShape->graphics;
//繪制簡單的圖形 這是一個像把子一樣的圓
graphics->beginFill(0xff00ff, 0.5);
graphics->drawCircle(64.0, 64.0, 64.0);
graphics->endFill();
graphics->beginFill(0xffff00, 0.5);
graphics->drawCircle(64.0, 64.0, 40.0);
graphics->endFill();
graphics->beginFill(0x00ffff, 0.5);
graphics->drawCircle(64.0, 64.0, 16.0);
graphics->endFill();
//創建一個BitmapData
flash::display::BitmapData myBitmapData = flash::display::BitmapData::_new(DIM, DIM);
//把圖形繪制到這個bitmapdata上
myBitmapData->draw(myShape);
// 創建一個Bitmap
flash::display::Bitmap myBitmap = flash::display::Bitmap::_new(myBitmapData);
// 加到一個Sprite中,以便顯示
flash::display::Sprite mySprite = flash::display::Sprite::_new();
mySprite->addChild(myBitmap);
// 增加一個鼠標監聽器
mySprite->addEventListener("mouseDown", Function::_new(&mouseDownHandler, NULL));
// 添加到舞臺
stage->addChild(mySprite);
// 這個函數將會使C++與AS3進行同步,以使可以處理鼠標事件。
AS3_GoAsync();
// 因為運行機制的原因,這行代碼是無法到達的。
return 0;
}
還是上個圖吧。

這個例子主要是向用戶展示,如何通過FlasCC提供的API,來操作AS3中的運行時庫。 包括stage,sprite等。
#include <vector>
#include <AS3/AS3.h>
#include <Flash++.h>
Flash 11.4時提供了一個基于工作線程的并發模型。這使得多個工作線程幾乎可以同時訪問Flash的API,只有一個限制就是,多個工作線程的對象不可以相互傳遞。工作線程之間的通信必須通過一個特殊的機制MessageChannel,或者在Flash 11.5后,可以使用共享的ByteArray進行通信。
Flash++這個頭文件提供了兩組Flash API的綁定。一是Flash中的UI工作線程的對象,另一個就是一個屬于一個工作線程的本地對象。
當使用“ui”相關的屬性來訪問時,這些方法的調用會被阻塞,直到它可以被主工作線程服務并調用CModule.serviceUIRequests() (這一般情況下是被EnterFrame或者在一個timer中被處理)
using namespace AS3::ui;
int main()
{
//取得當前舞臺的引用
flash::display::Stage stage = internal::get_Stage();
//我們用一個C++ VECTOR來裝Sprite引用
std::vector<flash::display::Sprite> sprites;
int numCircles = 10;
for(int i=0; i<numCircles; i++) {
// 新建一個Sprite
flash::display::Sprite mySprite = flash::display::Sprite::_new();
//訪問它們的 graphics屬性,然后,我們用來繪制
flash::display::Graphics graphics = mySprite->graphics;
//繪制實心圓
graphics->beginFill(0xff00ff, 0.5);
graphics->drawCircle(0.0, 0.0, 30.0);
graphics->endFill();
// 保存下來
sprites.push_back(mySprite);
}
// 添加到舞臺
for(int i=0; i<numCircles; i++) {
// 修改位置
flash::display::Sprite s = sprites[i];
s->x = i * 25;
s->y = i * 25;
//添加進舞臺
stage->addChild(s);
}
}
來張圖吧,我們終于可以看見東西了。
