{
貼圖可以極大的節省CPU時間。呵呵,但這一節費了我比較多的時間: (
因為用到了opengl的輔助函式庫,現在這個函式庫的函數已經很少人用了,但是我還是找到了,感謝zdcnow(磁效應),他給我提供的這個輔助函式庫的delphi版本。在學習本節之前,請大家到網上下載glaux.dll、Glaux.pas文件,並加入專案。
好了,讓我們繼續OPENGL之路.
首先我們要加進SysUtils單元,因為我們這節要用到檔案操作,我們還要將Glaux單元加進來。
然後我們在第一課的基礎上加上幾個變數,xrot , yrot 和zrot 。這些變數用來使立方體繞X、Y、Z軸旋轉。 texture[] 為一個紋理指派儲存空間。如果您需要不只一個的紋理,您應該將數字1改成您所需的數字。
}
VAR
h_RC : HGLRC; // Rendering Context(著色描述表)。
h_DC : HDC; // Device Context(裝置描述表)
h_Wnd : HWND; // 視窗句柄
h_Instance : HINST; // 程式Instance(實例)。
keys : Array[0..255] Of Boolean; // 用於鍵盤例程的陣列
xrot, // X 旋轉量( 新增)
yrot, // Y 旋轉量( 新增)
zrot : GLfloat; // Z 旋轉量( 新增)
Texture : Array[0..1] Of GLuint; // 儲存一個紋理( 新增)
{然後引載入opengl32.dll中的兩個過程,我們要用到他們}
PRocedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
opengl32;
Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
opengl32;
{接下來我們需要增加一個新的函數,用來再入影像,該函數的回傳類型在Glaux.pas中定義如下:
TAUX_RGBImageRec= record
sizeX, sizeY: GLint;
data: pointer;
end;
PTAUX_RGBImageRec= ^TAUX_RGBImageRec;
具體意義會在後面介紹}
Function LoadBmp(filename: pchar): PTAUX_RGBImageRec;
Var
BitmapFile : Thandle; // 檔案句柄
Begin
//接下來檢查檔案名稱是否已提供
If Filename = '' Then // 確保檔案名稱已提供。
result := Nil; // 如果沒提供,回傳NULL
//接著檢查檔案是否存在。
BitmapFile := FileOpen(Filename, fmOpenWrite); //嘗試開啟文件
//如果我們能開啟檔案的話,很顯然檔案是存在的。
If BitmapFile > 0 Then // 檔案存在麼?
Begin
//關閉檔案。
FileClose(BitmapFile); // 關閉句柄
//auxDIBImageLoad(Filename) 讀取圖象資料並將其傳回。
result := auxDIBImageLoadA(filename); //載入點陣圖並傳回指針
End
Else
//如果我們不能開啟文件,我們將返回NiL。
result := Nil; // 如果載入失敗,回傳NiL。
End;
//接下來在建立一個新函數,用來載入紋理貼圖
Function LoadTexture: boolean;
//Status 的變數。我們使用它來追蹤是否能夠載入位圖以及能否創建紋理。
// Status 缺省設為FALSE (表示沒有載入或創建任何東東)。
//TextureImage變數PTAUX_RGBImageRec類型儲存點陣圖的影像記錄。
//次記錄包含位圖的寬度、高度和資料。
Var
Status : boolean;
TextureImage : Array[0..1] Of PTAUX_RGBImageRec;
Begin
Status := false;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // 將指標設為NULL
TextureImage[0] := LoadBMP('Texture.bmp');
If TextureImage[0] <> Nil Then
Begin
Status := TRUE; // 將Status 設為TRUE
//現在使用中TextureImage[0] 的資料來建立紋理。
//glGenTextures(1, texture[0]) 告訴OpenGL我們想要產生一個紋理名字
//(如果您想載入多個紋理,加大數字)。
//glBindTexture(GL_TEXTURE_2D, texture[0]) 告訴OpenGL將紋理名字texture[0] 綁定到紋理目標上。
//2D紋理只有高度(在Y 軸上)和寬度(在X 軸上)。
//主函式將紋理名字指派給紋理資料。
//本例我們告知OpenGL, &texture[0] 處的記憶體已經可用。
//我們創建的紋理將儲存在&texture[0] 的指向的記憶體區域。
glGenTextures(1, texture[0]); // 建立紋理
glBindTexture(GL_TEXTURE_2D, texture[0]); // 使用來自點陣圖資料產生的典型紋理
//下來我們創造真正的紋理。
//下面一行告訴OpenGL此紋理是一個2D紋理( GL_TEXTURE_2D )。
//數字零代表影像的詳細程度,通常就由它為零去了。
//數字三是資料的成分數。因為影像是由紅色數據,綠色數據,藍色數據三種組成組成。
//TextureImage[0].sizeX 是紋理的寬度。
//如果您知道寬度,您可以在這裡填入,但計算機可以輕鬆的為您指出此值。
// TextureImage[0].sizey 是紋理的高度。
//數字零是邊框的值,通常就是零。
// GL_RGB 告訴OpenGL圖像資料由紅、綠、藍三色資料組成。
//GL_UNSIGNED_BYTE 意味著組成影像的資料是無符號位元組類型的。
//最後... TextureImage[0].data 告訴OpenGL紋理資料的來源。
//此例中指向存放在TextureImage[0] 記錄中的資料。
// 產生紋理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data);
//下面的兩行告訴OpenGL在顯示圖片時,
//當它比放大得原始的紋理大(GL_TEXTURE_MAG_FILTER)
//或縮小得比原始得紋理小(GL_TEXTURE_MIN_FILTER)時OpenGL所採用的濾波方式。
//通常這兩種情況我都採用GL_LINEAR。這使得紋理從很遠處到離螢幕很近時都平滑顯示。
//使用GL_LINEAR需要CPU和顯示卡做更多的運算。
//如果您的機器很慢,也許您應該採用GL_NEAREST 。
//過濾的紋理在放大的時候,看起來斑駁的很(馬賽克啦)。
//您也可以結合這兩種濾波方式。近處時使用GL_LINEAR ,遠處時GL_NEAREST 。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波
End;
//現在我們釋放前面用來存放點陣圖資料的記憶體。
//我們先查看點陣圖資料是否存放在處。
//如果是的話,再查看資料是否已經儲存。
//如果已經儲存的話,刪了它。
//接著再釋放TextureImage[0] 影像結構以確保所有的記憶體都能釋放。
If assigned(TextureImage[0]) Then // 紋理是否存在
If assigned(TextureImage[0].data) Then // 紋理影像是否存在
TextureImage[0].data := Nil; // 釋放紋理影像所佔用的內存
TextureImage[0] := Nil; // 釋放圖像結構
// 最後傳回狀態變數。如果一切OK,變數Status 的值為TRUE 。否則為FALSE
result := Status; // 回傳Status
End;