write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
個(gè)人認(rèn)為《 OpenGL Programming Guide 》的第8章是最讓人頭暈的一章,講了很多內(nèi)容,但是很多東西太偏向于純理論的概念及眾多函數(shù)參數(shù)的詳盡闡述,可能因?yàn)檫@個(gè)內(nèi)容本來(lái)就比較難,作者也知道,所以為本章配了全書(shū)最密集的圖示,可是個(gè)人感覺(jué)那些圖實(shí)在是沒(méi)有任何幫助-_-!。
太多的東西和理論我們學(xué)不來(lái),本節(jié)只搞定一件非常重要但是此書(shū)講了半天卻沒(méi)有觸及的事情,從一個(gè)bmp文件中讀取數(shù)據(jù)然后顯示出來(lái)。當(dāng)然,這也不怪作者,畢竟讀取數(shù)據(jù)不再是屬于OpenGL API的一部分,但是僅僅因?yàn)檫@樣,就總是用一堆通過(guò)野蠻的數(shù)組操作生成的惡心黑白圖來(lái)做演示和教學(xué),是不是也太過(guò)了點(diǎn)?
另外,NEHE教程中有載入圖形的相關(guān)章節(jié),單還是使用glaux這個(gè)現(xiàn)在已經(jīng)不再推薦的過(guò)時(shí)庫(kù),已經(jīng)有點(diǎn)不合時(shí)宜了,我不想使用這些,最好的辦法自然是字節(jié)弄明白bitmap文件的格式,直接讀取相關(guān)數(shù)據(jù),然后載入自己的結(jié)構(gòu)使用,這樣可以作為完全的跨平臺(tái)(irrlicht的做法),我又沒(méi)有這樣做的決心,既然是Win32下的OpenGL編程學(xué)習(xí),Win32 API永遠(yuǎn)是我先考慮的,同樣的簡(jiǎn)潔。。。只是別和我討論跨平臺(tái)的問(wèn)題。其實(shí)這個(gè)說(shuō)法值得探討。。。。不關(guān)心跨平臺(tái)為啥要用OpenGL了?-_-!
顯示簡(jiǎn)單的內(nèi)存中的像素?cái)?shù)據(jù)
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};
//這里進(jìn)行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區(qū) 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 (); }
因?yàn)閷?shí)在太簡(jiǎn)單了,簡(jiǎn)單的說(shuō)明一下代碼:
此例中主要有4個(gè)OpenGL API,但是都非常簡(jiǎn)單,因?yàn)闋可娴南嚓P(guān)概念比較少。
glPixelStore*用于指明像素存儲(chǔ)的格式,此例中表示1個(gè)字節(jié)的一個(gè)元素。
Name
glPixelStore — set pixel storage modes
C Specification
void glPixelStoref( GLenum pname,
GLfloat param);
void glPixelStorei( GLenum pname,
GLint param);
此函數(shù)的參數(shù)較多,但是使用起來(lái)卻較簡(jiǎn)單,具體的解釋大家就自己去查了。
glRasterPos* ,glWindowPos* 用于指定開(kāi)始繪制像素的位置,同時(shí),上例也說(shuō)明了指明時(shí)兩個(gè)函數(shù)的區(qū)別,glRasterPos* 確定位置后繪制了2個(gè)F,并且都在窗口的正中間,(0,0)位置,此函數(shù)的位置就是以普通的OpenGL坐標(biāo)系為基準(zhǔn)的,因此,也會(huì)受到OpenGL坐標(biāo)變換的影響。glWindowPos2i是個(gè)比較特殊的函數(shù),因?yàn)樗耆豢紤]OpenGL坐標(biāo)變換,永遠(yuǎn)按窗口的坐標(biāo)系定位,(這點(diǎn)在繪制界面的時(shí)候很有用)雖然實(shí)際的坐標(biāo)定位方式與Windows慣用方式有點(diǎn)區(qū)別,原點(diǎn)不是在左上角而是在左下角,直觀點(diǎn)說(shuō),glWindowPos* 是|_型坐標(biāo)系,坐標(biāo)系的方向遵循了OpenGL坐標(biāo)系的方向(也就是普通笛卡爾坐標(biāo)系的方向)。
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的函數(shù)調(diào)用完全一樣,但是繪制并沒(méi)有重合,因?yàn)锳PI中本身就包含了繪制位置的偏移參數(shù)。
為節(jié)省篇幅僅貼出關(guān)鍵片段,完整源代碼見(jiàn)我博客源代碼的2009-12-28/glPixelDraw 目錄,獲取方式見(jiàn)文章最后關(guān)于獲取博客完整源代碼的說(shuō)明。
OpenGL中位圖文件的顯示
以下圖片來(lái)自于經(jīng)典的《windows圖形編程》一書(shū)。
讀取bitmap文件的數(shù)據(jù)是個(gè)問(wèn)題,其實(shí)bitmap文件本身很簡(jiǎn)單,通過(guò)固定的結(jié)構(gòu)完全解析讀取也不是太難,LaMothe(《Windows游戲編程大師技巧》《3D 游戲編程大師技巧》 )在書(shū)中有介紹,但是,我就不這樣做了,與OpenGL學(xué)習(xí)不是一件事。
如一開(kāi)始描述的一樣,這里通過(guò)Windows API來(lái)完成,以下是Win32的BITMAP結(jié)構(gòu):
/* 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 ;
我們需要的都有了,長(zhǎng),高,實(shí)際的像素。
BITMAP gBmp
;
//OpenGL初始化開(kāi)始 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的函數(shù)原型:
HANDLE LoadImage(
HINSTANCE hinst , LPCTSTR lpszName , UINT uType , int cxDesired , int cyDesired , UINT fuLoad );
初始化的時(shí)候就將圖片讀出來(lái)了,上面就兩個(gè)Win32 API,一個(gè)LoadImage用于加載圖片,GetObject用于獲取信息,需要特別說(shuō)明的是,不要看到有個(gè)type指定圖片類型就感覺(jué)LoadImage很強(qiáng)大。。。。
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.
錯(cuò)覺(jué)吧。。。。。。。。。。。。。。畢竟是Win32 API,你以為D3D API啊。。。。。。。。。。呵呵,即使是MFC中的CImage都是弱的不行,還期望這個(gè)函數(shù)啊。。。。。。。。。。。。。
有了數(shù)據(jù)就好說(shuō)了,顯示貝。
//這里進(jìn)行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區(qū) 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函數(shù)并通過(guò)圖片長(zhǎng)寬的計(jì)算,將圖片顯示在窗口的中間。
哈。。。。。。。。。。學(xué)習(xí)了這么久的OpenGL,還是第一次利用API實(shí)現(xiàn)圖片的繪制(的確有點(diǎn)晚),看慣了線框和實(shí)心體,再看看圖片就是不一樣。。。。。。。。。。(事實(shí)上,這樣的繪制過(guò)程通過(guò)Win32 API來(lái)實(shí)現(xiàn)實(shí)在再簡(jiǎn)單不過(guò)了,但是誰(shuí)叫我們學(xué)習(xí)的是OpenGL呢,呵呵)
這里只多了一個(gè)函數(shù):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.
這里都沒(méi)有什么好奇怪的,我唯一奇怪的是,對(duì)于Windows下的圖片來(lái)說(shuō),OpenGL指定繪制的時(shí)候type竟然是GL_BGR而不是GL_RGB。。。有高人出來(lái)解釋一下。
另外,我們還可以通過(guò)glPixelZoom函數(shù)來(lái)縮放圖片,比如下列代碼就分別將圖片橫向擴(kuò)大2倍,縱向擴(kuò)大1.5倍。
//這里進(jìn)行所有的繪圖工作 void SceneShow ( GLvoid ) { glClear ( GL_COLOR_BUFFER_BIT ); // 清空顏色緩沖區(qū) 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 (); }
為節(jié)省篇幅僅貼出關(guān)鍵片段,完整源代碼見(jiàn)我博客源代碼的2009-12-28/glBitmapTest 目錄,獲取方式見(jiàn)文章最后關(guān)于獲取博客完整源代碼的說(shuō)明。
本系列其他文章見(jiàn)OpenGL專題 《 Win32 OpenGL系列專題 》
參考資料
1. 《 OpenGL Reference Manual 》,OpenGL參考手冊(cè)
2. 《OpenGL 編程指南》(《 OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波譯,機(jī)械工業(yè)出版社
3. 《Nehe OpenGL Tutorials》,Nehe著,在 http://nehe.gamedev.net/ 上可以找到教程及相關(guān)的代碼下載,(有PDF版本教程下載)Nehe自己還做了一個(gè)面向?qū)ο蟮目蚣埽鳛檠菔境绦騺?lái)說(shuō),這樣的框架非常合適。也有 中文版 ,各取所需吧。
4.《 [游戲開(kāi)發(fā)]OpenGL中用bmp圖片做紋理貼圖的三種方法 》
完整源代碼獲取說(shuō)明
由于篇幅限制,本文一般僅貼出代碼的主要關(guān)心的部分,代碼帶工程(或者makefile)完整版(如果有的話)都能用Mercurial在Google Code中下載。文章以博文發(fā)表的日期分目錄存放,請(qǐng)直接使用Mercurial克隆下庫(kù):
https://blog-sample-code.jtianling.googlecode.com/hg/
Mercurial使用方法見(jiàn)《 分布式的,新一代版本控制系統(tǒng)Mercurial的介紹及簡(jiǎn)要入門(mén) 》
要是僅僅想瀏覽全部代碼也可以直接到google code上去看,在下面的地址:
http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code
原創(chuàng)文章作者保留版權(quán) 轉(zhuǎn)載請(qǐng)注明原作者 并給出鏈接
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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