程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi下OpenGL2d繪圖(05)-畫圖片Bmp,

Delphi下OpenGL2d繪圖(05)-畫圖片Bmp,

編輯:Delphi

Delphi下OpenGL2d繪圖(05)-畫圖片Bmp,


一、前言

找了不少資料,要畫圖片要先處理一下,需要引用別的單元,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_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  // TBitmap的圖像數據在內存中是按行倒序連續存放的,通過TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即圖像緩沖區地址
  // bmp圖片的顏色是按b g r存儲的,所以要選 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.按流程,我們先把圖片加載到程序裡,獲取相關的圖片信息。

將圖片加載到紋理中,有幾種方法,網上有人寫了,建議參考學習:http://www.cnblogs.com/IamEasy_Man/archive/2009/12/14/1624062.html

在delphi中加載一張位圖是很簡單的,可以通過以下方式加載:

1).通過輔助庫的auxDIBImageLoadA函數加載圖片,返回是一個PTAUX_RGBImageRec數據指針,DIB數據格式為RGB。我沒找到辦法在使用完釋放內存的辦法。

  // RGB數據的結構體
  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都無法操作這個指針 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,                        // 數據的成分數。因為圖像是由紅,綠,藍三種組成 默認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_TEXTURE_MAG_FILTER, GL_LINEAR);  // 線形濾波

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_BUFFER_BIT);  

  l := 10;
  t := 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);
  glTexCoord2f(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,            // 紋理是一個2D紋理 GL_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_TEXTURE_MAG_FILTER, GL_LINEAR);  // 線形濾波

  // 以下是繪圖,利用一個四邊形,繪制圖片
  
  // 啟用紋理映射
  if glIsEnabled(GL_TEXTURE_2D) = 0 then
    glEnable(GL_TEXTURE_2D);
  // 清空緩沖區
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);  

  l := 10;
  t := 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);
  glTexCoord2f(0, 0);
  glVertex2f(l, t + w);
  glEnd();

  Bmp.Free;
  SwapBuffers(FDC);
end;

效果如下:

源碼下載:OpenGL_05.zip,包含Gl.pas與Glaux.pas

2014-07-10




  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved