//窗口及OpenGL所使用的库的头文件
#include <windows.h> //视窗头文件
#include <GL/gl.h>
#include <GL/glu.h>
#include <gl/glaux.h>
//定义程序中计划使用的所有变量
HWND hWnd=NULL; //得到窗口的句柄
HDC hDC=NULL; //私有的GDI设备环境
HGLRC hRC=NULL; //定义渲染环境
HINSTANCE hInstance; //建立一个程序的例子Instance(事件)
//设置窗口大小,斜率及全屏标志变量
RECT rect;
int sw = 640;
int sh = 480;
bool fullscreen = 1;
GLfloat aspect;
//定义程序链接时所需要调用的OpenGL程序库
#pragma comment( lib, "opengl32.lib" ) // 链接时使用OpenGL32.lib
#pragma comment( lib, "glu32.lib" ) // 链接时使用GLu32.lib
#pragma comment( lib, "glaux.lib" ) // 链接时使用GLaux.lib
//OpenGL初始化开始
void SceneInit(int w,int h)
{
glShadeModel(GL_SMOOTH); //允许平滑着色
glClearColor( 1.0, 1.0, 1.0, 0.5 ); //设置屏幕清屏的颜色
glClearDepth(1.0f); //设置深度缓冲区
glEnable(GL_DEPTH_TEST); //允许深度测试
glDepthFunc(GL_LEQUAL); //深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //透视校正,会使透视效果显得更好一些
}
//窗口尺寸改变时OpenGL场景的尺寸
void SceneResizeViewport(GLsizei w, GLsizei h)
{
if(h==0)
{
h=1;
}
aspect = (GLfloat)w/(GLfloat)h;
//设置透视场景,透视的作用是景物距离越远其尺寸越小
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //选择投影矩阵
glLoadIdentity();
gluPerspective( 45.0f, aspect, 0.1f, 100.0f ); //基于窗口的高和宽并以45度视角进行计算。0.1f和
//100f是绘制在屏幕上相对于屏幕距离的开始点和
//结束点
glMatrixMode(GL_MODELVIEW); //确定任何新的变换都会影响模型视点矩阵ModelView
glLoadIdentity(); //把被选择的矩阵还原到初始状态
}
void SceneShow(GLvoid) //这里进行所有的绘图工作
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清屏和清除深度缓冲区
glLoadIdentity(); //重置当前Modelview矩阵
//此处添加绘图命令
}
//激活创建OpenGL窗口
void EnableOpenGL()
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
hDC = GetDC( hWnd );
ZeroMemory( &pfd, sizeof( pfd ) );
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 16;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, iFormat, &pfd );
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
}
// 取消 OpenGL ,在程序结束前调用,释放渲染环境,设备环境以及最终窗口句柄。
void DisableOpenGL()
{
wglMakeCurrent( NULL, NULL );
wglDeleteContext( hRC );
ReleaseDC( hWnd, hDC );
}
//改变屏幕的分辨率
bool ChangeResolution(int w, int h, int bitdepth)
{
DEVMODE devMode;
int modeSwitch;
int closeMode = 0;
EnumDisplaySettings(NULL, closeMode, &devMode);
devMode.dmBitsPerPel = bitdepth;
devMode.dmPelsWidth = w;
devMode.dmPelsHeight = h;
devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
modeSwitch = ChangeDisplaySettings(&devMode, CDS_FULLSCREEN);
if(modeSwitch == DISP_CHANGE_SUCCESSFUL)
{
return true;
}
else
{
ChangeDisplaySettings(NULL, 0);
return false;
}
}
//处理窗口信息
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message ) //将message设置为所有事件声明比较的
//值,message将得到要处理的消息的名字
{
case WM_CREATE: //监视窗口激活的信息
GetWindowRect(hWnd, &rect);
sw = rect.right - rect.left;
sh = rect.bottom - rect.top;
SceneResizeViewport(sw, sh);
return 0;
case WM_SIZE: //改变OpenGL窗口的尺寸。
if(!fullscreen)
{
GetWindowRect(hWnd, &rect);
sw = rect.right - rect.left;
sh = rect.bottom - rect.top;
if(sw>0 && sh>0)
SceneResizeViewport(sw, sh);
}
else
{
SceneResizeViewport(GetSystemMetrics( SM_CXSCREEN ),
GetSystemMetrics( SM_CYSCREEN ));
}
return 0;
case WM_CLOSE: //是否收到一个关闭信息?
ShowWindow (hWnd, SW_HIDE);
PostQuitMessage( 0 );
return 0;
case WM_DESTROY:
return 0;
case WM_KEYDOWN: //是否有一个键被按下?
switch( wParam )
{
case VK_ESCAPE:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
return 0;
default:
return DefWindowProc( hWnd,message, wParam, lParam ); //一些无须在意的信息视窗自己处理
}
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc; //窗口类
MSG msg; //检测是否有信息在等待处理
bool bQuit = false; //bQuit为FLASE,程序当前在运行;为TRUE程序将退出
//询问选择那种屏幕模式
if (MessageBox(NULL,"是否选择全屏显示模式?", "全屏模式运行?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=0; //窗口模式
}
//创建OpenGL窗口,设置标题、宽高及颜色数
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = NULL;
wc.lpszClassName = "Name";
RegisterClass( &wc );
if(fullscreen)
{
ChangeResolution(640, 480, 16);
hWnd = CreateWindow(
"Name",
"Lesson1",
WS_POPUP | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0,
GetSystemMetrics( SM_CXSCREEN ),
GetSystemMetrics( SM_CYSCREEN ),
NULL, NULL,
hInstance,
NULL );
}else
{
hWnd = CreateWindow(
"Name",
"Model001",
WS_TILEDWINDOW | WS_VISIBLE,
GetSystemMetrics( SM_CXSCREEN )/2-sw/2,
GetSystemMetrics( SM_CYSCREEN )/2-sh/2,
sw,
sh,
NULL, NULL,
hInstance,
NULL );
ChangeDisplaySettings(NULL, 0);
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//初始化
EnableOpenGL();
SceneInit(sw, sh);
if(!fullscreen)
{
GetWindowRect(hWnd, &rect);
sw = rect.right - rect.left;
sh = rect.bottom - rect.top;
if(sw>0 && sh>0)
SceneResizeViewport(sw, sh);
}
else
{
SceneResizeViewport(GetSystemMetrics( SM_CXSCREEN ),
GetSystemMetrics( SM_CYSCREEN ));
}
//下面开始循环,如果bQuit的值一直是FLASE,循环将一直重复下去
while ( !bQuit )
{
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) //通过PeekMessage(),检测是否有消息
//在等待,又不会使程序挂起
if ( msg.message == WM_QUIT ) //检测是否有退出消息发出
bQuit = true;
else
{
TranslateMessage( &msg );//如果消息不是退出,使得WndProc()或窗口能处理它
DispatchMessage( &msg );
}
else
{
// OpenGL 动画,如果程序被激活并且ESC没有被按下,可以渲染场景及交换缓冲区(通过使用
//双缓冲区可获得平滑运动的动画)
//通过使用双缓存,先在不可见的隐藏屏幕上绘制,当交换缓冲区时,隐藏屏幕变为可见屏幕,
//原先可见的屏幕变为隐藏,这样
//就看不到屏幕被绘制的过程,画面会马上出现,这样看上去会更真实。
SceneShow();
SwapBuffers(hDC);
}
}
//关闭,退出程序。清除OpenGL窗口,以便释放所有资源,然后退出程序。
DisableOpenGL();
ShowWindow (hWnd, SW_HIDE);
DestroyWindow( hWnd );
ChangeDisplaySettings(NULL, 0);
return msg.wParam;
return 0;
}