云里来.雾里去2014-09-28 14:35:24281 次阅读
在《Cocos2d-x反走样画线》一文中已经介绍了Cocos2d-x的绘画方法,但是这些方法还是只能绘制一些比较简单的东西,没有办法满足高级的需求,比如像html canvas 提供的一些绘画方法就没办法支持。
所以最近一直在寻找跨平台绘画的库,找到的都是一些比较出名的C++绘画库,比如cairo、skia、agg 等,但是这些库都有个比较大的缺点就是 过于庞大,不适用于放到Cocos2d-x中,而且看到除了skia,其他的都没有怎么更新了。想过分离skia核心的部分来用,但是尝试了下还是算了。
比较幸运的是尝试了上面的库后,发现了一个非常不错的轻量级矢量图绘画库:
Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations.
The NanoVG API is modeled loosely on HTML5 canvas API. If you know canvas, you’re up to speed with NanoVG in no time.
nanovg 非常轻量级,只有一个.c文件加几个.h文件,代码量也不过3000多行。
但是他支持的功能确实非常多:反走样绘制,设置笔帽样式,渐变色,路径等等。
并且他可以通过宏设置当前opengl版本,gl2, gl3, gles2, gles3。
编译 nanovg
源码下载:nanovg-master.zip
Github地址:https://github.com/memononen/nanovg
nanovg使用premake工具来生成编译文件,Mac平台安装只需要运行brew install premake即可完成安装。
然后cd到nanovg目录,执行premake4 –help可以看到支持生成的工程文件选择premake4 xcode3
可以在nanovg/build目录下找到生成的工程文件。
这是编译后运行的demo截图,gif效果有折扣,看上面的截图会比较清晰(点击这里看大图)。
在Cocos2d-x中使用
为了测试nanovg在Cocos2d-x中使用效果,做了个小demo。
先上 Demo效果图(点击这里看大图):
git 地址:https://github.com/2youyouo2/nanovg-test.git
因为nanovg足够轻量,所以直接将它的代码包含进工程基本就可直接使用。
1
2
3
4
5
6
7
8
9
10
11
|
#include "nanovg.h"
// 移动平台使用 gles2, 桌面平台使用gl2
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#define NANOVG_GLES2_IMPLEMENTATION
#else
#define NANOVG_GL2_IMPLEMENTATION
#endif
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"
|
创建 context 也需要根据平台区分
1
2
3
4
5
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
vg = nvgCreateGLES2(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG);
#else
vg = nvgCreateGL2(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG);
#endif
|
绘画函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
void
HelloWorld::onDraw(
const
Mat4 &transform, uint32_t flags)
{
auto origin = Director::getInstance()->getVisibleOrigin();
nvgBeginFrame(vg, width, height, 1);
// draw background
nvgBeginPath(vg);
nvgRect(vg, 0,0, width,height);
nvgFillColor(vg, nvgRGBA(255,255,255,255));
nvgFill(vg);
nvgStrokeColor(vg, nvgRGBA(0,0,0,50));
for
(
int
i=0; i<nbPts-1; i++) {
for
(
int
j=i+1; j<nbPts; j++) {
if
(dist(x[i], y[i], x[j], y[j])<RADIUS+10) {
nvgBeginPath(vg);
nvgMoveTo(vg, x[i], y[i]);
nvgLineTo(vg, x[j], y[j]);
nvgStroke(vg);
nbConnex[i]++;
nbConnex[j]++;
}
}
}
for
(
int
i=0; i<nbPts; i++) {
angle[i] += speed[i];
x[i] = ease(x[i], width/2 +
cos
(angle[i]) * rad[i], 0.1);
y[i] = ease(y[i], height/2 +
sin
(angle[i]) * rad[i], 0.1);
diam[i] = ease(diam[i], min(nbConnex[i], 7)*max(0.5,(rad[i]/RADIUS/5.0)), 0.1);
nvgBeginPath(vg);
nvgFillColor(vg, nvgRGBA(0,0,0,100));
nvgEllipse(vg, x[i], y[i], diam[i] + 3, diam[i] + 3);
nvgFill(vg);
nvgBeginPath(vg);
nvgFillColor(vg, nvgRGBA(0,0,0,255));
nvgEllipse(vg, x[i], y[i], diam[i], diam[i]);
nvgFill(vg);
nbConnex[i] = 0;
}
nvgBeginPath(vg);
nvgMoveTo(vg, 0,0);
nvgLineTo(vg, 100, 40);
nvgStrokeColor(vg, nvgRGB(255,255,255));
nvgStrokeWidth(vg, 3);
nvgStroke(vg);
nvgEndFrame(vg);
GL::bindTexture2D(0);
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_NONE);
GL::useProgram(0);
}
|
nanovg api都以 nvg 前缀开始,使用类似于 html canvas。
绘画必须包含在nvgBeginFrame和nvgEndFrame之中。
1
2
|
// width, height 表示绘画区域,最后一个参数是指定像素比例,在高清设备上可以设置2来使绘画更清楚
nvgBeginFrame(vg, width, height, 1);
|
需要注意的是nvgEndFrame内部会调用gl函数清除gl状态,但是Cocos2d-x默认是做了gl状态缓存的。
比如GL::useProgram中会判断缓存状态有没有更改来决定是否执行gl函数
1
2
3
4
5
6
7
8
9
10
11
|
void
useProgram( GLuint program )
{
#if CC_ENABLE_GL_STATE_CACHE
if
( program != s_currentShaderProgram ) {
s_currentShaderProgram = program;
glUseProgram(program);
}
#else
glUseProgram(program);
#endif // CC_ENABLE_GL_STATE_CACHE
}
|
这样就会造成nvgEndFrame直接清除了gl状态,但是没有修改cocos2dgl缓存状态,导致Cocos2d-x绘制错误。
所以需要在后面手动清除cocos2dgl缓存状态,如果出现绘制问题,很可能是有些缓存状态没有清除
1
2
3
|
GL::bindTexture2D(0);
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_NONE);
GL::useProgram(0);
|
更简单的方法就是直接设置CC_ENABLE_GL_STATE_CACHE为0。
processing
在这个demo中还使用了另外一个库,processing的C++版本
Processing是一种具有革命前瞻性的新兴计算机语言,它的概念是在电子艺术的环境下介绍程序语言,并将电子艺术的概念介绍给程序设计师。它是Java语言的延伸,并支持许多现有的Java语言架构,不过在语法(syntax)上简易许多,并具有许多贴心及人性化的设计(摘自百度百科)。
processing提供了比较简单了方法做出十分酷炫的东西,他有许多优秀的扩展版本,比如:paper.js,p5.js,processing.js
其中paper.js是我比较喜欢的一个版本。
http://openprocessing.org/是一个可以在线编辑processing的网站,其中许多demo都非常酷炫,即使不使用processing语言也可以从上面获取到灵感或是找到相关算法。
cprocessing如其名,是processing的一个C++版本,也比较轻量,他没有移植所有processing功能,只是一些基本的函数。