將CKER翻譯的NeHe的VC 的OPENGL框架轉成了Delphi版,
希望對用Delphi學習OPENGL的兄弟有幫助,
不知為什麼,我的Delphi環境下無法直接運行,但是在別的機器上好像沒問題
我的機器只能編譯後執行EXE檔。
感謝NeHe提供的這麼好的框架,感謝CKER翻譯的VC的資料
PRogram Project1;
Uses
opengl,
windows,
Messages;
Const
WND_TITLE = 'OPenGl 基本框架'; //標題
Var
//================================================ =============================
// 每一個OpenGL都被連接到一個著色描述表上。著色描述表將所有的OpenGL呼叫命令連
// 接到Device Context(裝置描述表)上,將OpenGL的著色描述表定義為hRC ,要讓程式能
// 夠繪製視窗的話,還需要建立一個裝置描述表,Windows的裝置描述表被定義為hDC,
// DC將視窗連接到GDI(Graphics Device Interface圖形設備介面)。而RC將OpenGL連接
// 到DC。
//================================================ =============================
h_RC : HGLRC; // Rendering Context(著色描述表)。
h_DC : HDC; // Device Context(裝置描述表)
h_Wnd : HWND; // 視窗句柄
h_Instance : HINST; // 程式Instance(實例)。
keys : Array[0..255] Of Boolean; // 用於鍵盤例程的陣列
{$R *.res}
//================================================ ================================
//重新設定OpenGL場景的大小,而不管視窗的大小是否已經改變(假定沒有使用全螢幕模式)。
//甚至無法改變視窗的大小時(例如在全螢幕模式下),它至少仍將運行一次————————
//在程式開始時設定透視圖。 OpenGL場景的尺寸將會被設定成它顯示時所在視窗的大小。
//================================================ ================================
Procedure glResizeWnd(Width, Height: Integer); // 重置並初始化GL視窗大小
Begin
If (Height = 0) Then // 防止高度為0,產生除0異常
Height := 1;
glViewport(0, 0, Width, Height); // 重置目前的視窗(Viewport)
//下面幾行為透視圖設定畫面。意味著越遠的東西看起來越小。這麼做創造了一個現實
//外觀的場景。此處透視依照基於視窗寬度和高度的45度視角來計算。 0.1f,100.0f是
//我們在場景中所能繪製深度的起點和終點。
//glMatrixMode(GL_PROJECTION)指明接下來的兩行程式碼將影響projection matrix(投影矩陣)。
//投影矩陣負責為我們的場景增加透視。
//glLoadIdentity()近似於重置。它將所選的矩陣狀態恢復成原始狀態。
//呼叫glLoadIdentity()之後我們為場景設定透視圖。
glMatrixMode(GL_PROJECTION); // 選擇投影矩陣
glLoadIdentity(); // 重置投影矩陣
gluPerspective(45.0, Width / Height, 0.1, 100.0); // 計算視窗的外觀比例
//glMatrixMode(GL_MODELVIEW)指明任何新的變換將會影響modelview matrix(模型觀察矩陣)。
//模型觀察矩陣中存放了我們的物體訊息。
glMatrixMode(GL_MODELVIEW); // 選擇模型觀察矩陣
glLoadIdentity(); // 重置模型觀察矩陣
//如果現在還不能理解這些術語的含義,請別著急。
//只要知道如果想獲得一個精彩的透視場景的話,必須這麼做。
End;
//================================================ ================================
// 對OpenGL進行所有的設定。將設定清除螢幕所使用的顏色,開啟深度緩存,
// 啟用smooth shading(陰影平滑),等等。這個例程直到OpenGL視窗創建之後才會被呼叫。
// 此過程將有回傳值。但此處的初始化沒那麼複雜,現在還用不著擔心這個回傳值。
//================================================ ================================
Procedure glInit();
Begin
//設定清除螢幕時所使用的顏色。如果對色彩的工作原理不清楚的話,快速解釋一下。
//色彩值的範圍從0.0f到1.0f。 0.0f代表最黑的情況,1.0f就是最亮的情況。
//glClearColor 後的第一個參數是Red Intensity(紅色分量),第二個是綠色,第三個是藍色。
//最大值也是1.0f,代表特定顏色分量的最亮情況。最後一個參數是Alpha值。
//當它用來清除螢幕的時候,不用關心第四個數字。現在讓它為0.0f。
//透過混合三原色(紅、綠、藍),可以得到不同的色彩
//因此,使用glClearColor(0.0f,0.0f,1.0f,0.0f),您藍色來清除螢幕。
//如果用glClearColor(0.5f,0.0f,0.0f,0.0f)的話,將使用中紅色來清除螢幕。
//不是最亮(1.0f),也不是最暗(0.0f)。要得到白色背景,應該將所有的顏色設為最亮(1.0f)。
//要黑色背景的話,該將所有的顏色設為最暗(0.0f)。
glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景
//陰影平滑通過多邊形精細的混合色彩,並對外部光進行平滑。
glShadeModel(GL_SMOOTH); // 啟用陰影平滑
//接下來必須做的是關於depth buffer(深度快取)的。將深度快取設想為螢幕後面的層。
//深度快取不斷的對物體進入螢幕內部有多深進行追蹤。本程式其實沒有真正使用深度緩存,
//但幾乎所有在螢幕上顯示3D場景OpenGL程式都使用深度快取。它的排序決定那個物體先畫。
//這樣您就不會將一個圓形後方的正方形畫到圓形上來。深度快取是OpenGL十分重要的部分。
glClearDepth(1.0); // 設定深度緩存
glEnable(GL_DEPTH_TEST); // 啟用深度測試
glDepthFunc(GL_LESS); // 所做深度測試的型別
//接著告訴OpenGL我們希望進行最好的透視修正。
//這會十分輕微的影響效能。但使得透視圖看起來好一點。
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精細的透視修正
End;
//================================================ ================================
//所有的繪圖程式碼。任何您所想在螢幕上顯示的東東都將在此段代碼中出現。
//以後的每個程式都會在此增加新的程式碼。
//================================================ ================================
Procedure glDraw();
Begin
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除螢幕與深度緩存
glLoadIdentity(); // 重置目前的模型觀察矩陣
End;
Function WndProc(hWnd: HWND; // 視窗的句柄
Msg: UINT; // 視窗的訊息
wParam: WPARAM; // 附加的訊息內容
lParam: LPARAM // 附加的訊息內容
): LRESULT; stdcall;
Begin
Result := 0;
Case (Msg) Of // 檢查Windows訊息
WM_ACTIVATE: // 監視視窗啟動訊息
Begin
End;
WM_CREATE: // 創建
Begin
End;
WM_CLOSE: // 關閉
Begin
PostQuitMessage(0); // 發出退出訊息
Result := 0
End;
WM_KEYDOWN: // 按鍵按下
Begin
keys[wParam] := 真; // 如果是,設為TRUE
Result := 0;
End;
WM_KEYUP: // 按下鍵放開
Begin
keys[wParam] := False; // 如果是,設為FALSE
Result := 0;
End;
WM_SIZE: //調整OpenGL視窗大小
Begin
glResizeWnd(LOWord(lParam), HIWORD(lParam)); //LoWord=Width,HiWord=Height
Result := 0;
End;
WM_TIMER: //timers
Begin
End;
Else //其餘的讓Windows自行處理。
Result := DefWindowProc(hWnd, Msg, wParam, lParam); //向DefWindowProc傳遞所有未處理的訊息。
End;
End;
//================================================ ================================
// 只在程式退出之前呼叫。作用是依序釋放著色描述表,設備描述表和視窗句柄。
// 加入了許多錯誤檢查。如果程式無法銷毀視窗的任意部分,都會彈出帶有對應錯誤訊息的
// 訊息窗口,
//================================================ ================================
Procedure glKillWnd(Fullscreen: Boolean);
Begin
//在KillGLWindow()中所做的第一件事是檢查是否處於全螢幕模式。
//如果是,要切換回桌面。本應在停用全螢幕模式前先銷毀窗口,
//但在某些顯示卡上這麼做可能會讓桌面崩潰。所以還是先停用全螢幕模式。
//這將防止桌面出現崩潰,並在Nvidia和3dfx顯示卡上都工作的很好!
If Fullscreen Then // 處於全螢幕模式嗎?
Begin
// 使用ChangeDisplaySettings(NULL,0)回到原始桌面。
// 將NULL當作第一個參數,
// 0作為第二個參數傳遞強制Windows使用目前存放在登錄中的值
// (缺省的解析度、色彩深度、刷新頻率,等等)來有效的恢復我原始桌面。
// 換回桌面後,也要讓滑鼠指標重新可見。
ChangeDisplaySettings(devmode(Nil^), 0); // 是的話,切換回桌面
ShowCursor(True); //顯示滑鼠
End;
//是否擁有著色描述表(hRC)。
If h_RC > 0 Then
//看我們能否釋放它(將hRC從hDC分開)。
If (Not wglMakeCurrent(h_DC, 0)) Then
MessageBox(0, 'DC和RC無法被釋放!', '錯誤', MB_OK Or
MB_ICONERROR);
// 能否刪除著色描述表
If (Not wglDeleteContext(h_RC)) Then
Begin
MessageBox(0, '刪除著色描述表失敗!', '錯誤', MB_OK Or
MB_ICONERROR);
h_RC := 0;
End;
//是否存在裝置描述表,如果有嘗試釋放它。
If ((h_DC > 0) And (ReleaseDC(h_Wnd, h_DC) = 0)) Then
Begin
MessageBox(0, '釋放裝置描述表失敗!', '錯誤', MB_OK Or
MB_ICONERROR);
h_DC := 0;
End;
//是否存在視窗句柄,呼叫DestroyWindow( hWnd )來嘗試銷毀視窗
If ((h_Wnd <> 0) And (Not DestroyWindow(h_Wnd))) Then
Begin
MessageBox(0, '無法銷毀窗體!', '錯誤', MB_OK Or
MB_ICONERROR);
h_Wnd := 0;
End;
// 登出視窗類
//這允許我們正常銷毀窗口,接著在開啟其他視窗時,
//不會收到諸如"Windows Class already registered"(視窗類別已註冊)的錯誤訊息。
If (Not UnRegisterClass('OpenGL', hInstance)) Then
Begin
MessageBox(0, '無法登出視窗類別!', '錯誤', MB_OK Or
MB_ICONERROR);
hInstance := 0;
End;
End;