write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
個人認為《 OpenGL Programming Guide 》的第8章是最讓人頭暈的一章,講了很多內容,但是很多東西太偏向于純理論的概念及眾多函數參數的詳盡闡述,可能因為這個內容本來就比較難,作者也知道,所以為本章配了全書最密集的圖示,可是個人感覺那些圖實在是沒有任何幫助-_-!。
太多的東西和理論我們學不來,本節只搞定一件非常重要但是此書講了半天卻沒有觸及的事情,從一個bmp文件中讀取數據然后顯示出來。當然,這也不怪作者,畢竟讀取數據不再是屬于OpenGL API的一部分,但是僅僅因為這樣,就總是用一堆通過野蠻的數組操作生成的惡心黑白圖來做演示和教學,是不是也太過了點?
另外,NEHE教程中有載入圖形的相關章節,單還是使用glaux這個現在已經不再推薦的過時庫,已經有點不合時宜了,我不想使用這些,最好的辦法自然是字節弄明白bitmap文件的格式,直接讀取相關數據,然后載入自己的結構使用,這樣可以作為完全的跨平臺(irrlicht的做法),我又沒有這樣做的決心,既然是Win32下的OpenGL編程學習,Win32 API永遠是我先考慮的,同樣的簡潔。。。只是別和我討論跨平臺的問題。其實這個說法值得探討。。。。不關心跨平臺為啥要用OpenGL了?-_-!
顯示簡單的內存中的像素數據
GLubyte rasters
[24] = {
0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0};
//這里進行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區 glColor3f (1.0, 0.0, 0.0); glPixelStorei ( GL_UNPACK_ALIGNMENT , 1); // Pixel Storage Mode (Word Alignment / 1 Bytes) glRasterPos2f (0, 0); glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters ); glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters ); glWindowPos2i (0, 0); glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters ); glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters ); glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters ); glFlush (); }
因為實在太簡單了,簡單的說明一下代碼:
此例中主要有4個OpenGL API,但是都非常簡單,因為牽涉的相關概念比較少。
glPixelStore*用于指明像素存儲的格式,此例中表示1個字節的一個元素。
Name
glPixelStore — set pixel storage modes
C Specification
void glPixelStoref( GLenum pname,
GLfloat param);
void glPixelStorei( GLenum pname,
GLint param);
此函數的參數較多,但是使用起來卻較簡單,具體的解釋大家就自己去查了。
glRasterPos* ,glWindowPos* 用于指定開始繪制像素的位置,同時,上例也說明了指明時兩個函數的區別,glRasterPos* 確定位置后繪制了2個F,并且都在窗口的正中間,(0,0)位置,此函數的位置就是以普通的OpenGL坐標系為基準的,因此,也會受到OpenGL坐標變換的影響。glWindowPos2i是個比較特殊的函數,因為它完全不考慮OpenGL坐標變換,永遠按窗口的坐標系定位,(這點在繪制界面的時候很有用)雖然實際的坐標定位方式與Windows慣用方式有點區別,原點不是在左上角而是在左下角,直觀點說,glWindowPos* 是|_型坐標系,坐標系的方向遵循了OpenGL坐標系的方向(也就是普通笛卡爾坐標系的方向)。
glRasterPos — specify the raster position for pixel operations
glWindowPos — specify the raster position in window coordinates for pixel operations
為了更清楚的看到glWindowPos* 的確定性及glRasterPos* 的可變性,這里我加入glTranslate引入的偏移,(glTranslatef(0.5, 0.0, 0.0);),可以看到glRasterPos* 確定的位置變了,glWindowPos* 的還是老地方。
另外,需要注意的是,上面繪制F的函數調用完全一樣,但是繪制并沒有重合,因為API中本身就包含了繪制位置的偏移參數。
為節省篇幅僅貼出關鍵片段,完整源代碼見我博客源代碼的2009-12-28/glPixelDraw 目錄,獲取方式見文章最后關于獲取博客完整源代碼的說明。
OpenGL中位圖文件的顯示
以下圖片來自于經典的《windows圖形編程》一書。
讀取bitmap文件的數據是個問題,其實bitmap文件本身很簡單,通過固定的結構完全解析讀取也不是太難,LaMothe(《Windows游戲編程大師技巧》《3D 游戲編程大師技巧》 )在書中有介紹,但是,我就不這樣做了,與OpenGL學習不是一件事。
如一開始描述的一樣,這里通過Windows API來完成,以下是Win32的BITMAP結構:
/* Bitmap Header Definition */ typedef struct tagBITMAP { LONG bmType ; LONG bmWidth ; LONG bmHeight ; LONG bmWidthBytes ; WORD bmPlanes ; WORD bmBitsPixel ; LPVOID bmBits ; } BITMAP , * PBITMAP , NEAR * NPBITMAP , FAR * LPBITMAP ;
BITMAP gBmp
;
//OpenGL初始化開始 void SceneInit ( int w , int h ) { GLenum err = glewInit (); if ( err != GLEW_OK ) { MessageBox ( NULL , _T ( "Error" ), _T ( "Glew init failed." ), MB_OK ); exit (-1); } HBITMAP hBmp =( HBITMAP ) LoadImage ( NULL , "tiger.bmp" , IMAGE_BITMAP , 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE ); if (! hBmp ) { exit (3); } GetObject ( hBmp , sizeof ( gBmp ), & gBmp ); glClearColor (0.0, 0.0, 0.0, 0.0); }
MSDN的函數原型:
HANDLE LoadImage(
HINSTANCE hinst , LPCTSTR lpszName , UINT uType , int cxDesired , int cyDesired , UINT fuLoad );
初始化的時候就將圖片讀出來了,上面就兩個Win32 API,一個LoadImage用于加載圖片,GetObject用于獲取信息,需要特別說明的是,不要看到有個type指定圖片類型就感覺LoadImage很強大。。。。
uType
[in] Specifies the type of image to be loaded. This parameter can be one of the following values. IMAGE_BITMAP Loads a bitmap. IMAGE_CURSOR Loads a cursor. IMAGE_ICON Loads an icon.
錯覺吧。。。。。。。。。。。。。。畢竟是Win32 API,你以為D3D API啊。。。。。。。。。。呵呵,即使是MFC中的CImage都是弱的不行,還期望這個函數啊。。。。。。。。。。。。。
有了數據就好說了,顯示貝。
//這里進行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區 glPixelStorei ( GL_UNPACK_ALIGNMENT , 4); // Pixel Storage Mode (Word Alignment / 4 Bytes) glWindowPos2d ( ( WIDTH - gBmp . bmWidth ) / 2, ( HEIGHT - gBmp . bmHeight ) / 2 ); glDrawPixels ( gBmp . bmWidth , gBmp . bmHeight , GL_BGR , GL_UNSIGNED_BYTE , gBmp . bmBits ); glFlush (); }
如圖,這里利用glWindowPos2d函數并通過圖片長寬的計算,將圖片顯示在窗口的中間。
哈。。。。。。。。。。學習了這么久的OpenGL,還是第一次利用API實現圖片的繪制(的確有點晚),看慣了線框和實心體,再看看圖片就是不一樣。。。。。。。。。。(事實上,這樣的繪制過程通過Win32 API來實現實在再簡單不過了,但是誰叫我們學習的是OpenGL呢,呵呵)
這里只多了一個函數:glDrawPixels
glDrawPixels — write a block of pixels to the frame buffer
C Specification
void glDrawPixels( GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
const GLvoid * data);
Parameterswidth, height : Specify the dimensions of the pixel rectangle to be written into the frame buffer.
format:Specifies the format of the pixel data.
type:Specifies the data type for data.
data:Specifies a pointer to the pixel data.
這里都沒有什么好奇怪的,我唯一奇怪的是,對于Windows下的圖片來說,OpenGL指定繪制的時候type竟然是GL_BGR而不是GL_RGB。。。有高人出來解釋一下。
另外,我們還可以通過glPixelZoom函數來縮放圖片,比如下列代碼就分別將圖片橫向擴大2倍,縱向擴大1.5倍。
//這里進行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區 glPixelZoom (2.0, 1.5); glPixelStorei ( GL_UNPACK_ALIGNMENT , 4); // Pixel Storage Mode (Word Alignment / 4 Bytes) glWindowPos2d ( ( WIDTH - gBmp . bmWidth ) / 2, ( HEIGHT - gBmp . bmHeight ) / 2 ); glDrawPixels ( gBmp . bmWidth , gBmp . bmHeight , GL_BGR , GL_UNSIGNED_BYTE , gBmp . bmBits ); glFlush (); }
為節省篇幅僅貼出關鍵片段,完整源代碼見我博客源代碼的2009-12-28/glBitmapTest 目錄,獲取方式見文章最后關于獲取博客完整源代碼的說明。
本系列其他文章見OpenGL專題 《 Win32 OpenGL系列專題 》
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機械工業出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個面向對象的框架,作為演示程序來說,這樣的框架非常合適。也有 中文版 ,各取所需吧。
4.《 [游戲開發]OpenGL中用bmp圖片做紋理貼圖的三種方法 》
完整源代碼獲取說明
由于篇幅限制,本文一般僅貼出代碼的主要關心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發表的日期分目錄存放,請直接使用Mercurial克隆下庫:
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見《 分布式的,新一代版本控制系統Mercurial的介紹及簡要入門 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創文章作者保留版權 轉載請注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
