#
这个例子是建立在上一个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);
}
}
来张图吧,我们终于可以看见东西了。