一、前言:
對Delphi來說,要畫圖片要先處理一下,需要引用別的單元,而Delphi中沒帶,需要另外下載Gl.pas。網路上常見自帶的OpenGl單元封裝的是1.0版的,有此函數未宣告。網路上可以找到Gl.pas單元。另外需要一個Glaux.pas單元與glaux.dll,是輔助庫。在本文最後會提供下載。
二、實現流程:
繪畫圖片需要以下流程。 Window本身的繪圖是以點陣圖為基礎的,png,jpg等,繪畫時,可以轉為bmp再畫。
1.載入bmp圖片:使用auxDIBImageLoadA或其他函數
2.轉換為紋理:glGenTextures -> glBindTexture -> glTexImage2D, glTexParameteri用於設定相關參數
3.繪製紋理:glBindTexture -> glBegin(GL_QUADS) -> glTexCoord2f -> glVertex2f -> glEnd
三、利用glDrawPixels函數繪圖
glDrawPixels共有如下5個參數:
width: 表影像的寬度
height: 表圖像的高度
format:表格影像的資料儲存格式
atype: 未知
pixels: DIB資料的指針
範例程式碼如下:
procedure TForm1.Draw;var Bmp: TBitmap;begin Bmp := TBitmap.Create; Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp'); // 清空緩衝區glClear(GL_COLOR_BUFFGLER_BIT or BUFFClear(GL_COLOR_BUFFGLER_BIT or BUFFClear(GL_COLOR_BUFFGLER_BIT or BU / TBitmap的影像資料在記憶體中是按行倒序連續存放的,透過TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即影像緩衝區位址// bmp圖片的顏色是按bgr儲存的,所以要選GL_BGR_EXT做為參數glDrawPixels(Bmp.Width, Bmp.Height, GL_BGR_EXT, GL_UNSIGNED_BYTE, Bmp.ScanLine[Bmp.Height - 1]); SwapBuffers(FDC); Bmp.Free;end;
用以上方法繪製圖片不需要啟用紋理映射,可以透過glPixelZoom函數來縮放圖片,顯示位置在視窗的左下角(暫時不知道如何改變影像位置。)
三、使用紋理繪圖
想要按製圖片的顯示位置與放大縮小,可以用以下方法。
1.按流程,我們先把圖片載入到程式裡,取得相關的圖片資訊。
將圖片載入到紋理中,可參考本站://www.VeVB.COm/article/52125.htm
在delphi中載入一張點陣圖是很簡單的,可以透過以下方式載入:
(1)透過輔助庫的auxDIBImageLoadA函數載入圖片,返回是一個PTAUX_RGBImageRec資料指針,DIB資料格式為RGB。
// RGB資料的結構體TAUX_RGBImageRec = record sizeX, sizeY: GLint; data: pointer; end; PTAUX_RGBImageRec = ^TAUX_RGBImageRec;var p: PTAVUX_RGBImageRec;begin :EUpptract ptracted (Charpac; '1.bmp')); // p 怎麼釋放? Dispose與Freemem都無法操作這個指標end;
(2)透過TBitmap.LoadFromFile載入圖片。 Delphi自帶,從效率上對比,與auxDIBImageLoadA效能是一樣的,但DIB資料格式為BGR,DIB指標為TBitmap.ScanLine[Bmp.Height - 1]
var Bmp: TBitmap;begin Bmp := TBitmap.Create; TBitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp'); // do something // 用完釋放Bmp.Free;end;
2.創造紋理,其中的glGenTextures與glBindTexture,在Gl.pas。
// 建立紋理區域glGenTextures(1, @texture); // 綁定紋理區域glBindTexture(GL_TEXTURE_2D, texture); // 使用點陣圖建立圖片紋理glTexImage2D( GL_TEXTURE_2D, // 紋理是一個2D紋理GL_TEXTURE_2D 0, //影像的詳細程度預設為0 3, //資料的成分數。資料格式bmp使用bgr GL_UNSIGNED_BYTE, // 組成影像的資料是無符號位元組類型的Bmp.ScanLine[Bmp.Height - 1] // DIB資料指標); // 下面兩行是讓opengl在放大原始的紋理大(GL_TEXTURE_MAG_FILTER)或縮小原始紋理(GL_TEXTURE_MIN_FILTER)時OpenGL採用的濾波方式。 // GL_LINEAR 使用線性濾波,可以把圖片處理處平滑,但需要更多的記憶體與CPU glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波glTexParameteri(GL_TEXTURE_2D, GL_XTParameteri_
3.繪製紋理
繪製紋理之前,必須通知OpenGL開啟紋理映射glEnable(GL_TEXTURE_2D)。開啟後,非紋理的繪製將無法運作。用完記得關閉就可以了。
// 以下是繪圖,利用一個四邊形,繪製圖片// 啟用紋理映射if glIsEnabled(GL_TEXTURE_2D) = 0 then glEnable(GL_TEXTURE_2D); // 清空緩衝區glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFF_BUFFER_BIT or GL_DEPTH_BUFF_BUFFER . 10; w := 200; // 放大為200*200的圖片// 選擇紋理如果場景中使用多個紋理,不能在glBegin() 和glEnd() 之間綁定紋理glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); / / glTexCoord2f 的第一個參數是X座標。 // 0.0是紋理的左側。 0.5是紋理的中點, 1.0是紋理的右邊。 // glTexCoord2f 的第二個參數是Y座標。 // 0.0是紋理的底部。 0.5是紋理的中點, 1.0是紋理的頂部。 glTexCoord2f(0, 1); glVertex2f(l, t); glTexCoord2f(1, 1); glVertex2f(l + w, t); glTexCoord2f(1, 0); glVertex2f(l + w, t + w); glTex2f( 0, 0); glVertex2f(l, t + w); glEnd();
以上的繪製就結束了,以下是Draw中完整的程式碼,可以不引用輔助函式庫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'); / / 建立紋理區域glGenTextures(1, @texture); //綁定紋理區域glBindTexture(GL_TEXTURE_2D, texture); // 使用點陣圖建立影像紋理glTexImage2D( GL_TEXTURE_2D, // 紋理為2DDGL_TEXTURE_2D 0, // 影像的詳細程度預設為0 3, // 資料的紋理成分數。因為影像是由紅,綠,藍三種組成預設3 Bmp.Width, // 紋理的寬度Bmp.Height, // 紋理的高度0, // 邊框的值預設0 GL_BGR_EXT, // 資料格式bmp使用bgr GL_UNSIGNED_BYTE, // 組成影像的資料是無符號位元組類型的Bmp.ScanLine[Bmp.Height - 1] // DIB資料指針); //下面兩行是讓opengl在放大原始的紋理大(GL_TEXTURE_MAG_FILTER)或縮小原始紋理(GL_TEXTURE_MIN_FILTER)時OpenGL採用的濾波方式。 // GL_LINEAR 使用線性濾波,可以把圖片處理處平滑,但需要更多的記憶體與CPU glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波glTexParameteri(GL_TEXTURE_2D, GL_XT +/Toteri_以下是繪圖,利用一個四邊形,繪製圖片// 啟用紋理映射if glIsEnabled(GL_TEXTURE_2D) = 0 then glEnable(GL_TEXTURE_2D); // 清空緩衝區glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUER_BUFFER_BIT or GL_DEPTH_BUER_BIT); w := 200; // 放大為200*200的圖片// 選擇紋理如果場景中使用多個紋理,不能在glBegin() 和glEnd() 之間綁定紋理glBindTexture(GL_TEXTURE_2D, texture); glBegin(GL_QUADS); / / glTexCoord2f 的第一個參數是X座標。 // 0.0是紋理的左側。 0.5是紋理的中點, 1.0是紋理的右邊。 // glTexCoord2f 的第二個參數是Y座標。 // 0.0是紋理的底部。 0.5是紋理的中點, 1.0是紋理的頂部。 glTexCoord2f(0, 1); glVertex2f(l, t); glTexCoord2f(1, 1); glVertex2f(l + w, t); glTexCoord2f(1, 0); glVertex2f(l + w, t + w); glTex2f( 0, 0); glVertex2f(l, t + w); glEnd(); Bmp.Free; SwapBuffers(FDC);end;
本實例完整程式碼可點此下載。