NeHe的OpenGL教程7(Bang翻譯Delphi版)-如何使用光源
在這一課裡,我将教會你如何用光源照亮立方體的六個面,如下圖:

将下圖放在應用程式data目錄下,起名NeHe.bmp
program lesson7a;
{
OpenGL DelphiXE
在這一課裡,我将教會你如何用光源照亮立方體的六個面
注:本單元用到了glaux.dll和glaux.pas,下載下傳位址為:
}
uses
Windows,
Messages,
SysUtils,
OpenGL,
glaux;
procedure glGenTextures(n: GLsizei; var textures: GLuint); stdcall; external opengl32;
procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;
// 全局變量
var
h_Rc: HGLRC; // 視窗着色描述表句柄
h_Dc: HDC; // OpenGL渲染描述表句柄
h_Wnd: HWND; // 儲存我們的視窗句柄
keys: array [0..255] of BOOL; // 儲存鍵盤按鍵的數組
Active: bool = true; // 視窗的活動标志,預設為TRUE
FullScreen:bool = true; // P全屏标志預設,預設設定成全屏模式
rquadx, rquady, rquadz: GLfloat; // 用于立方體的三個方向上的角度
texture: Array[0..0] of GLuint; // 存儲一個紋理
//設定用來建立光源的數組。我們将使用兩種不同的光。
//第一種稱為環境光。環境光來自于四面八方。所有場景中的對象都處于環境光的照射中。
//第二種類型的光源叫做漫射光。漫射光由特定的光源産生,并在您的場景中的對象表面上産生反射。
//處于漫射光直接照射下的任何對象表面都變得很亮,而幾乎未被照射到的區域就顯得要暗一些。
//這樣在我們所建立的木闆箱的棱邊上就會産生的很不錯的陰影效果。
//建立光源的過程和顔色的建立完全一緻。前三個參數分别是RGB三色分量,最後一個是alpha通道參數。
//是以,下面的代碼我們得到的是半亮(0.5f)的白色環境光。如果沒有環境光,未被漫射光照到的地方會變得十分黑暗。
LightAmbient: array[0..3] of GLfloat = (0.5, 0.5, 0.5, 1.0); // 環境光參數
LightDiffuse: array[0..3] of GLfloat = (1.0, 1.0, 1.0, 1.0); // 環境光參數(所有的參數值都取成最大值1.0f。它将照在我們木闆箱的前面,看起來挺好)
//最後我們儲存光源的位置。前三個參數和glTranslate中的一樣。依次分别是XYZ軸上的位移。
//由于我們想要光線直接照射在木箱的正面,是以XY軸上的位移都是0.0f。
//第三個值是Z軸上的位移。為了保證光線總在木箱的前面,是以我們将光源的位置朝着觀察者(就是您哪。)挪出螢幕。
//我們通常将螢幕也就是顯示器的螢幕玻璃所處的位置稱作Z軸的0.0f點。是以Z軸上的位移最後定為2.0f。
//假如您能夠看見光源的話,它就浮在您顯示器的前方。當然,如果木箱不在顯示器的螢幕玻璃後面的話,您也無法看見箱子。
//最後一個參數取為1.0f。這将告訴OpenGL這裡指定的坐标就是光源的位置
LightPosition: array[0..3] of GLfloat = (0.0, 0.0, 2.0, 1.0); // 環境光參數
//載入位圖
function LoadBMP(FileName: PAnsichar):PTAUX_RGBImageRec; // 加載位圖
begin
if not FileExists(Filename) then // 位圖是否存在
begin
Result := nil;
exit;
end;
Result := auxDIBImageLoadA(FileName); // 載入位圖
end;
//加載紋理
function LoadGLTextures: Bool;
TextureImage: array [0..0] of PTAUX_RGBImageRec; // 紋理句柄
Result := false;
ZeroMemory(@TextureImage,sizeof(TextureImage)); // 初始化記憶體
TextureImage[0] := LoadBMP('Data/NeHe.bmp'); // 加載紋理圖檔
if Assigned(TextureImage[0]) then
Result := true;
glGenTextures(1,Texture[0]); // 建立紋理
glBindTexture(GL_TEXTURE_2D,texture[0]); // 使用來自位圖資料生成的典型紋理
glTexImage2D(GL_TEXTURE_2D,0,3,TextureImage[0].sizeX,TextureImage[0].sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage[0].data); // 生成紋理
// gluBuild2DMipmaps(GL_TEXTURE_2D,3,TextureImage[0].sizeX,TextureImage[0].sizeY,GL_RGB,GL_UNSIGNED_BYTE,TextureImage[0].data); // 生成紋理
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 線形濾波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 線形濾波
// 重置OpenGL視窗大小
procedure ReSizeGLScene(Width: GLsizei; Height: GLsizei);
if (Height=0) then // 防止被零除
Height:=1; // 将Height設為1
glViewport(0, 0, Width, Height); // 重置目前的視口(和視窗大小相當)
glMatrixMode(GL_PROJECTION); // 指定"投影矩陣堆棧"是下一個矩陣操作的目标
glLoadIdentity(); // 重置目前指定的矩陣為機關矩陣
gluPerspective(45.0,Width/Height,0.1,100.0); // 設定視口的大小
glMatrixMode(GL_MODELVIEW); // 指定"模型視圖矩陣堆棧"是下一個矩陣操作的目标
glLoadIdentity; // 重置目前指定的矩陣為機關矩陣
// 初始化OpenGL所有設定
function InitGL:bool;
//啟用紋理映射
if not LoadGLTextures then // 加載紋理
Result := false;
glEnable(GL_TEXTURE_2D); // 啟用紋理映射
//啟用光源
//設定環境光的發光量,光源light1開始發光。環境光的發光量存放在LightAmbient數組中。
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient); // 設定環境光
//接下來我們設定漫射光的發光量。它存放在LightDiffuse數組中(全亮度白光)。
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse); // 設定漫射光
//設定光源的位置。位置存放在 LightPosition 數組中(正好位于木箱前面的中心,X-0.0f,Y-0.0f,Z方向移向觀察者2個機關<位于螢幕外面>)。
glLightfv(GL_LIGHT1, GL_POSITION,@LightPosition); // 設定光源位置
//啟用一号光源。我們還沒有啟用GL_LIGHTING,是以您看不見任何光線。記住:隻對光源進行設定、定位、甚至啟用,光源都不會工作。除非我們啟用GL_LIGHTING。
glEnable(GL_LIGHT1); // 啟用一号光源
glEnable(GL_LIGHTING); // 啟用光源
glShadeModel(GL_SMOOTH); // 采用光滑着色(繪制指定兩點間其他點顔色時使用過渡色)
glClearColor(0.0, 0.0, 0.0, 0.5); // 指定清除顔色緩存時使用的顔色值(黑色,0.5透明)
glClearDepth(1.0); // 指定清除深度緩存時使用的深度值
glEnable(GL_DEPTH_TEST); // 啟用深度測試,對深度緩存中符合"深度比較算法"要求的像素進行重繪
glDepthFunc(GL_LEQUAL); // 指定"深度比較算法"
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // 告訴系統對透視進行最高品質修正
Result:=true;
// 繪制OpenGL場景(任何您所想在螢幕上顯示的東東都将在此段代碼中出現)
function DrawGLScene():bool;
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // 根據glClearColor和glClearDepth指定的值清除顔色和深度緩存
glLoadIdentity(); // 重置目前指定的矩陣為機關矩陣
//注意到這次我們将立方體移地更遠離螢幕了。因為立方體的大小要比金字塔大,同樣移入6個機關時,立方體看起來要大的多。這是透視的緣故。越遠的對象看起來越小。
glTranslatef(0.0,0.0,-7.0); // 向螢幕深處移動7個機關
//旋轉
glRotatef(rquadx,1.0,0.0,0.0); // 繞X軸旋轉
glRotatef(rquadY,0.0,1.0,0.0); // 繞Y軸旋轉
glRotatef(rquadZ,0.0,0.0,1.0); // 繞Z軸旋轉
glBegin(GL_QUADS); // 開始繪制立方體
//glNormal3f是這一課的新東西。
//Normal就是法線的意思,所謂法線是指經過面(多邊形)上的一點且垂直于這個面(多邊形)的直線。
//使用光源的時候必須指定一條法線。法線告訴OpenGL這個多邊形的朝向,并指明多邊形的正面和背面。
//如果沒有指定法線,什麼怪事情都可能發生:不該照亮的面被照亮了,多邊形的背面也被照亮....。
//對了,法線應該指向多邊形的外側。
//看着木箱的前面您會注意到法線與Z軸正向同向。
//這意味着法線正指向觀察者-您自己。這正是我們所希望的。
//對于木箱的背面,也正如我們所要的,法線背對着觀察者。
//如果立方體沿着X或Y軸轉個180度的話,前側面的法線仍然朝着觀察者,背面的法線也還是背對着觀察者。
//換句話說,不管是哪個面,隻要它朝着觀察者這個面的法線就指向觀察者。
//由于光源緊鄰觀察者,任何時候法線對着觀察者時,這個面就會被照亮。
//并且法線越朝着光源,就顯得越亮一些。
//如果您把觀察點放到立方體内部,你就會法線裡面一片漆黑。因為法線是向外指的。
//如果立方體内部沒有光源的話,當然是一片漆黑。
// 前面
glNormal3f( 0.0, 0.0, 1.0); // 法線指向觀察者
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // 紋理和立方體的左下
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // 紋理和立方體的右下
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); // 紋理和立方體的右上
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); // 紋理和立方體的左上
// 後面
glNormal3f( 0.0, 0.0,-1.0); // 法線背向觀察者
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); // 紋理和立方體的右下
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); // 紋理和立方體的右上
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // 紋理和立方體的左上
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); // 紋理和立方體的左下
// 頂面
glNormal3f( 0.0, 1.0, 0.0); // 法線向上
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); // 紋理和立方體的左上
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0); // 紋理和立方體的左下
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, 1.0, 1.0); // 紋理和立方體的右下
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // 紋理和立方體的右上
// 底面
glNormal3f( 0.0,-1.0, 0.0); // 法線朝下
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0); // 紋理和立方體的右上
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0); // 紋理和立方體的左上
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // 紋理和立方體的左下
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // 紋理和立方體的右下
// 右面
glNormal3f( 1.0, 0.0, 0.0); // 法線朝右
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); // 紋理和立方體的右下
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); // 紋理和立方體的左上
// 左面
glNormal3f(-1.0, 0.0, 0.0); // 法線朝左
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); // 紋理和立方體的左下
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); // 紋理和立方體的右上
glEnd();
rquadx:= rquadx + 0.35; // 增加立方體x方向的旋轉變量
rquady:= rquady + 0.35; // 增加立方體y方向的旋轉變量
rquadz:= rquadz + 0.35; // 增加立方體z方向的旋轉變量
Result := true;
//處理所有的視窗消息。當我們注冊好視窗類之後,程式跳轉到這部分代碼處理視窗消息
function WndProc(hWnd: HWND; // 視窗的句柄
message: UINT; // 視窗的消息
wParam: WPARAM; // 附加的消息内容
lParam: LPARAM): // 附加的消息内容
LRESULT; stdcall;
scrWidth,scrHeight: integer;
rect: TRect;
if message=WM_SYSCOMMAND then // 監視系統中斷指令
begin
case wParam of
SC_SCREENSAVE,SC_MONITORPOWER: // 屏保要運作或顯示器要進入節電模式
begin
result:=0; // 禁止指令執行
exit;
end;
end;
end;
case message of
WM_CREATE: // 監視建構窗體消息
begin
//獲得螢幕尺寸
scrWidth := GetSystemMetrics(SM_CXSCREEN);
scrHeight := GetSystemMetrics(SM_CYSCREEN);
//擷取窗體尺寸
GetWindowRect(hWnd,&rect);
rect.left := (scrWidth-rect.right) DIV 2;
rect.top := (scrHeight-rect.bottom) DIV 2;
//設定窗體位置(螢幕居中)
SetWindowPos(hWnd,HWND_TOP,rect.left,rect.top,rect.right,rect.bottom,SWP_SHOWWINDOW);
result:=0; // 傳回消息循環
end;
WM_ACTIVATE: // 監視視窗激活消息
begin
if (Hiword(wParam)=0) then // 檢查最小化狀态
active:=true // 程式處于激活狀态
else
active:=false; // 程式不再激活
Result:=0; // 傳回消息循環
WM_CLOSE: // 監視視窗關閉消息
Begin
PostQuitMessage(0); // 發出退出消息
result:=0 // 傳回消息循環
WM_KEYDOWN: // 監視鍵盤有鍵按下消息
keys[wParam] := TRUE; // 如果是,設為TRUE
result:=0; // 傳回消息循環
WM_KEYUP: // 監視鍵盤有鍵擡起消息
keys[wParam] := FALSE; // 如果是,設為FALSE
WM_SIZE: // 監視視窗尺寸改變消息
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // 重置OpenGL視窗大小
end
else
// 其餘無關的消息被傳遞給DefWindowProc,讓Windows自行處理
Result := DefWindowProc(hWnd, message, wParam, lParam);
//正常銷毀視窗(在程式退出之前調用,依次釋放着色描述表,裝置描述表和視窗句柄)
procedure KillGLWindow;
if FullScreen then // 處于全屏模式嗎?
ChangeDisplaySettings(devmode(nil^),0); // 回到原始桌面
showcursor(true); // 顯示滑鼠指針
if h_rc<> 0 then // 擁有OpenGL渲染描述表嗎?
if (not wglMakeCurrent(h_Dc,0)) then // 釋放DC和RC描述表
MessageBox(0,'Release of DC and RC failed.',' 關閉錯誤',MB_OK or MB_ICONERROR);
if (not wglDeleteContext(h_Rc)) then // 删除RC
begin
MessageBox(0,'釋放RC失敗.',' 關閉錯誤',MB_OK or MB_ICONERROR);
h_Rc:=0; // 将RC設為 NULL
end;
if (h_Dc=1) and (releaseDC(h_Wnd,h_Dc)<>0) then // 釋放 DC
MessageBox(0,'釋放DC失敗.',' S關閉錯誤',MB_OK or MB_ICONERROR);
h_Dc:=0; // 将 DC 設為 NULL
if (h_Wnd<>0) and (not destroywindow(h_Wnd))then // 銷毀視窗
MessageBox(0,'釋放視窗句柄失敗.',' 關閉錯誤',MB_OK or MB_ICONERROR);
h_Wnd:=0; // 将 hWnd 設為 NULL
if (not UnregisterClass('OpenGL',hInstance)) then // 登出類
MessageBox(0,'不能登出視窗類.','關閉錯誤',MB_OK or MB_ICONINFORMATION);
//建立我們的OpenGL視窗
function CreateGlWindow(title:Pchar; width,height,bits:integer;FullScreenflag:bool):boolean stdcall;
Pixelformat: GLuint; // 當我們要求Windows為我們尋找相比對的象素格式時,Windows尋找結束後将模式值儲存在變量PixelFormat中
wc:TWndclass; // 視窗類結構
dwExStyle:dword; // 擴充視窗風格
dwStyle:dword; // 視窗風格
pfd: pixelformatdescriptor; // 象素格式描述
dmScreenSettings: Devmode; // 裝置模式
h_Instance:hinst; // 視窗的執行個體
WindowRect: TRect; // 取得矩形的左上角和右下角的坐标值
//取得矩形的左上角和右下角的坐标值。
//我們将使用這些值來調整我們的視窗使得其上的繪圖區的大小恰好是我們所需的分辨率的值。
//通常如果我們建立一個640x480的視窗,視窗的邊框會占掉一些分辨率的值。
WindowRect.Left := 0; // 将Left 設為 0
WindowRect.Top := 0; // 将Right 設為要求的寬度
WindowRect.Right := width; // 将Top 設為 0
WindowRect.Bottom := height; // 将Bottom 設為要求的高度
FullScreen:=FullScreenflag; // 設定全局全屏标志
//我們取得視窗的執行個體,然後定義視窗類
h_instance:=GetModuleHandle(nil); // 取得我們視窗的執行個體
with wc do
style := CS_HREDRAW or CS_VREDRAW or CS_OWNDC; // 移動時重畫,并為視窗取得DC
lpfnWndProc:=@WndProc; // WndProc消息處理函數回調
cbClsExtra:=0; // 無額外視窗資料
cbWndExtra:=0; // 無額外視窗資料
hInstance:=h_Instance; // 設定視窗執行個體
hIcon:=LoadIcon(0,IDI_WINLOGO); // 裝入預設圖示
hCursor:=LoadCursor(0,IDC_ARROW); // 裝入滑鼠指針
hbrBackground:=0; // GL不需要背景
lpszMenuName:=nil; // 不需要菜單
lpszClassName:='OpenGl'; // 設定類名字
//注冊視窗類
if RegisterClass(wc)=0 then // 注冊視窗類
MessageBox(0,'注冊視窗失敗.','錯誤',MB_OK or MB_ICONERROR);
Result:=false;
exit;
//嘗試全屏模式
if FullScreen then
//配置設定用于存儲視訊設定的空間;設定螢幕的寬,高,色彩深度
ZeroMemory( @dmScreenSettings, sizeof(dmScreenSettings) ); // 初始化記憶體
with dmScreensettings do //裝置模式
dmSize := sizeof(dmScreenSettings); // Devmode 結構的大小
dmPelsWidth := width; // 所選螢幕寬度
dmPelsHeight := height; // 所選螢幕高度
dmBitsPerPel := bits; // 每象素所選的色彩深度
dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
// 嘗試設定顯示模式并傳回結果。注: CDS_FULLSCREEN 移去了狀态條。
if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN))<>DISP_CHANGE_SUCCESSFUL THEN
Begin
// 若全屏模式失敗,提供兩個選項:退出或在視窗内運作
if MessageBox(0,'全屏模式在目前顯示卡上設定失敗!\n使用視窗模式?'
,'OpenGL',MB_YESNO or MB_ICONEXCLAMATION)= IDYES then
FullScreen:=false // 選擇視窗模式(Fullscreen=FALSE)
else
begin
// 彈出一個對話框,告訴使用者程式結束
MessageBox(0,'程式将被關閉.','錯誤',MB_OK or MB_ICONERROR);
Result:=false; // 退出并傳回 FALSE
exit;
end;
//由于全屏模式可能失敗,使用者可能決定在視窗下運作,
//我們需要在設定螢幕/視窗之前,再次檢查fullscreen的值是TRUE或FALSE
dwExStyle:=WS_EX_APPWINDOW; // 擴充窗體風格(窗體可見時處于最前面)
dwStyle:=WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; // 窗體風格(沒有邊框)
Showcursor(false); // 隐藏滑鼠指針
end
else
dwExStyle:=WS_EX_APPWINDOW or WS_EX_WINDOWEDGE; // 擴充窗體風格(增強窗體的3D感觀)
dwStyle:=WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; // 窗體風格(帶标題欄、可變大小的邊框、菜單和最大化/最小化按鈕的窗體)
AdjustWindowRectEx(WindowRect,dwStyle,false,dwExStyle); // 調整視窗達到真正要求的大小
// 開始建立視窗并檢查視窗是否成功建立
H_wnd:=CreateWindowEx(dwExStyle, // 擴充窗體風格
'OpenGl', // 類名字
Title, // 視窗标題
dwStyle, // 窗體風格
0,0, // 視窗位置
WindowRect.Right-WindowRect.Left, // 計算調整好的視窗寬度
WindowRect.Bottom-WindowRect.Top, // 計算調整好的視窗高度
0, // 無父視窗
0, // 無菜單
hinstance, // 視窗執行個體
nil); // 不向WM_CREATE傳遞任何東東
if h_Wnd=0 then // 視窗是否正常建立
KillGlWindow(); // 重置顯示區
MessageBox(0,'不能建立一個視窗裝置描述表.','錯誤',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 傳回 FALSE
//描述象素格式
with pfd do
nSize:= SizeOf( PIXELFORMATDESCRIPTOR ); // 象素描述符的大小
nVersion:= 1; // 版本号
dwFlags:= PFD_DRAW_TO_WINDOW // 格式必須支援視窗
or PFD_SUPPORT_OPENGL // 格式必須支援OpenGL
or PFD_DOUBLEBUFFER; // 格式必須支援雙緩沖
iPixelType:= PFD_TYPE_RGBA; // 申請 RGBA 格式
cColorBits:= bits; // 標明色彩深度
cRedBits:= 0; // 忽略的色彩位
cRedShift:= 0;
cGreenBits:= 0;
cBlueBits:= 0;
cBlueShift:= 0;
cAlphaBits:= 0; // 無Alpha緩存
cAlphaShift:= 0; // 忽略Shift Bit
cAccumBits:= 0; // 無累加緩存
cAccumRedBits:= 0; // 忽略聚集位
cAccumGreenBits:= 0;
cAccumBlueBits:= 0;
cAccumAlphaBits:= 0;
cDepthBits:= 16; // 16位 Z-緩存 (深度緩存)
cStencilBits:= 0; // 無蒙闆緩存
cAuxBuffers:= 0; // 無輔助緩存
iLayerType:= PFD_MAIN_PLANE; // 主繪圖層
bReserved:= 0; // Reserved
dwLayerMask:= 0; // 忽略層遮罩
dwVisibleMask:= 0;
dwDamageMask:= 0;
//嘗試取得OpenGL裝置描述表
h_Dc := GetDC(h_Wnd);
if h_Dc=0 then
KillGLWindow(); // 重置顯示區
MessageBox(0,'不能建立一種相比對的像素格式.','錯誤',MB_OK or MB_ICONEXCLAMATION);
//找到對應與此前我們標明的象素格式的象素格式
PixelFormat := ChoosePixelFormat(h_Dc, @pfd);
if (PixelFormat=0) then
MessageBox(0,'不能找到像素格式.','錯誤',MB_OK or MB_ICONEXCLAMATION);
//嘗試設定象素格式
if (not SetPixelFormat(h_Dc,PixelFormat,@pfd)) then
MessageBox(0,'不能設定像素格式.','錯誤',MB_OK or MB_ICONEXCLAMATION);
//嘗試取得着色描述表
h_Rc := wglCreateContext(h_Dc); // 嘗試取得着色描述表
if (h_Rc=0) then
MessageBox(0,'不能建立OpenGL渲染描述表.','錯誤',MB_OK or MB_ICONEXCLAMATION);
//激活着色描述表
if (not wglMakeCurrent(h_Dc, h_Rc)) then
MessageBox(0,'不能激活目前的OpenGL渲然描述表.','錯誤',MB_OK or MB_ICONEXCLAMATION);
//顯示建立完成的OpenGL視窗
ShowWindow(h_Wnd,SW_SHOW); // 顯示建立完成的OpenGL視窗
SetForegroundWindow(h_Wnd); // 設為前端視窗(給它更高的優先級)
SetFocus(h_Wnd); // 并将焦點移至此視窗
ReSizeGLScene(width,height); // 設定透視 GL 螢幕
//初始化OpenGL(設定光照、紋理、等等任何需要設定的東東)
if (not InitGl()) then // 初始化OpenGL
MessageBox(0,'初始化失敗.','錯誤',MB_OK or MB_ICONEXCLAMATION);
Result:=true; // 成功
//Windows程式的入口(調用視窗建立例程,處理視窗消息,并監視人機互動)
function WinMain(hInstance: HINST; // 目前視窗執行個體
hPrevInstance: HINST; // 前一個視窗執行個體
lpCmdLine: PChar; // 指令行參數
nCmdShow: integer): // 視窗顯示狀态
integer; stdcall;
msg: TMsg; // 用來檢查是否有消息等待處理
done: Bool; // 用來檢查否完程式完成運作
done:=false; //用來退出循環的Bool 變量
// 選擇視窗是否全屏
if MessageBox(0,'你想在全屏模式下運作麼?','全屏',
MB_YESNO or MB_ICONQUESTION)=IDNO then
FullScreen:=false
FullScreen:=true;
// 建立OpenGL視窗
if not CreateGLWindow('我的OpenGL 架構',640,480,16,FullScreen) then
Result := 0; // 失敗退出
// 下面是消息循環的開始。隻要done保持FALSE,循環一直進行
while not done do
if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // 檢查是否有消息在等待
if msg.message=WM_QUIT then // 收到退出消息?
done:=true
else // 如果不是退出消息,我們翻譯消息,然後發送消息(使得WndProc() 或 Windows能夠處理他們)
TranslateMessage(msg); // 翻譯消息
DispatchMessage(msg); // 發送消息
end;
end
else
// J如果沒有消息,繪制我們的OpenGL場景失敗,或者ESC 發出退出信号直接退出程式
if (active and not(DrawGLScene()) or keys[VK_ESCAPE]) then
SwapBuffers(h_Dc); // 交換緩存 (雙緩存)
if keys[VK_F1] then // 允許使用者按下F1鍵在全屏模式和視窗模式間切換
Keys[VK_F1] := false; // 若是,使對應的Key數組中的值為 FALSE
KillGLWindow(); // 銷毀目前的視窗
FullScreen := not FullScreen; // 切換 全屏 / 視窗 模式
// 重建 OpenGL 視窗
CreateGLWindow('我的OpenGL 架構',640,480,16,fullscreen);
// 關閉程式
killGLwindow(); // 銷毀視窗
result:=msg.wParam; // 退出程式
WinMain(hInstance, HPrevInst, CmdLine, CmdShow); // 程式開始運作
end.