接上面,附件里带有可执行文件.欢迎大家跟我交流,QQ:31377458^_^
///////////////////////////////////////////////////////////////////////////////////////////////////
//函数接收5个参数:窗口标题,窗口宽度,窗口高度,色彩深度(16/24/32)还有全屏幕模式开关.TRUE代表使用全屏幕模式,FALSE代表使用窗口模式
//函数返回一个BOOL值来表明窗口创建是否成功。
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat; //保存Windows给出匹配的像素点格式
WNDCLASS wc; //保存窗口类结构
DWORD dwExStyle; //用于存放扩展窗口风格的信息
DWORD dwStyle; //存放通常窗口风格的信息
//获取矩形左上角和右下角的值,因为窗口是具有边框的,所以一般窗口尺寸会大于绘图区尺寸
RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right values
WindowRect.left=(long)0; // Set Left value To 0
WindowRect.right=(long)width; // Set Right value To Requested Width
WindowRect.top=(long)0; // Set Top value To 0
WindowRect.bottom=(long)height; // Set Bottom value To Requested Height
fullscreen=fullscreenflag; //把fullscreenflag的值赋给全局变量fullscreen
hInstance = GetModuleHandle(NULL); //获取应用程序实例句柄,然后定义窗口类
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //窗口在调整尺寸时重绘,创建一个私有的窗口DC
wc.lpfnWndProc = (WNDPROC) WndProc; //窗口过程 WndProc Handles Messages
wc.cbClsExtra = 0; //不需要额外的窗口数据
wc.cbWndExtra = 0; //不需要额外的窗口数据
wc.hInstance = hInstance; // Set The Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
wc.hbrBackground = NULL; //之后在OpenGL中设置窗口背景色
wc.lpszMenuName = NULL; //不需要菜单
wc.lpszClassName = \"OpenGL\"; //设置类名
if (!RegisterClass(&wc)) //注册窗口类
{
MessageBox (NULL,\" Failed To Register The Window Class.\",\"ERROR\",MB_OK|MB_ICONEXCLAMATION);
return FALSE; //退出
}
if (fullscreen) //切换到全屏幕模式
{
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //清除用于保存显示设置参数的空间
dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = width; //设置需要的宽,在全屏幕模式下使用的窗口的宽和高应该和在窗口模式中使用的宽和高相同
dmScreenSettings.dmPelsHeight= height; //设置需要的高
dmScreenSettings.dmBitsPerPel = bits; //设置色彩深度
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
//尝试设置与dmScreenSettings中相匹配的模式
//NOTE:CDS_FULLSCREEN使得在切换全屏模式的时候移除底部的开始菜单任务栏,而且在整个切换过程中不会影响到桌面上其它窗口的尺寸.
if (ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
//如果所请求的全屏幕模式不被支持,将弹出一个消息框.你可以选择使用窗口模式或退出
if (MessageBox(NULL,\"The Requested Fullscreen Mode Is Not Supported By\\nYour Video Card. Use Windowed Mode Instead?\",\"NeHe GL\",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE; // Select Windowed Mode (Fullscreen=FALSE)
}
else
{
//弹出一个消息框告诉用户程序即将结束,窗口创建失败
MessageBox(NULL,\"

rogram Will Now Close.\",\"ERROR\",MB_OK|MB_ICONSTOP);
return FALSE; //程序退出
}
}
}
if (fullscreen) //仍在全屏设置中
{
dwExStyle=WS_EX_APPWINDOW; //设置扩展风格为WS_EX_APPWINDOW,强制使窗口可见于最前面
dwStyle=WS_POPUP; //设置通常风格为WS_POPUP,没有边框的弹出式窗口,使得全屏模式窗口完美显示
ShowCursor(FALSE); //禁止鼠标箭头
}
else //转为窗口模式继续运行
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; //增加WS_EX_WINDOWEDGE到扩展风格,使窗口具有 3D 外观
dwStyle=WS_OVERLAPPEDWINDOW; //用WS_OVERLAPPEDWINDOW代替WS_POPUP,具有标题栏,窗口菜单,最大化最小化按钮和可调整尺寸的窗口
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); //根据窗口风格来调整窗口尺寸,对于全屏幕模式来说这条函数没有效果
//创建窗口
if (!(hWnd=CreateWindowEx( dwExStyle, //扩展窗口风格
\"OpenGL\", //类名(必须与之前注册的类名相同)
title, //窗口标题
WS_CLIPSIBLINGS | //WS_CLIPSIBLINGS和WS_CLIPCHILDREN 风格,这是保证OpenGL正常运行所必须的.
WS_CLIPCHILDREN | //能预防其它窗口在OpenGL窗口上进行绘图
dwStyle, //通常样式
0, 0, //窗口左上角坐标
WindowRect.right-WindowRect.left, //窗口宽与高
WindowRect.bottom-WindowRect.top,
NULL, //没有父窗口
NULL, //不需要菜单
hInstance, //应用程序句柄
NULL))) // Don\'t Pass Anything To WM_CREATE
{ //创建不成功
KillGLWindow(); // Reset The Display
MessageBox(NULL,\"Window Creation Error.\",\"ERROR\",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
//描述象素点格式
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | //格式支持 OpenGL
PFD_DOUBLEBUFFER, //支持双缓冲
PFD_TYPE_RGBA, //支持RGBA 模式
bits, //要求的色彩深度相匹配色深
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer(积累缓存)
0, 0, 0, 0, // Accumulation Bits Ignored
16, //设置一个16bit的Z-缓存(Depth Buffer)
0, // No Stencil Buffer(模版缓存)
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if (!(hDC=GetDC(hWnd))) //尝试获取一个OpenGL Device Context
{
KillGLWindow(); //Reset The Display
MessageBox(NULL, \"Can\'t Create A GL Device Context.\", \"ERROR\", MB_OK|MB_ICONEXCLAMATION);
return FALSE; //程序退出
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) //找出一个与上面所描述的相匹配的像素点格式
{
KillGLWindow(); // Reset The Display
MessageBox(NULL, \"Can\'t Find A Suitable PixelFormat.\", \"ERROR\",MB_OK|MB_ICONEXCLAMATION);
return FALSE; //程序退出
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) //设置像素点格式
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,\"Can\'t Set The PixelFormat.\",\"ERROR\",MB_OK|MB_ICONEXCLAMATION);
return FALSE; //Return FALSE程序退出
}
if (!(hRC=wglCreateContext(hDC))) //获取一个Rendering Context
{
KillGLWindow(); //Reset The Display
MessageBox(NULL, \"Can\'t Create A GL Rendering Context.\", \"ERROR\", MB_OK|MB_ICONEXCLAMATION);
return FALSE; //Return FALSE程序退出
}
if(!wglMakeCurrent(hDC,hRC)) //激活Rendering Context
{
KillGLWindow(); // Reset The Display
MessageBox(NULL, \"Can\'t Activate The GL Rendering Context.\", \"ERROR\", MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
ShowWindow(hWnd,SW_SHOW); //将窗口显示出来 Show The Window
SetForegroundWindow(hWnd); //并把它设到前台 Slightly Higher Priority
SetFocus(hWnd); //设置焦点到窗口上 Sets Keyboard Focus To The Window
ReSizeGLScene(width, height); //将窗口的宽与高作为参数来调用ReSizeGLScene以设置OpenGL透视
if (!InitGL()) // Initialize Our Newly Created GL Window
{
KillGLWindow(); // Reset The Display
MessageBox(NULL,\"Initialization Failed.\",\"ERROR\",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
return TRUE; //返回TRUE告知WinMain()未发生错误
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
switch (uMsg) //uMsg用来保存待处理的消息的名字 Check For Windows Messages
{
case WM_ACTIVATE: // Watch For Window Activate Message
{
if (!HIWORD(wParam)) //检查窗口是否还处于活动状态
{
active=TRUE; //窗口处于活动状态
}
else
{
active=FALSE; //窗口处于非活动状态
}
return 0; // Return To The Message Loop
}
case WM_SYSCOMMAND: //(系统消息)
{
switch (wParam) // Check System Calls
{
case SC_SCREENSAVE: //代表屏幕保护程序将启动
case SC_MONITORPOWER: //代表显示器将进入节能模式
return 0; //返回0以阻止这种事情的发生
}
break; // Exit
}
case WM_CLOSE: //窗口被关闭
{
PostQuitMessage(0); //发出一条退出消息
return 0; //Jump Back
}
case WM_KEYDOWN: //某个键被按下,支持多个键同时按下的方法
{
keys[wParam] = TRUE; //数组keys[]中与那个键相对应的元素将被设置为TRUE
return 0; // Jump Back
}
case WM_KEYUP: //某个键抬起
{
keys[wParam] = FALSE; //数组keys[]中与那个键相对应的元素将被设置为FALSE
return 0; // Jump Back
}
case WM_SIZE: //调整窗口的尺寸消息
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); //读取lParam 的低字和高字的值可以获取新的窗口尺寸的宽与高,以新的尺寸值作为参数调用ReSizeGLScene(),OpenGL场景做出相应的尺寸调整
return 0; // Jump Back
}
}
//其余的消息递给DefWindowProc,让 Windows 自行处理。
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain (HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
MSG msg; //用于检测是否有消息需要处理 Windows Message Structure
BOOL done = FALSE; //当它为TRUE的时候程序就会退出 Bool Variable To Exit Loop
//询问是否要运行于全屏幕模式
if (MessageBox(NULL,\"Would You Like To Run In Fullscreen Mode?\", \"Start FullScreen?\",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE; //选择NO变量fullscreen从TRUE(默认值)变为FALSE.并且程序会运行于窗口模式
}
//创建OpenGL窗口
if (!CreateGLWindow(\"OpenGL\",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
while(!done) // Loop That Runs Until done=TRUE
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //否有 Windows 消息待处理.使用PeekMessage() 检索消息可以避免程序等待。
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else // If Not, 解释消息
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else //没有消息的话绘制OpenGL场景
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if (active) //检查窗口是否处于活动状态
{
if (keys[VK_ESCAPE]) // Was ESC Pressed?
{
done=TRUE; // ESC Signalled A Quit
}
else // Not Time To Quit, Update Screen
{
//如果程序处于活动状态并且 ESC 按钮没有被按下
DrawGLScene(); //绘制场景
SwapBuffers(hDC); //交换缓冲区(使用双缓冲技术可以得到平滑无闪烁的动画)
if (keys[\'L\'] && !lp) //L键是否被按下?
{ //lp初值为false.false意味着L键不处于压下状态,或早已释放.true意味着L键处于压下状态
lp=TRUE; //lp置为true.为了避免如果按住L键光照就会因为反复的开、关而闪烁
light=!light; //转换光照的开与关.变量light只能是true或false,如果它是true的话就会变成false,是false的话就会变成true
if (!light) //light为false
{
glDisable(GL_LIGHTING); //关闭光照
}
else //light为true
{
glEnable(GL_LIGHTING); //打开光照
}
}
if (!keys[\'L\']) //检测是否已经释放L键
{
lp=FALSE; //是的话就置变量lp为false
}
if (keys[\'F\'] && !fp) //检测F键是否被按下?
{ //同上的方式
fp=TRUE; // fp Becomes TRUE
filter+=1; //F键被按下一次变量filter就会增加1
if (filter>2) //当其大于2时
{
filter=0; //回到0
}
}
if (!keys[\'F\']) //是否已经释放F键?
{
fp=FALSE; //是的话就置变量fp为false
}
if (keys[VK_PRIOR]) //检测是否按下\"

age Up\"?
{
z-=0.02f; //是的话变量z就会有减量.把木箱向屏幕里的方向移动
}
if (keys[VK_NEXT]) //检测是否按下\"

age Down\"键
{
z+=0.02f; //是的话变量z就会有增量,DrawGLScene中的glTranslatef(0.0f,0.0f,z)就会把木箱向外移动。
}
//检测方向键是否被按下
//按下左或右键,变量xspeed就会相应地减量或增量;按下上或下键,变量yspeed就会相应地减量或增量
//xspeed或yspeed的(绝对)值越高,木箱旋转的就会越快.所以按住某个方向键的时间越长,木箱在对应的方向就会旋转的越快
if (keys[VK_UP]) // Is Up Arrow Being Pressed?
{
xspeed-=0.01f; // If So, Decrease xspeed
}
if (keys[VK_DOWN]) // Is Down Arrow Being Pressed?
{
xspeed+=0.01f; // If So, Increase xspeed
}
if (keys[VK_RIGHT]) // Is Right Arrow Being Pressed?
{
yspeed+=0.01f; // If So, Increase yspeed
}
if (keys[VK_LEFT]) // Is Left Arrow Being Pressed?
{
yspeed-=0.01f; // If So, Decrease yspeed
}
//在绘制透明物体的时候,关闭深度缓存,因为希望在半透明物体后面的物体能被绘制,这并不是使用混合的正确方式,但是在情况简单的时候它会工作得很好
//正确的方法是在整个场景绘制完之后再绘制所有的透明(alpha < 1.0)多边形,而且要按照由远及近的深度顺序
//这是由于事实上按照不同的顺序混合两个(1和2)多边形会得到不同的结果
//假如多边形1距离我们最近,那么正确的方法是先绘制多边形2,然后是多边形1
//如果你看着它,那么真实情况就是它们后面的光首先经过多边形2,然后经过多边形1,最后到达你的眼睛
//所以,需要按照深度将透明的多边形进行排序,开着深度缓存并在整个场景绘制完毕之后再绘制它们,否则将得到不正确的结果
if (keys[\'B\'] && !bp) //检查键盘上的B键是否被按下?
{
bp=TRUE; // If So, bp Becomes TRUE
blend = !blend; // Toggle blend TRUE / FALSE
if(blend) //混合是关?
{
glEnable(GL_BLEND); //打开混合
glDisable(GL_DEPTH_TEST); //关闭深度测试
}
else //混合是开
{
glDisable(GL_BLEND); //关闭混合
glEnable(GL_DEPTH_TEST); //打开深度测试
}
}
if (!keys[\'B\']) //B被释放?
{
bp=FALSE; //bp置为FALSE
}
}
}
//使用 F1 切换全屏幕模式和窗口模式。
if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
if (!CreateGLWindow(\"OpneGL\",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
}
}
}
//程序退出,完全地摧毁窗口,所有东西都释放掉
KillGLWindow(); // Kill The Window
return (msg.wParam); // Exit The Program
}