opengles--1.0定點數

OpenGL ES是一個平臺中立的圖形庫,在它能夠工作之前,需要與一個實際的窗口系統關聯起來,這與OpenGL是一樣的。但不一樣的是,這部份工作有標準,這個標準就是EGL。而OpenGL時代在不同平臺上有不同的機制以關聯窗口系統,在Windows上是wgl,在X-Window上是xgl,在Apple OS上是agl等。EGL的工作方式和部份術語都接近於xgl。

OpenGL ES的初始化過程如下圖所示意:

Display → Config → Surface
                        ↑
                      Context
                        ↑
Application → OpenGL Command

1. 獲取Display。
Display代表顯示器,在有些系統上可以有多個顯示器,也就會有多個Display。獲得Display要調用EGLboolean eglGetDisplay(NativeDisplay dpy),參數一般爲 EGL_DEFAULT_DISPLAY 。該參數實際的意義是平臺實現相關的,在X-Window下是XDisplay ID,在MS Windows下是Window DC。

2. 初始化egl。
調用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),該函數會進行一些內部初始化工作,並傳回EGL版本號(major.minor)。

3. 選擇Config。
所爲Config實際指的是FrameBuffer的參數,在MS Windows下對應於PixelFormat,在X-Window下對應Visual。一般用EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config),其中attr_list是以EGL_NONE結束的參數數組,通常以id,value依次存放,對於個別標識性的屬性可以只有 id,沒有value。另一個辦法是用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 來獲得所有config。這兩個函數都會返回不多於config_size個Config,結果保存在config[]中,系統的總Config個數保存 在num_config中。可以利用eglGetConfig()中間兩個參數爲0來查詢系統支持的Config總個數。
Config有衆多的Attribute,這些Attribute決定FrameBuffer的格式和能力,通過eglGetConfigAttrib ()來讀取,但不能修改。

4. 構造Surface。
Surface實際上就是一個FrameBuffer,通過 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr) 來創建一個可實際顯示的Surface。系統通常還支持另外兩種Surface:PixmapSurface和PBufferSurface,這兩種都不 是可顯示的Surface,PixmapSurface是保存在系統內存中的位圖,PBuffer則是保存在顯存中的幀。
Surface也有一些attribute,基本上都可以故名思意, EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL,通過eglSurfaceAttrib()設置、eglQuerySurface()讀取。

5. 創建Context。
OpenGL的pipeline從程序的角度看就是一個狀態機,有當前的顏色、紋理座標、變換矩陣、絢染模式等一大堆狀態,這些狀態作用於程序提交的頂點 座標等圖元從而形成幀緩衝內的像素。在OpenGL的編程接口中,Context就代表這個狀態機,程序的主要工作就是向Context提供圖元、設置狀 態,偶爾也從Context裏獲取一些信息。
用EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)來創建一個Context。

6. 繪製。
應用程序通過OpenGL API進行繪製,一幀完成之後,調用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)來顯示。

初始化OpenGL ES分四步:調用eglInitialize()初始化egl庫,用eglChooseConfig()選擇合適的framebuffer,調用eglCreateWindowSurface創建EGLSurface,用eglCreateContext創建RenderContext(RC)。 其實跟標準OpenGL的初始化過程很接近(選擇PixelFormat或者Visual,再創建Rc),只是多了一個Window Surface的概念。OpenGL標準是不依賴於窗口系統的,這提供了很強的平臺無關性,但也使得我們在Windows下要用wgl初始化,而X-Window下就得學會用xgl,Mac OS X上則是agl。而手持及嵌入式市場的平臺種類不計其數,單是學習各家手機操作系統的接口就是很大的負擔了,更不用說總有一些有志於支持各種尺寸平臺的軟件開發者,所以OpenGL ES提供了Window Surface的抽象,使得移植工作可以基本侷限在重新實現一下建立窗口的過程。

以下是我的EGLWrapper和EGLConfigWrapper:

用法簡單,包含"eglwrapper.h",創建一個EGLWrapper實例,調用init(),第一個參數是利用系統相關API建好的window id,對Windows CE而言就是HWND了,程序結束時再clean()一下就好。

見OpenGL ES系列 之 基本 代碼1和2

OpenGL ES簡化了模型描述,取消了通過在 glBegin/glEnd 之間使用大量glVertex之類的調用來逐點描述模型,統一到使用VertexArray。

下面我們就來畫一個簡單的物體:用三角形拼出的HELLO EGL。該物體的示意圖如下:

照例,先New App:

然後設置一下項目屬性:

共有三處要改的,使得該項目可以利用上如下圖所示的庫和頭文件:

首先是頭文件包含目錄:

然後是庫文件目錄:

最後是OpenGL ES庫: 

OK,環境準備好了,可以寫代碼了。先把我們準備好的OpenGL ES初始化代碼加上:

最後標記出來的那個draw()函數就是實際繪製HELLO EGL的代碼了:

正如前面提過的,我們只能通過VERTEX_ARRAY批量的將模型頂點座標發送給OpenGL ES,爲此需要先glEnableClientState()以打開相關支持。爲了讓世界看上去更美好一點,我還用ColorArray給每個頂點指定了顏色。然後通過glVertexPointer/glColorPointer將數據發送出去,再通過glDrawArrays(GL_TRIANGLES)進行繪製。值得一提的是,目前GLES不支持GL_QUADS。 除了調用glDrawArrays(),OpenGL ES還提供了更爲靈活的glDrawElements()方法,值得看一下規範裏的說明。

剩下的奧密就全在數組helloVertex裏了。其實它的內容已經完全表示的本文開始的那張示意圖裏了,建議您自己推算一下,以熟悉TRIANGLES建模。這個小小的例子也可以利用GL_TRIANG_STRIP得到很大的優化,感興趣的可以練習一下。

代碼如下:
見 OpenGL ES系列 之 基本 代碼3 
可能注意到裏面大量調用了宏Float2Fixed,這是因爲OpenGL ES 1.0 Common Lite Profile只支持定點數,不能直接使用浮點座標。所謂定點數這裏指的是16整數部份+16位小數部份的32位數,也就是OpenGL ES預定義的GLfixed類型。 將單精度浮點數轉成定點數很簡單,直接乘個65536再強制一下類型就行了,這也就是Float2Fixed所做的。

發佈了15 篇原創文章 · 獲贊 11 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章