NeHe OpenGL教程 第七課:光照和鍵盤 程式碼
阿新 • • 發佈:2018-12-19
#include <windows.h> // Windows的標頭檔案
#include <glew.h> // 包含最新的gl.h,glu.h庫
#include <glut.h> // 包含OpenGL實用庫
#include <stdio.h> // 標準輸入/輸出庫的標頭檔案
#include <glaux.h> // GLaux庫的標頭檔案
HGLRC hRC = NULL; // 視窗著色描述表控制代碼
HDC hDC = NULL; // OpenGL渲染描述表控制代碼
HWND hWnd = NULL; // 儲存我們的視窗控制代碼
HINSTANCE hInstance; // 儲存程式的例項
bool keys[256]; // 儲存鍵盤按鍵的陣列
bool active = TRUE; // 視窗的活動標誌,預設為TRUE
bool fullscreen = TRUE; // 全屏標誌預設,預設設定成全屏模式
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // WndProc的定義
GLfloat xrot; // X 旋轉
GLfloat yrot; // Y 旋轉
GLfloat xspeed = 0.0f; // X 旋轉速度
GLfloat yspeed = 0.0f; // Y 旋轉速度
GLfloat z=-5.0f; // 深入螢幕的距離
GLuint texture[3]; // 儲存一個紋理
BOOL light; // 光源的開/關
BOOL lp; // L鍵按下了麼?
BOOL fp; // F鍵按下了麼?
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // 環境光引數
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // 漫射光引數
GLfloat LightPosition[ ]= { 0.0f, 0.0f, 2.0f, 1.0f }; // 光源位置
GLuint filter; // 濾波型別
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
// 防止被零除
if (height==0)
{
height=1; // 將Height設為1
}
// 重置當前的視口
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);// 選擇投影矩陣
glLoadIdentity();// 重置投影矩陣
// 設定視口的大小
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);// 選擇模型觀察矩陣
glLoadIdentity();// 重置模型觀察矩陣
}
AUX_RGBImageRec *LoadBMP(char *Filename) // 載入點陣圖圖象
{
FILE *File=NULL; // 檔案控制代碼
if (!Filename) // 確保檔名已提供
{
return NULL; // 如果沒提供,返回 NULL
}
File=fopen(Filename,"r"); // 嘗試開啟檔案
if (File) // 檔案存在麼?
{
fclose(File); // 關閉控制代碼
return auxDIBImageLoad(Filename); // 載入點陣圖並返回指標
}
return NULL; // 如果載入失敗,返回 NULL
}
int LoadGLTextures() // 載入點陣圖(呼叫上面的程式碼)並轉換成紋理
{
int Status=FALSE; // 狀態指示器
AUX_RGBImageRec *TextureImage[1]; // 建立紋理的儲存空間
memset(TextureImage,0,sizeof(void *)*1); // 將指標設為 NULL
// 載入點陣圖,檢查有無錯誤,如果點陣圖沒找到則退出
if (TextureImage[0]=LoadBMP("bitmap1.bmp"))
{
Status=TRUE; // 將 Status 設為 TRUE
// 建立 Nearest 濾波貼圖
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// 建立線性濾波紋理
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// 建立 MipMapped 紋理
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
}
if (TextureImage[0]) // 紋理是否存在
{
if (TextureImage[0]->data) // 紋理影象是否存在
{
free(TextureImage[0]->data); // 釋放紋理影象佔用的記憶體
}
free(TextureImage[0]); // 釋放影象結構
}
return Status; // 返回 Status
}
int InitGL(GLvoid) // 此處開始對OpenGL進行所有設定
{
if (!LoadGLTextures()) // 呼叫紋理載入子例程
{
return FALSE; // 如果未能載入,返回FALSE
}
glEnable(GL_TEXTURE_2D); // 啟用紋理對映
glShadeModel(GL_SMOOTH); // 啟用陰影平滑
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
glClearDepth(1.0f); // 設定深度快取
glEnable(GL_DEPTH_TEST); // 啟用深度測試
glDepthFunc(GL_LEQUAL); // 所作深度測試的型別
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精細的透視修正
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 設定環境光
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 設定漫射光
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 設定光源位置
glEnable(GL_LIGHT1);
return TRUE; // 初始化 OK
}
int DrawGLScene(GLvoid) // 從這裡開始進行所有的繪製
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除螢幕和深度快取
glLoadIdentity(); // 重置當前的模型觀察矩陣
glTranslatef(0.0f,0.0f,z); // 移入/移出螢幕 z 個單位
glRotatef(xrot,1.0f,0.0f,0.0f); // 繞X軸旋轉
glRotatef(yrot,0.0f,1.0f,0.0f); // 繞Y軸旋轉
glBindTexture(GL_TEXTURE_2D, texture[filter]); // 選擇由filter決定的紋理
glBegin(GL_QUADS); // 開始繪製四邊形
// 前側面
glNormal3f( 0.0f, 0.0f, 1.0f); // 法線指向觀察者
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 後側面
glNormal3f( 0.0f, 0.0f,-1.0f); // 法線背向觀察者
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 頂面
glNormal3f( 0.0f, 1.0f, 0.0f); // 法線向上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 底面
glNormal3f( 0.0f,-1.0f, 0.0f); // 法線朝下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右側面
glNormal3f( 1.0f, 0.0f, 0.0f); // 法線朝右
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左側面
glNormal3f(-1.0f, 0.0f, 0.0f); // 法線朝左
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd(); // 四邊形繪製結束
xrot+=xspeed; // xrot 增加 xspeed 單位
yrot+=yspeed; // yrot 增加 yspeed 單位
return TRUE;
}
GLvoid KillGLWindow(GLvoid) { // 正常銷燬視窗
if (fullscreen) { // 我們處於全屏模式嗎?
ChangeDisplaySettings(NULL, 0);// 是的話,切換回桌面
ShowCursor(TRUE); // 顯示滑鼠指標
}
if (hRC) { // 我們擁有OpenGL渲染描述表嗎?
if (!wglMakeCurrent(NULL, NULL)) { // 我們能否釋放DC和RC描述表?
MessageBox(NULL, "釋放DC或RC失敗", "關閉錯誤", MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) {
MessageBox(NULL, "釋放RC失敗。", "關閉錯誤", MB_OK | MB_ICONINFORMATION);
}
hRC = NULL;
}
if (hDC && !ReleaseDC(hWnd, hDC)) // 我們能否釋放 DC?
{
MessageBox(NULL, "釋放DC失敗。", "關閉錯誤", MB_OK | MB_ICONINFORMATION);
hDC = NULL; // 將 DC 設為 NULL
}
if (hWnd && !DestroyWindow(hWnd)) // 能否銷燬視窗?
{
MessageBox(NULL, "釋放視窗控制代碼失敗。", "關閉錯誤", MB_OK |
MB_ICONINFORMATION);
hWnd = NULL; // 將 hWnd 設為 NULL
}
if (!UnregisterClass("OpenG", hInstance)) // 能否登出類?
{
MessageBox(NULL, "不能登出視窗類。", "關閉錯誤", MB_OK | MB_ICONINFORMATION);
hInstance = NULL; // 將 hInstance 設為 NULL
}
}
// 建立OpenGL視窗
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) {
GLuint PixelFormat; // 儲存查詢匹配的結果
WNDCLASS wc; // 視窗類結構
DWORD dwExStyle;// 擴充套件視窗風格
DWORD dwStyle; // 視窗風格
RECT WindowRect; // 取得矩形的左上角和右下角的座標值
WindowRect.left = (long)0; // 將Left 設為 0
WindowRect.right = (long)width; // 將Right 設為要求的寬度
WindowRect.top = (long)0; // 將Top 設為 0
WindowRect.bottom = (long)height; // 將Bottom 設為要求的高度
fullscreen = fullscreenflag;
hInstance = GetModuleHandle(NULL); //取得視窗例項
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //移動時重畫並取得視窗DC
wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc處理訊息
wc.cbClsExtra = 0; // 無額外視窗資料
wc.cbWndExtra = 0; // 無額外視窗資料
wc.hInstance = hInstance; // 設定例項
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // 裝入預設圖示
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 裝入滑鼠指標
wc.hbrBackground = NULL; // GL不需要背景
wc.lpszMenuName = NULL