Agg学习笔记之渲染

No Comments

        Agg渲染层(Render)分为三层,最底层和RenderBuffer通信,主要封装各种颜色模式和基本的操作,如Copy/Blend。中层主要是BaseRender,作为上下两种的连接层,主要实现基本的裁剪。渲染层最上是应用层,用来和Scanline Rasterizer 层通信。他们的交互通过scanline 来完成。

      Scanline Rasterizer 主要用于光栅化上层提供的矢量图形,并且以Y轴将其分解成y条水平线,这些水平线最终存储在scanline中。

      关于scanline,这里摘抄一段http://blog.csdn.net/liyiwen007/archive/2010/06/09/5659411.aspx

      AGG 中主要的光栅化技术是基于 scanline 的,也就是说,一个多边形会先转换成很多的水平扫描线,然后再逐个描画这些扫描线。同样的, scanline rasterizer 并不是唯一可以用于生成水平扫描线(scanline)的类,你也可以使用一些容器,甚至是你自己的  super-ultra-mega rasterizer

      在从 rasterizer(光栅化器)到 scanline renderer 之间的信息转换时,用到了 scanline 容器。一个 scanline 由很多的水平的、不相交的 span 组成。这些 span x 轴排序。这就意味着并没有提供排序这个操作,必须在将 span 添加到 scanline 时就把顺序处理好。如果顺序不是按要求排列的,那么可能会出现未定义的行为。

      AGG 中有以下三种 scanline 容器。

  1. scanline_u – 未包装的 scanline 容器。
  2. scanline_p – 包装过的 scanline 容器。
  3. scanline_bin – 原始的,“带锯齿”的 scanline 容器。

      前面两种容器可以包含去锯齿信息,第三种不行。

      包装的(packedscanline 与未包装的(unpackedscanline 的区别在于, unpacked scanline 总是会为所有像素保存覆盖值(coverage value),包括那些全部覆盖在多边形内部的像素。而 packed scanlines 则会把具有相同 coverage value 的像素合并成 solid span

      看起来好像使用 packed 版的 scanline 总是会好一点,但在实践中并非如此。但你渲染一些大型的实心多边型时,使用 scanline_p 会更快,那是因为多边型的面积比周长要大很多(从像素的角度来衡量)。但是如果是渲染字符的时候绝对应该使用 scanline_u ,这样就能处理更少的 span 了,(scanline_u 会比 scanline_p)大约少产生三倍左右的 span,而 span 数本身就是一项重要的开销。同样的,在大多数 span 产生器中(比如 gradients, Gouraud shader, 以及 image 产生器等),span 的数量更加是(效能的)关键,所以一般也不会使用 scanline_p

      站在巨人的肩膀上,我也废话几句,Agg抗锯齿信息通过存储在scanline_u和scanline_p中的cover值来体现,虽然cover值不等同alpha值,不过它的大小直接影响到alpha值的大小,这种影响在Agg渲染层顶层中得以体现。

      应用层包含几个类和若干工具函数,实际上这些类也就对工具函数进行简单的封装agg_renderer_scanline.h。这些类包括:

http://www.cppprog.com/2009/0821/150_5.html

template<class BaseRenderer>
	class renderer_scanline_aa_solid; //实色AA渲染
template<class BaseRenderer>
	class renderer_scanline_bin_solid; //实色原始渲染
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
 	class renderer_scanline_aa; // 自定义AA渲染
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
 	class renderer_scanline_bin; // 自定义原始渲染

      关于这四个类,有两种分类方法:

      aa/bin(一三/二四),包含aa的使用scanline的反锯齿信息(通过alpha值实现),包含bin的则仅仅根据原始的顶点渲染。这两者的区别可以通过下面的图来说明:

aa

 

      左边使用 renderer_scanline_bin_solid渲染,每一次Span渲染操作都是同一颜色(因为忽略了反锯齿信息),右边使用 renderer_scanline_aa_solid,因为会使用scanline的抗锯齿信息,所以每一次Span都可能包含若干种颜色(通过scanlinecover值改变alpha值,然后alpha blend改变颜色),从而导致锯齿不明显(这也导致了抗锯齿的线比没有抗锯齿的线稍窄)

      另一种分类方法是solid/none(一二/三四),solid(如其意)在渲染Span是只能使用单种颜色,如上图。而后者则可以对一次Span渲染中的每一个像素指定一种颜色。这些颜色从哪里来呢?通过其模板参数 SpanGenerator提供,那SpanGenerator是什么,它的颜色信息从哪里来呢?看看这里 http://www.cppprog.com/2009/0829/153.html 。SpanGenerator用于从一些复杂的颜色源来获取Span颜色信息,例如位图,渐变色等等。

      这些工具函数包括render_scanlines、render_scanlines_aa_solid等。其实现也相当之简单,通过遍历Rasterizer来生成Scanline,然后对每一个Scanline调用底层渲染层来完成多边形的渲染。

WA_INACTIVE的陷阱

No Comments

      今天往程序里面加了个WM_ACTIVATE消息,在判断具体是获得焦点还是失去焦点时,习惯性的使用如下语句”if( LOWORD(wParam) == WA_INACTIVE)”,结果很是郁闷,怎么都收不到“失去激活”的消息,而WA_ACTIVE和WA_CLICKACTIVE则正常。

      后来看WA_INACTIVE的定义发现“#define     WA_INACTIVE     0”,就是这个0在捣鬼,因为怎么按位与也不可能出现一个1,所以将其改为“if( LOWORD(wParam) == WA_INACTIVE)”即正常,其他Flag不变。

狗日的WM_LBUTTONUP和WM_RBUTTONUP

No Comments

      在众多鼠标消息中,wParam参数包含了一系列Flag,这些Flag通过一些MK_开头的宏来定义,其中MK_LBUTTON、MK_MBUTTON、MK_RBUTTON分别表示左/中/右键被按下。除了标题中的两个消息外,其他鼠标消息以上三个Flag都有效,而WM_LBUTTONUP中MK_LBUTTON标志无效,WM_RBUTTONUP中MK_RBUTTON标志无效(见MSDN)。

      今天就是因为这个问题出了个兴邦级的bug,调了N久。狗日的萎缩消息!!!

QUI开始

No Comments

      一直想自己写套UI框架来练练笔,以便加深对这一块的了解。犹豫了将近半年的时间,今天总算是开工了。几个月前基于Xlib写了个小框架,刚刚能够跑起来,仅仅包含窗口管理和消息循环,没有任何控件支持和绘图支持。这一套框架底层架构基本沿用那里,只是从Xlib移植到Windows。

      关于名字,实在没啥好说的。我个人喜欢简单明了,尤其是容易记忆的名字,既然有GUI一说,那就稍微改改,叫“QUI“咯。Q和G有些类似,也是我名字拼音第一个字母。

      干一件事,总得有一个目标以及具体的规划,给QUI定的目标是一个兼容Windows和Linux(Xlib或基于它的Gtk再说吧,估计QT不大可能),Mac因为一时也不了解先不考虑,嵌入式平台暂不考虑,毕竟PC UI和嵌入式UI设计哲学还是有很大区别的。

      在图形渲染方面,本来是想用那个传说中极度牛B,Google推出来的Skia引擎,不过由于天生驽钝,加上网上关于Skia的资料还相对较少,硬是没有将它攻下来,所以就使用Agg将就一下了。

      对于外设,和普通的UI框架一致,支持鼠标和键盘,不过尽量考虑到未来可能加入其他输入设备的可能,例如比较流行的触摸屏设备。

      控件方面,全部自绘,不过保留对原生控件的接口支持(对其封装,使其看上去和自绘窗口一致)。窗口内部的全部绘图操作都通过绘图引擎Agg实现,不依赖于Gdi等平台相关的API支持。原则上不使用平台内置的控件,不过考虑到richedit、brower等控件相对复杂,自己实现显然不靠谱,所以通过原生控件接口封装使用。

      其他设计要求包括,皮肤支持和动态换肤、国际化和动态语言(如Lua)扩展。遗漏的再慢慢补充,具体的细节再通过开发日志来说明。

      无图不真相,贴个图先,该窗口包含一个控件,自绘了一个太阳光谱。

QQ截图未命名.bmp

WM_MOUSEWHEEL消息

No Comments

      今天调试程序时,发现该消息附带的坐标不是窗口坐标,而是屏幕座标。后来Google了下,发现不仅如此,此消息和它兄弟消息不一样,消息直接发送到具有Focus的控件,而不是鼠标底下的控件。

Older Entries