#include <windows.h> //win32的头文件
#include <tchar.h>
#include <gl\gl.h> //opengl32.lib 的头文件
#include <gl\glu.h> //glu32.lib 的头文件
HDC hDC = NULL; //全局的设备描述表句柄
HGLRC hRC = NULL; //Rendering Context句柄
HWND hWnd = NULL; //win32程序的窗口句柄
HINSTANCE hInst; //win32程序的实例句柄
bool Fullscreen = false;
int Width = 800;
int Height = 600;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //声明窗口过程函数
void InitGL(); //初始化OpenGL
void ResizeGLScene(int, int); //当窗口大小变化时,调整OpenGL的投影
void DrawGLScene(); //绘制OpenGL内容
//创建windows窗口并绑定OpenGL
//未实现全屏判断
BOOL CreateGLWindow(TCHAR *caption, int bits, BOOL fullscreenflag)
{
GLuint PixelFormat;
WNDCLASS wndclass; //窗口类结构
Fullscreen = fullscreenflag;
hInst = GetModuleHandle(NULL);
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //HREDRAW,VREDRAW表示该窗口在大小改变时候将发生WM_PAINT消息;
//OWNDC表示该窗口将保存自己的设备描述表属性
wndclass.lpfnWndProc = WndProc; //注册窗口过程
wndclass.cbClsExtra = 0; //额外的窗口信息
wndclass.cbWndExtra = 0; //额外的窗口信息
wndclass.hInstance = hInst; //为什么要用这个函数?
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //窗口图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //窗口鼠标图标
wndclass.hbrBackground = NULL; //窗口背景画刷( 因为我们用Opengl绘图,不宜再使用GDI提供的画刷;否则如果选用
// GetStockObject(WHITE_BRUSH),你会发现每次拉动窗口大小时候画面将会被该画刷清除!)
wndclass.lpszMenuName = NULL; //该窗口没有菜单
wndclass.lpszClassName = TEXT("OpenGL"); //窗口类名字
//注册该窗口类
if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Failed To Register The Window Class."), TEXT("ERROR"), MB_ICONERROR);
return false;
}
if(Fullscreen)
{
MessageBox(NULL, TEXT("不好意思,没实现全屏窗口."), TEXT("ERROR"), MB_OK);
}
//创建程序窗口
hWnd = CreateWindow( TEXT("OpenGL"),
TEXT("OpenGL Framework"),
WS_OVERLAPPEDWINDOW,
0, //窗口x坐标
0, //窗口y坐标
Width, //窗口宽
Height, //窗口高
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInst, //程序实例句柄
NULL); //创建附带参数
//CreateWindow函数在返回前,会发送WM_CREATE消息
if(!hWnd)
{
MessageBox(NULL, TEXT("Failed To Create A Window."), TEXT("ERROR"), MB_ICONERROR);
return false;
}
//设置像素格式
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), //PIXELFORMATDESCRIPTOR结构体的大小
1, //PIXELFORMATDESCRIPTOR结构体的版本号
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //定义像素缓存的属性
PFD_TYPE_RGBA, //像素数据类型,可以是RGBA或者是COLORINDEX
bits, //每个像素点的颜色位数
0, 0, 0, 0, 0, 0, //忽略每个颜色位
0, //无alpha缓存
0, //忽略移位位
0, //无累加缓存
0, 0, 0, 0, //忽略累加位
16, //16位深度缓存
0, //无模板缓存
0, //无辅助缓存
PFD_MAIN_PLANE, //主层
0, //保留
0, 0, 0 //忽略层,可见性和损毁掩模
};
hDC = GetDC(hWnd); //获得设备描述表
//相应的ReleaseDC在DestroyGLWindow中调用
PixelFormat = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, PixelFormat, &pfd );
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
InitGL(); //我本来想把这个函数放在WM_CREATE消息中处理。
//但实际上,CreateWindow函数返回之前,就可能发送并处理WM_CREATE消息了。
//而此时上面几句OpenGL绑定到设备描述表的还没做呢
return TRUE;
}
//销毁OpenGL关联的窗口
void DestroyGLWindow()
{
if(hRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
hRC = NULL;
}
if(hDC)
{
ReleaseDC(hWnd, hDC);
}
}
//主程序入口
int WINAPI WinMain( HINSTANCE hInstance, //该实例句柄
HINSTANCE hPrevInstance, //上一个实例
LPSTR lpCmdLine, //启动该实例的命令行参数
int iCmdShow) //程序初始显示方法
{
MSG msg; //windows消息结构
BOOL quit = FALSE; //用来判断是否跳出循环
BOOL fullscreenflag = true; //全屏标志
float theta = 0.0;
if(MessageBox(NULL, TEXT("Would U Like To Run In Fullscreen Mode?"), TEXT("Start Fullscreen?"), MB_YESNO|MB_ICONQUESTION) == IDNO)
{
fullscreenflag = false;
}
if(!CreateGLWindow(TEXT("OpenGL Framework"), 16, fullscreenflag))
{
return 0;
}
ShowWindow(hWnd, SW_SHOW); //只是CreateWindow的话,窗口只是在内存中创建好了,只有调用了ShowWindow后才会显示窗口
//ShowWindow函数在显示窗口时,会发送第一个WM_SIZE消息;但具体是在ShowWindow最后返回前还是其他什么时候,我还不知道
//UpdateWindow(hWnd); //UpdateWindow函数会发送WM_PAINT消息来更新窗口客户区
//由于我们用了OpenGL,所以这里可以不需调用UpdateWindow
while(!quit)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //提取消息,如果此时没有消息,则不等待,立即返回false
{
if(msg.message == WM_QUIT)
{
quit = TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
DrawGLScene();
SwapBuffers( hDC );
}
}
DestroyGLWindow();
return msg.wParam;
}
//窗口过程
LRESULT CALLBACK WndProc( HWND hwnd, //窗口句柄
UINT message, //接收到的消息
WPARAM wParam, //消息的附加参数
LPARAM lParam) //消息的附加参数
{
switch(message)
{
case WM_SIZE: //窗口大小改变,或者第一次显现窗口时(ShowWindow),都将发送该消息
ResizeGLScene(LOWORD(lParam), HIWORD(lParam));
return 0;
case WM_DESTROY:
PostQuitMessage(0); //发送WM_QUIT消息
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//初始化OpenGL一些属性
void InitGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
}
//根据窗口大小的变化
void ResizeGLScene(int width, int height)
{
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
}
//OpenGL绘图
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glLoadIdentity();
gluLookAt( 0.0, 0.0, 5.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
glScalef(1.0, 2.0, 1.0);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0, 1.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glVertex3f( 1.0, -1.0, 0.0);
glEnd();
}