Delphi使用OpenGL2d繪圖之畫(huà)圖片Bmp的方法
一、前言:
對(duì)于Delphi來(lái)說(shuō),要畫(huà)圖片要先處理一下,需要引用別的單元,而Delphi中沒(méi)帶,需要另外下載Gl.pas。網(wǎng)上常見(jiàn)自帶的OpenGl單元封裝的是1.0版的,有此函數(shù)未聲明。網(wǎng)上可以找到Gl.pas單元。另外需要一個(gè)Glaux.pas單元與glaux.dll,是輔助庫(kù)。在本文最后會(huì)提供下載。
二、實(shí)現(xiàn)流程:
繪畫(huà)圖片需要以下幾個(gè)流程。Window本身的繪圖是以位圖為基礎(chǔ)的,png,jpg等,繪畫(huà)時(shí),可以轉(zhuǎn)為bmp再畫(huà)。
1.加載bmp圖片:使用auxDIBImageLoadA或其他函數(shù)
2.轉(zhuǎn)換為紋理:glGenTextures -> glBindTexture -> glTexImage2D, glTexParameteri用于設(shè)置相關(guān)參數(shù)
3.繪制紋理:glBindTexture -> glBegin(GL_QUADS) -> glTexCoord2f -> glVertex2f -> glEnd
三、利用glDrawPixels函數(shù)繪圖
glDrawPixels共有如下5個(gè)參數(shù):
width: 表圖像的寬度
height: 表圖像的高度
format:表圖像的數(shù)據(jù)存儲(chǔ)格式
atype: 未知
pixels: DIB數(shù)據(jù)的指針
示例代碼如下:
procedure TForm1.Draw; var Bmp: TBitmap; begin Bmp := TBitmap.Create; Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp'); // 清空緩沖區(qū) glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // TBitmap的圖像數(shù)據(jù)在內(nèi)存中是按行倒序連續(xù)存放的,通過(guò)TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即圖像緩沖區(qū)地址 // bmp圖片的顏色是按b g r存儲(chǔ)的,所以要選 GL_BGR_EXT做為參數(shù) glDrawPixels(Bmp.Width, Bmp.Height, GL_BGR_EXT, GL_UNSIGNED_BYTE, Bmp.ScanLine[Bmp.Height - 1]); SwapBuffers(FDC); Bmp.Free; end;
用以上方法繪制圖片不需要啟用紋理映射,可以通過(guò)glPixelZoom函數(shù)來(lái)縮放圖片,顯示位置在窗口的左下角(暫時(shí)不知道如何改變圖像位置。)
三、使用紋理繪圖
想要按制圖片的顯示位置與放大縮小,可以用以下方法。
1.按流程,我們先把圖片加載到程序里,獲取相關(guān)的圖片信息。
將圖片加載到紋理中,可參考本站:http://www.dhdzp.com/article/52125.htm
在delphi中加載一張位圖是很簡(jiǎn)單的,可以通過(guò)以下方式加載:
(1)通過(guò)輔助庫(kù)的auxDIBImageLoadA函數(shù)加載圖片,返回是一個(gè)PTAUX_RGBImageRec數(shù)據(jù)指針,DIB數(shù)據(jù)格式為RGB。
// RGB數(shù)據(jù)的結(jié)構(gòu)體 TAUX_RGBImageRec = record sizeX, sizeY: GLint; data: pointer; end; PTAUX_RGBImageRec = ^TAUX_RGBImageRec; var p: PTAUX_RGBImageRec; begin p := auxDIBImageLoadA(PAnsiChar(ExtractFilePath(ParamStr(0)) + '1.bmp')); // p 怎么釋放? Dispose與Freemem都無(wú)法操作這個(gè)指針 end;
(2)通過(guò)TBitmap.LoadFromFile加載圖片。Delphi自帶,從效率上對(duì)比,與auxDIBImageLoadA性能是一樣的,但DIB數(shù)據(jù)格式為BGR,DIB指針為T(mén)Bitmap.ScanLine[Bmp.Height - 1]
var Bmp: TBitmap; begin Bmp := TBitmap.Create; TBitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp'); // do something // 用完釋放 Bmp.Free; end;
2.創(chuàng)建紋理,其中的glGenTextures與glBindTexture,在Gl.pas中。
// 創(chuàng)建紋理區(qū)域 glGenTextures(1, @texture); // 綁定紋理區(qū)域 glBindTexture(GL_TEXTURE_2D, texture); // 使用位圖創(chuàng)建圖像紋理 glTexImage2D( GL_TEXTURE_2D, // 紋理是一個(gè)2D紋理 GL_TEXTURE_2D 0, // 圖像的詳細(xì)程度 默認(rèn) 0 3, // 數(shù)據(jù)的成分?jǐn)?shù)。因?yàn)閳D像是由紅,綠,藍(lán)三種組成 默認(rèn)3 Bmp.Width, // 紋理的寬度 Bmp.Height, // 紋理的高度 0, // 邊框的值 默認(rèn) 0 GL_BGR_EXT, // 數(shù)據(jù)格式 bmp使用 bgr GL_UNSIGNED_BYTE, // 組成圖像的數(shù)據(jù)是無(wú)符號(hào)字節(jié)類型的 Bmp.ScanLine[Bmp.Height - 1] // DIB數(shù)據(jù)指針 ); // 下面兩行是讓opengl在放大原始的紋理大(GL_TEXTURE_MAG_FILTER)或縮小原始紋理(GL_TEXTURE_MIN_FILTER)時(shí)OpenGL采用的濾波方式。 // GL_LINEAR 使用線性濾波,可以把圖片處理處平滑,但需要更多的內(nèi)存與CPU glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波
3.繪制紋理
繪制紋理之前,必須通知OpenGL開(kāi)啟紋理映射glEnable(GL_TEXTURE_2D)。開(kāi)啟后,非紋理的繪制將不起作用。用完記得關(guān)閉就可以了。
// 以下是繪圖,利用一個(gè)四邊形,繪制圖片 // 啟用紋理映射 if glIsEnabled(GL_TEXTURE_2D) = 0 then glEnable(GL_TEXTURE_2D); // 清空緩沖區(qū) glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); l := 10; t := 10; w := 200; // 放大為200*200的圖片 // 選擇紋理 如果場(chǎng)景中使用多個(gè)紋理,不能在glBegin() 和 glEnd() 之間綁定紋理 glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); // glTexCoord2f 的第一個(gè)參數(shù)是X坐標(biāo)。 // 0.0是紋理的左側(cè)。 0.5是紋理的中點(diǎn), 1.0是紋理的右側(cè)。 // glTexCoord2f 的第二個(gè)參數(shù)是Y坐標(biāo)。 // 0.0是紋理的底部。 0.5是紋理的中點(diǎn), 1.0是紋理的頂部。 glTexCoord2f(0, 1); glVertex2f(l, t); glTexCoord2f(1, 1); glVertex2f(l + w, t); glTexCoord2f(1, 0); glVertex2f(l + w, t + w); glTexCoord2f(0, 0); glVertex2f(l, t + w); glEnd();
以上的繪制就結(jié)束了,以下是Draw中完整的代碼,可以不引用輔助庫(kù)Glaux.pas
procedure TForm1.Draw; var Bmp: TBitmap; texture: GLuint; l, t, w: Integer; begin Bmp := TBitmap.Create; Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp'); // 創(chuàng)建紋理區(qū)域 glGenTextures(1, @texture); // 綁定紋理區(qū)域 glBindTexture(GL_TEXTURE_2D, texture); // 使用位圖創(chuàng)建圖像紋理 glTexImage2D( GL_TEXTURE_2D, // 紋理是一個(gè)2D紋理 GL_TEXTURE_2D 0, // 圖像的詳細(xì)程度 默認(rèn) 0 3, // 數(shù)據(jù)的成分?jǐn)?shù)。因?yàn)閳D像是由紅,綠,藍(lán)三種組成 默認(rèn)3 Bmp.Width, // 紋理的寬度 Bmp.Height, // 紋理的高度 0, // 邊框的值 默認(rèn) 0 GL_BGR_EXT, // 數(shù)據(jù)格式 bmp使用 bgr GL_UNSIGNED_BYTE, // 組成圖像的數(shù)據(jù)是無(wú)符號(hào)字節(jié)類型的 Bmp.ScanLine[Bmp.Height - 1] // DIB數(shù)據(jù)指針 ); // 下面兩行是讓opengl在放大原始的紋理大(GL_TEXTURE_MAG_FILTER)或縮小原始紋理(GL_TEXTURE_MIN_FILTER)時(shí)OpenGL采用的濾波方式。 // GL_LINEAR 使用線性濾波,可以把圖片處理處平滑,但需要更多的內(nèi)存與CPU glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波 // 以下是繪圖,利用一個(gè)四邊形,繪制圖片 // 啟用紋理映射 if glIsEnabled(GL_TEXTURE_2D) = 0 then glEnable(GL_TEXTURE_2D); // 清空緩沖區(qū) glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); l := 10; t := 10; w := 200; // 放大為200*200的圖片 // 選擇紋理 如果場(chǎng)景中使用多個(gè)紋理,不能在glBegin() 和 glEnd() 之間綁定紋理 glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); // glTexCoord2f 的第一個(gè)參數(shù)是X坐標(biāo)。 // 0.0是紋理的左側(cè)。 0.5是紋理的中點(diǎn), 1.0是紋理的右側(cè)。 // glTexCoord2f 的第二個(gè)參數(shù)是Y坐標(biāo)。 // 0.0是紋理的底部。 0.5是紋理的中點(diǎn), 1.0是紋理的頂部。 glTexCoord2f(0, 1); glVertex2f(l, t); glTexCoord2f(1, 1); glVertex2f(l + w, t); glTexCoord2f(1, 0); glVertex2f(l + w, t + w); glTexCoord2f(0, 0); glVertex2f(l, t + w); glEnd(); Bmp.Free; SwapBuffers(FDC); end;
本實(shí)例完整代碼可點(diǎn)此下載。
相關(guān)文章
Delphi之Pascal語(yǔ)言中的關(guān)鍵字及保留字匯總
這篇文章主要介紹了Delphi之Pascal語(yǔ)言中的關(guān)鍵字及保留字匯總,需要的朋友可以參考下2014-07-07
Delphi實(shí)現(xiàn)判斷網(wǎng)址是否存在及是否可以打開(kāi)的方法
這篇文章主要介紹了Delphi實(shí)現(xiàn)判斷網(wǎng)址是否存在及是否可以打開(kāi)的方法,需要的朋友可以參考下2014-07-07
Delphi實(shí)現(xiàn)Listbox中的item根據(jù)內(nèi)容顯示不同顏色的方法
這篇文章主要介紹了Delphi實(shí)現(xiàn)Listbox中的item根據(jù)內(nèi)容顯示不同顏色的方法,需要的朋友可以參考下2014-07-07
Delphi實(shí)現(xiàn)毫秒級(jí)別的倒計(jì)時(shí)實(shí)例代碼
這篇文章主要介紹了Delphi實(shí)現(xiàn)毫秒級(jí)別的倒計(jì)時(shí)實(shí)例代碼,需要的朋友可以參考下2014-07-07
解決delphi TAdoQuery組件的close方法導(dǎo)致”列名無(wú)效“錯(cuò)誤的問(wèn)題
今天小編就為大家分享一篇解決delphi TAdoQuery組件的close方法導(dǎo)致”列名無(wú)效“錯(cuò)誤的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
delphi中exit,abort,break,continue的區(qū)別介紹
本文詳細(xì)介紹下delphi中表示跳出的有break,continue, exit,abort, halt, runerror的區(qū)別,感興趣的朋友可以參考下哈,希望對(duì)你學(xué)習(xí)跳出有所幫助2013-04-04

