作者
魏永明
主題七
MiniGUI
引入的新 GDI 功能和函數之二
引言
我們在本系列主題五中曾經詳細描述了在 MiniGUI
版本開發過程中添加的新 GDI 功能和函數
這些接口首次出現在版本
Pre
當中
目前 MiniGUI
Pre
版本已經發布
該版本中的新 GDI 接口趨於穩定
相對
Pre
版本而言
又新增了若干高級圖形接口
這些接口涉及到直線和曲線生成器
復雜曲線的繪制
封閉曲線填充
復雜區域的創建
直接的顯示緩沖區訪問
YUV 覆蓋和 Gamma 校正等等
本文將就這些主題詳細描述各個接口的用法
曲線和填充生成器
在一般的圖形系統中
通常給用戶提供若干用於進行直線或者復雜曲線
比如圓弧
橢圓和樣條曲線的繪圖函數
用戶可以通過這些函數進行繪圖
但不能利用這些系統中已有的曲線生成算法完成其他的工作
在 MiniGUI 新的 GDI 接口設計當中
我們采用了一種特殊的設計方法來實現曲線和封閉曲線的填充
這種方法非常靈活
而且給用戶提供了直接使用系統內部算法的機會
)系統中定義了若干用來生成直線和曲線的函數
我們稱之為
曲線生成器
)用戶在調用生成器之前
需要定義一個回調函數
並將函數地址傳遞給曲線生成器
曲線生成器在生成了一個曲線上的點或者封閉曲線中的一條水平填充線時
將調用這個回調函數
)用戶可以在回調函數當中完成針對新的點或者新的水平填充線的操作
對 MiniGUI 繪圖函數來說
就是完成繪圖工作
)因為回調函數在生成器的運行過程中不斷調用
為了保持一致的上下文環境
系統允許用戶在調用曲線生成器時傳遞一個表示上下文的指針
生成器將把該指針傳遞給回調函數
下面將分小節講述目前的 MiniGUI 版本所提供的曲線和填充生成器
直線剪切器和直線生成器
直線剪切器和生成器的原型如下
/* Line clipper */
BOOL GUIAPI LineClipper (const RECT* cliprc
int *_x
int *_y
int *_x
int *_y
);
/* Line generators */
typedef void (* CB_LINE) (void* context
int stepx
int stepy);
void GUIAPI LineGenerator (void* context
int x
int y
int x
int y
CB_LINE cb);
直線剪切器並不是生成器
它用於對給定的直線進行剪切操作
cliprc 是給定的直線
而 _x
_y
_x
和 _y
傳遞要剪切的直線起始端點
並通過這些指針返回剪切之後的直線起始端點
MiniGUI 內部使用了 Cohen
Sutherland 算法
LineGenerator 是采用 Breshenham 算法的生成器
該生成器從給定直線的起始端點開始
每生成一個點調用一次 cb 回調函數
並傳遞上下文 context
以及新的點相對於上一個點的步進值或者差量
比如
傳遞 stepx =
stepy =
表示新的點比上一個點在 X 軸上前進一步
而在 Y 軸上保持不變
回調函數可以在步進值基礎上實現某種程度上的優化
圓生成器
MiniGUI 定義的圓生成器原型如下
/* Circle generator */
typedef void (* CB_CIRCLE) (void* context
int x
int x
int y);
void GUIAPI CircleGenerator (void* context
int sx
int sy
int r
CB_CIRCLE cb);
首先要指定圓心坐標以及半徑
並傳遞上下文信息以及回調函數
每生成一個點
生成器將調用一次 cb 回調函數
並傳遞三個值
x
x
和 y
這三個值實際表示了圓上的兩個點
(x
y) 和 (x
y)
因為圓的對稱性
生成器只要計算圓上的四分之一圓弧點即可得出圓上所有的點
橢圓生成器
橢圓生成器和圓生成器類似
原型如下
/* Ellipse generator */
typedef void (* CB_ELLIPSE) (void* context
int x
int x
int y);
void GUIAPI EllipseGenerator (void* context
int sx
int sy
int rx
int ry
CB_ELLIPSE cb);
首先要指定橢圓心坐標以及 X 軸和 Y 軸半徑
並傳遞上下文信息以及回調函數
每生成一個點
生成器將調用一次 cb 回調函數
並傳遞三個值
x
x
和 y
這三個值實際表示了橢圓上的兩個點
(x
y) 和 (x
y)
因為橢圓的對稱性
生成器只要計算橢圓上的二分之一圓弧點即可得出橢圓上所有的點
圓弧生成器
MiniGUI 定義的圓弧生成器如下所示
/* Arc generator */
typedef void (* CB_ARC) (void* context
int x
int y);
void GUIAPI ArcGenerator (void* context
int sx
int sy
int r
fixed ang
fixed ang
CB_ARC cb);
首先要指定圓弧的圓心
半徑
起始弧度和終止弧度
需要注意的是
起始弧度和終止弧度是采用定點數表示的
而不是浮點數
並且是弧度而不是角度
然後傳遞 cb 回調函數
每生成一個圓弧上的點
該函數將調用回調函數
並傳遞新點的坐標值 (x
y)
有關定點數的信息
請參閱本系列
主題六
MiniGUI 提供的非 GUI/GDI 接口
一文
垂直單調多邊形生成器
通常而言
多邊形有凸多邊形和凹多邊形之分
這裡的垂直單調多邊形
是為了優化多邊形填充算法而針對計算機圖形特點而提出的一種特殊多邊形
這種多邊形的定義如下
垂直單調多邊形是指
多邊形的邊和計算機屏幕上的所有水平掃描線
只能有一個或者兩個交點
不會有更多交點
圖
給出了凸多邊形
凹多邊形和垂直單調多邊形的幾個示例
需要注意的是
凸多邊形一定是垂直單調多邊形
但垂直單調多邊形可以是凹多邊形
顯然
普通的多邊形填充算法需要判斷多邊形邊和每條屏幕掃描線之間的交點個數
而垂直單調多邊形則可以免去這一判斷
所以可以大大提高多邊形填充的速度
MiniGUI 所定義的垂直單調多邊形相關函數原型如下
/* To determine whether the specified Polygon is Monotone Vertical Polygon */
BOOL GUIAPI PolygonIsMonotoneVertical (const POINT* pts
int vertices);
/* Monotone vertical polygon generator */
typedef void (* CB_POLYGON) (void* context
int x
int x
int y);
BOOL GUIAPI MonotoneVerticalPolygonGenerator (void* context
const POINT* pts
int vertices
CB_POLYGON cb);
PolygonIsMonotoneVertical 用來判斷給定的多邊形是否是垂直單調多邊形
而 MonotoneVerticalPolygonGenerator 函數是垂直多邊形生成器
在 MiniGUI 當中
多邊形是由組成多邊形的頂點來表示的
pts 表示頂點數組
而 vertices 表示頂點個數
生成器生成的實際是填充多邊形的每一條水平線
端點為 (x
y) 和 (x
y)
一般矩形生成器
MiniGUI 還提供了一般的矩形生成器
該生成器可以處理凸多邊形
也可以處理凹多邊形
原型如下
/* General polygon generator */
typedef void (* CB_POLYGON) (void* context
int x
int x
int y);
BOOL GUIAPI PolygonGenerator (void* context
const POINT* pts
int vertices
CB_POLYGON cb);
和垂直單調多邊形生成器一樣
該函數生成的是填充多邊形的每一條水平掃描線
x
是水平線的起始X坐標
x
是水平線的終止 X 坐標
y 是水平線的 Y 坐標值
填注生成器
填注(flood filling)生成器比較復雜
這個函數在 MiniGUI 內部用於 FloodFill 函數
我們知道
FloodFill 函數從給定的起始位置開始
以給定的顏色向四面八方填充某個區域(像水一樣蔓延
因此叫 Flood Filling)
一直到遇到與給定起始位置的象素值不同的點為止
因此
在這一過程中
我們需要兩個回調函數
一個回調函數用來判斷蔓延過程中遇到的點的象素值是否和起始點相同
另外一個回調函數用來生成填充該區域的水平掃描線
在進行繪圖時
該函數比較的是象素值
但實際上
該函數也可以比較任何其他值
從而完成特有的蔓延動作
這就是將填注生成器單獨出來的初衷
MiniGUI 如下定義填注生成器
/* General Flood Filling generator */
typedef BOOL (* CB_EQUAL_PIXEL) (void* context
int x
int y);
typedef void (* CB_FLOOD_FILL) (void* context
int x
int x
int y);
BOOL GUIAPI FloodFillGenerator (void* context
const RECT* src_rc
int x
int y
CB_EQUAL_PIXEL cb_equal_pixel
CB_FLOOD_FILL cb_flood_fill);
cb_equal_pixel 被調用
以便判斷目標點的象素值是否和起始點一樣
起始點的象素值可以通過 context 來傳遞
cb_flood_fill 函數用來填充一條掃描線
傳遞的是水平掃描線的端點
即(x
y) 和 (x
y)
曲線和填充生成器的用法
曲線和填充生成器的用法非常簡單
為了對曲線和填充生成器有個更好的了解
我們首先看 MiniGUI 內部是如何使用曲線和填充生成器的
下面的程序段來自 MiniGUI 的 FloodFill 函數(src/newgdi/flood
c)
static void _flood_fill_draw_hline (void* context
int x
int x
int y)
{
PDC pdc = (PDC)context;
RECT rcOutput = {MIN (x
x
)
y
MAX (x
x
) +
y +
};
ENTER_DRAWING (pdc
rcOutput);
From:http://tw.wingwit.com/Article/program/Oracle/201311/16987.html