Agg學習筆記


很久前就聽一大牛說起Agg,據說是一個架構極度牛B的2D引擎,沉寂了許久,最后花了兩周時間走馬觀花地把它過了一遍。果然如那大牛所言,這家伙簡直就是巧奪天工的藝術品。今天稍稍瞄了一下Google扔出來的,也宣稱極度牛B的2D引擎Skia,不過個人感覺整體架構大不如Agg漂亮。至於兩者的性能,沒做過比較,只是聽說skia性能表現優異。

      在啃這塊骨頭之前,有兩點建議:

  1. 稍了解一點2D計算機圖形學的知識。這一點在學習Agg的過程中至關重要。

  2. 至少嘗試使用過一種UI框架,諸如Wtl、Mfc等。

      很多人曾說Agg將C++模板用到了爐火純青的地步,不過就我現在的認知,發現其用法也就正規正矩而已,沒用像Boost那樣到處是奇技淫巧,讓人眼花繚亂,找不到北。也許我功底還不行,無法體會高人的用意。

      學習代碼最好的辦法莫過於編譯,看運行效果。下載源碼見這里【http://www.antigrain.com/download/index.html】。Agg源碼包中並沒有對Virtual Studio的直接支持,不過建一個Project,然后將文件拖到里面編譯即可(為了保證可移植性,Agg對標准的支持還是很得力的)。在源碼包中的examples目錄有很多sample,可以另建Project編譯運行看效果。如果想偷懶,可以去這里【http://www.antigrain.com/demo/index.html 】下載編譯好的可執行文件先睹為快。我圍觀了下,效果很“炫”。

      對於開源的東西,找學習資料總是值得先去官網瞄瞄。Agg官網的Reference 不多,不過強烈建議看下這里【http://www.antigrain.com/doc/index.html 】。如果不喜歡看E文,國內有人翻譯(感謝之),質量還不錯,見這里【http://www.cnblogs.com/liyiwen/category/248229.html 】。認真看完第一篇【Basic Renderers】很重要,這篇文章對Agg的底層架構做了清晰的講述,包括RenderBuffer和底層Render,以及兩者的職責分離。這種設計相當好,因為RenderBuffer並不應該知道上層使用何種顏色模式。

      為了對Agg有一個總體的了解(非技術層次),可以參考這里【http://www.cnblogs.com/Kane_zzt/archive/2009/02/15/1271793.html 】。下面這張圖是Agg總體框架的一個總體表述

aa

 

      最后一項Screen Output可以不理會,那是OS的事。Agg處理的最底層是Rendering Buffer 。說白了Rendering Buffer就是一塊內存塊,類似Bitmap。當然這也不一定,它也可以是通過OS API獲得窗口屏幕的映射地址Windows下可以通過GDI函數獲得),或者是FrameBuffer,這樣整個屏幕就可以任意虐,如果沒猜錯的話,Android這鳥毛就這么干的。

      在講Renderers之前,有必要區分兩個概念,圖形和圖像。簡單地講,圖形就是一些點線組成的形狀,可以通過LineTo和MoveTo原語構造。而圖像一般包含形狀和具體的顏色信息。而Readerers【渲染器】就是將圖形信息渲染成圖像。

渲染器層實際上包含三層:

  1. 顏色模式(例如RGBA相關的底層渲染層,這一層直接跟Rendering Buffer日。在這一層,每一個像素的大小、顏色的表示被確定。

  2. Basic Render層,這一層在底層的基礎上進行簡單的裁剪支持。包括單裁剪和多區域裁剪。多區域裁剪性能和區域數量相關。

  3. 應用渲染層,這一層負責渲染具體的線段。在后面會講到,在Agg中任何一個多邊形在光柵化后都會分解成一條條水平線(span),然后依次渲染。

      Scanline Rasterizer就是將任意多邊形(頂點源)分解成水平線,然后交給頂層渲染器渲染。在這一層也可以進行適當的裁剪。反鋸齒功能在這一層引入,Agg中的像素存儲使用浮點型,小數部分即傳說中的亞像素。

      Coordinate conversion pipeline對頂點源進行坐標轉換,我們熟悉的操作如放大/縮小、旋轉等操作都在這一層完成,這部分代碼對數學基礎和算法要求較高,我直接死不鳥跳過。在反走樣插值功能在這一層引入。

      Vertex Source提供光柵化的多邊形,它通過一個迭代器來傳遞頂點。頂點源包括普通的圖形,例如矩形、橢圓、三角形,也包括字體等復雜多邊形。在Linux下被廣泛應用的Freetype庫就是根據字符編碼、其他字符參數來生成一個字體多邊形。這在Agg中也被支持。

      前面提到的都是一些很簡單的矢量繪圖操作,那么Agg對貼圖、漸變色和字體引擎的支持怎么樣呢?

      關於Agg對貼圖的支持,默認包含對bmp格式的支持,Agg源碼內置了對bmp圖片格式的解碼代碼,不過默認並不支持png和jpg等流行格式。我想作者可能是為了保持簡單,不想引入libpng和libjpeg。Agg對所有圖片格式除了解碼部分外,處理是一致的。

      前面一直講到渲染,那何謂渲染呢,說白了就是將一個像素用顏色填充(或混合Blend)。而前面一直忽略了一個問題,就是渲染時用什么顏色來填充(准確的講,並不是填充,而是混合(Blend))特定的像素呢?在Agg中其實也包含一個虛擬的“顏色源”,這個顏色源中的每一個點和“頂點源“中的點一一對應。可以有多種方式構造這個虛擬的顏色源,首先可以指定一種顏色,即純色填充,其次可以通過一定算法來生成”漸變“效果,當然也可以從圖片中獲取。

      說到圖片,其實任何格式在處理前都必須轉化成bitmap格式,所謂的libpng和libjpeg就是干這個事。而bitmap說到底就是一個矩形顏色源。也許有人會疑惑,某些圖片不是支持不規則形狀么,例如png圖片格式。其實png並不支持不規則形狀,而是支持Alpha通道。而2D引擎在渲染時通過Alpha Blend后某些地方就成了透明色,用戶看起來就是不規則形狀了。

      說到這里,Agg對貼圖的支持就很簡單了,從貼圖資源中獲得顏色源,然后使用它渲染特定多邊形(裁剪在這個多邊形中完成)。而對圖片的放大/縮小、旋轉等過程類似Coordinate conversion pipeline對頂點源的操作。

      Agg對漸變的支持和貼圖一致。

      Agg內置對英文字符的支持,我沒有仔細研究源碼,不過可以推測它將所有英文字符的路徑存儲在一個全局(靜態)變量中,渲染前直接通過這些路徑生成頂點,因而效率極高。不過這種方式有幾個不足:

  1. 不支持未存儲的字符,很顯然不要靠他來支持”我日“。

  2. 不支持字體,因為字體路徑表述都是寫死的,除非修改源代碼。

      更高級的字體支持來自字體引擎,Agg支持Windows Gdi的字體接口,也可以使用第三方的字體引擎,例如Freetype。Agg可以通過字體引擎提供的字模來包裝一個頂點源,因而可以將字體渲染成任意效果。此外Agg也可以對字體引擎進一步封裝,實現一個類似貼圖的接口,然后渲染多邊形,不過個人覺得這種方式很別扭,而且渲染時不太靈活。暫時沒有測試兩種方式的效率差別。

      最后,因本人水平有限,錯誤之處在所難免,歡迎指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM