学习了《NeHe's OpenGL Tutorials》后感觉其程序结构设计并不是太理想,因此在此基础之上重写了部分代码:
说明:
首先在在Visual C++6.0中建立一个Win32 Application的空Project;
其次在Visual C++6.0中配置OpenGL,方法有两种:1.Project->Settings->Link选项卡的Project Options栏中添加OpenGL32.lib GLu32.lib GLaux.lib于kernel32.lib之前,中间用空格隔开,点击“OK”退出。2.在WinMain函数同一文件中添加:
#pragma comment( lib, "opengl32.lib") // OpenGL32连接库
#pragma comment( lib, "glu32.lib") // GLu32连接库
#pragma comment( lib, "glaux.lib") // GLaux连接库
另外要运行该程序选择6张bmp格式的图片大小为:200px,分辨率最好为:72dpi。将该6张图片依次命名为:OpenGL01.bmp,OpenGL02.bmp,OpenGL03.bmp,OpenGL04.bmp,OpenGL05.bmp,OpenGL06.bmp,并将其放于你所创建的工程文件目录中(直接运行*.exe时,图片和可执行文件放在同一目录下)。
按照以上设置完成后即可将以下代码复制到相应的文件中并添加到(Project->Add To Project->Files)你所建立的工程文件。
头文件:stdafx.h的源代码
#define WIN32_LEAN_AND_MEAN //从Windows中排除极少使用的资料
#include <windows.h> //Windows头文件
#include <stdio.h> //标准输入输出文件
#include <GL\gl.h> //OpenGL32库的头文件
#include <GL\glu.h> //glu32库的头文件
#include <GL\glaux.h> //glaux库的头文件
#include "OpenGL.h"
头文件:OpenGL.h的源代码
class OpenGL
{
private:
GLuint Texture[6]; //纹理数据存储
public:
GLvoid ReSizeGLScene(GLsizei width,GLsizei height); //重设并初始化窗口大小
int InitGL(GLvoid); //对OpenGL进行所有设置
int DrawGLScene(GLvoid); //进行所有绘制
AUX_RGBImageRec *LoadBMP(char *Filename); //载入位图图象
bool LoadGLTextures(char *Filename,GLuint &texture); //载入位图并转换为纹理
};
cpp文件:WinMain.cpp的源代码
//包含头文件
#include "stdafx.h" //包含全局头文件
//函数声明
bool CreateGLWindow(char,int,int,int,bool); //创建窗口
GLvoid KillGLWindow(GLvoid); //正常销毁窗口
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//接收消息
//全局变量
HGLRC hRC = NULL; //永久着色描述表
HDC hDC = NULL; //私有你GDI设备描述表
HWND hWnd = NULL; //保存我们的窗口句柄
HINSTANCE hInstance; //保存程序的实例
bool keys[256] = {false}; //用于键盘例程的数组
bool bActive = true; //窗口的活动标志
bool bFullscreen = true; //全屏标志,默认使用全屏
OpenGL *myGL = new OpenGL(); //类申请
char *Title = "OpenGL RGB Studio";//窗口标题
//函数
bool CreateGLWindow(char *title,int width,int height,int bits,bool bFullScreenFlag)
{
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为要求的高度
bFullscreen=bFullScreenFlag; //设置全屏标志
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; //不需要菜单
wc.lpszClassName = "OpenGL"; //设定类名字
if(!RegisterClass(&wc)) //注册窗口类
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(bFullscreen) //全屏
{
DEVMODE dmScreenSettings; //设备模式
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //内存分配
dmScreenSettings.dmSize = sizeof(dmScreenSettings); //Devmode结构的大小
dmScreenSettings.dmPelsWidth = width; //屏幕宽度
dmScreenSettings.dmPelsHeight = height; //屏幕高度
dmScreenSettings.dmBitsPerPel = bits; //每象素所选的色彩深度
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{ //设置显示模式并返回结果
if(MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By Your Video Card. Use Window Mode Instead?","OpenGL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{ //若设置失败则退出或者在窗口运行
bFullscreen=false; //选择窗口模式
}
else
{
MessageBox(NULL,"Program Will Close Now.","ERROR",MB_OK|MB_ICONSTOP);
return false;
}
}
}
if(bFullscreen) //是否全屏
{
dwExStyle = WS_EX_APPWINDOW; //扩展窗体风格
dwStyle = WS_POPUP; //窗体风格
ShowCursor(false); //隐藏鼠标指针
}
else
{
dwExStyle = WS_EX_APPWINDOW|WS_EX_WINDOWEDGE; //扩展窗体风格
dwStyle = WS_OVERLAPPEDWINDOW; //窗体风格
}
AdjustWindowRectEx(&WindowRect,dwStyle,false,dwExStyle);//调整窗口达到真正要求的大小
//以下用于计算初始时的窗口位置
int wid = GetSystemMetrics(SM_CXSCREEN); // 获取当前屏幕宽
int hei = GetSystemMetrics(SM_CYSCREEN); // 获取当前屏幕高
int Width = WindowRect.right-WindowRect.left; //窗口的宽度
int Height = WindowRect.bottom-WindowRect.top; //窗口的高度
if (!(hWnd=CreateWindowEx(dwExStyle, //扩展窗体风格
"OpenGL", //类名字
title, //窗口标题
WS_CLIPSIBLINGS| //必须的窗体风格属性
WS_CLIPCHILDREN| //必须的窗体风格属性
dwStyle, //选择的窗体属性
(wid-Width)/2,(hei-Height)/2, //窗口位置居中
WindowRect.right-WindowRect.left, //计算调整好的窗口宽度
WindowRect.bottom-WindowRect.top, //计算调整好的窗口高度
NULL, //无父窗口
NULL, //无菜单
hInstance, //实例
NULL))) //不向WM_CREATE传递任何东东
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
static PIXELFORMATDESCRIPTOR pfd= //pfd 告诉窗口我们所希望的东东
{
sizeof(PIXELFORMATDESCRIPTOR), //上诉格式描述符的大小
1, // 版本号
PFD_DRAW_TO_WINDOW| //格式必须支持窗口
PFD_SUPPORT_OPENGL| //格式必须支持OpenGL
PFD_DOUBLEBUFFER, //必须支持双缓冲
PFD_TYPE_RGBA, //申请RGBA格式
bits, //选定色彩深度
0,0,0,0,0,0, //忽略的色彩位
0, //无Alpha缓存
0, //忽略Shift Bit
0, //无聚集缓存
0,0,0,0, //忽略聚集位
16, //16位Z-缓存(深度缓存)
0, //无模板缓存
0, //无辅助缓存
PFD_MAIN_PLANE, //主绘图层
0, //保留
0,0,0 //忽略层遮罩
};
if(!(hDC=GetDC(hWnd))) //是否取得设备描述表
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) //是否找到相应的象素格式
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) //是否能够设置象素格式
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(!(hRC=wglCreateContext(hDC))) //能否取得着色描述表?
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Can’t Create A GL Rendering Context.",
"ERROR",MB_OK|MB_ICONEXCLAMATION);
return false; //返回 FALSE
}
if(!wglMakeCurrent(hDC,hRC)) //尝试激活着色描述表
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Can’t Activate The GL Rendering Context.",
"ERROR",MB_OK|MB_ICONEXCLAMATION);
return false; //返回 FALSE
}
ShowWindow(hWnd,SW_SHOW); //显示窗口
SetForegroundWindow(hWnd); //略略提高优先级
SetFocus(hWnd); //设置键盘的焦点至此窗口
myGL->ReSizeGLScene(width, height); //设置透视GL屏幕
if(!myGL->InitGL()) //初始化新建的GL窗口
{
KillGLWindow(); //重置显示区
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false; //返回 FALSE
}
return true; //成功
}
GLvoid KillGLWindow(GLvoid) //正常销毁窗口
{
if(bFullscreen) //是否处于全屏状态
{
ChangeDisplaySettings(NULL,0); //换回桌面
ShowCursor(true); //显示鼠标指针
}
if(hRC!=NULL) //是否拥有颜色着色表
{
if(!wglMakeCurrent(NULL,NULL)) //能否释放DC和RC描述表
{
MessageBox(NULL,"Release DC And RC Failed.","ERROR",MB_OK|MB_ICONINFORMATION);
}
if(!wglDeleteContext(hRC)) //能否删除RC
{
MessageBox(NULL,"Release Rendering Context Failed.","ERROR",MB_OK|MB_ICONINFORMATION);
}
hRC=NULL;
}
if(hDC&&!ReleaseDC(hWnd,hDC)) //能否释放DC
{
MessageBox(NULL,"Could not Release Device Context.","ERROR",MB_OK|MB_ICONINFORMATION);
hDC=NULL;
}
if(hWnd&&!DestroyWindow(hWnd)) //能否销毁窗口
{
MessageBox(NULL,"Could not Release hWnd.","ERROR",MB_OK|MB_ICONINFORMATION);
hWnd=NULL;
}
if(!UnregisterClass("OpenGL",hInstance))
{ //能否注销类
MessageBox(NULL,"Could Not Unregister Class.","ERROR",MB_OK|MB_ICONINFORMATION);
hInstance=NULL;
}
}
LRESULT CALLBACK WndProc(HWND hWnd, //窗口的句柄
UINT uMsg, //窗口的消息
WPARAM wParam, //附加的消息内容
LPARAM lParam) //附加的消息内容
{
switch(uMsg) //检查Windows消息
{
case WM_ACTIVATE: //监视窗口激活消息
{
if(!HIWORD(wParam)) //检查最小化状态
{
bActive=true; //程序处于激活状态
}
else
{
bActive=false; //程序不再激活
}
return 0; //返回消息循环
}
case WM_SYSCOMMAND: //中断系统命令Intercept System Commands
{
switch (wParam) //检查系统调用Check System Calls
{
case SC_SCREENSAVE: //屏保要运行
case SC_MONITORPOWER: //显示器要进入节电模式
return 0; //阻止发生
}
break; // 退出
}
case WM_CLOSE: //收到Close消息
{
PostQuitMessage(0); //发出退出消息
return 0;
}
case WM_KEYDOWN: //有键按下
{
keys[wParam]=true;
return 0;
}
case WM_KEYUP: //有键放开
{
switch(wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
default:
break;
}
keys[wParam]=false;
return 0;
}
case WM_SIZE:
{
myGL->ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
return 0;
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam); //向 DefWindowProc传递所有未处理的消息。
}
int WINAPI WinMain( HINSTANCE hInstance, //实例
HINSTANCE hPrevInstance, //前一个实例
LPSTR lpCmdLine, //命令行参数
int nCmdShow) // 窗口显示状态
{
MSG msg; //Windowsx消息结构
bool bExit=false; //用来退出循环的Bool变量
myGL=new OpenGL(); //OpenGL类申请
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?",
"Start Fullscreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{ // 提示用户选择运行模式
bFullscreen=false; //窗口模式
}
if (!CreateGLWindow(Title,640,480,16,bFullscreen))
{ //创建OpenGL窗口
return 0; //失败退出
}
while(!bExit) //保持循环直到bExit=true
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))//是否有消息在等待
{
if (msg.message==WM_QUIT) //是否收到退出消息
{
bExit=true; //bExit=true则退出
}
else //不是,处理窗口消息
{
TranslateMessage(&msg); //翻译消息
DispatchMessage(&msg); //发送消息
}
}
else
{
if(bActive) //窗口是否处于最小化状态
{
myGL->DrawGLScene(); //绘制场景
SwapBuffers(hDC); //交换缓存(双缓存)
}
}
}
KillGLWindow(); //销毁窗口
delete myGL; //删除类指针
return (msg.wParam); //退出程序
}
cpp文件:OpenGL.cpp的源代码
#include "stdafx.h"
AUX_RGBImageRec *OpenGL::LoadBMP(char *filename) //载入位图图象
{
FILE *pFile=NULL; //位图文件指针
if(!filename)
{
return NULL;
}
pFile=fopen(filename,"r");
if(pFile!=NULL)
{
fclose(pFile);
return auxDIBImageLoad(filename); //载入位图
}
return NULL;
}
bool OpenGL::LoadGLTextures(char *filename,GLuint &texture) //载入位图并转换为纹理
{
bool bStatus=false;
AUX_RGBImageRec *TextureImage=new AUX_RGBImageRec; //创建纹理的存储空间
memset(TextureImage,0,sizeof(void *)*1);
if(TextureImage=LoadBMP(filename))
{
bStatus=true;
glGenTextures(1,&texture); //创建纹理
glBindTexture(GL_TEXTURE_2D,texture); //使用来自位图的数据生成的典型纹理
gluBuild2DMipmaps(GL_TEXTURE_2D,3, TextureImage->sizeX,
TextureImage->sizeY,GL_RGB, GL_UNSIGNED_BYTE,TextureImage->data);
// glTexImage2D(GL_TEXTURE_2D,0,3,
// TextureImage->sizeX,TextureImage->sizeY,
// 0,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//线型滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//线型滤波
}
if(TextureImage!=NULL) //纹理是否存在
{
if(TextureImage->data) //纹理图像是否存在
{
delete TextureImage->data; //释放纹理图像占用的内存
}
delete TextureImage; //释放图像结构
}
return bStatus;
}
GLvoid OpenGL::ReSizeGLScene(GLsizei width,GLsizei height)
//重设并初始化窗口大小
{
if(height==0) //防止被0除
{
height=1; //将height设为1
}
glViewport(0,0,width,height); //重置当前的视口
glMatrixMode(GL_PROJECTION); //选择投影矩阵
glLoadIdentity(); //重设投影矩阵
gluPerspective(45.0,(GLfloat)width/(GLfloat)height,0.01f,1000.0f); //计算窗口的外观比例
glMatrixMode(GL_MODELVIEW); //选择模型观察矩阵
glLoadIdentity(); //重设模型观察矩阵
}
int OpenGL::InitGL(GLvoid) //对OpenGL进行所有设置
{
LoadGLTextures("OpenGL01.bmp",Texture[0]); //载入纹理1
LoadGLTextures("OpenGL02.bmp",Texture[1]); //载入纹理2
LoadGLTextures("OpenGL03.bmp",Texture[2]); //载入纹理3
LoadGLTextures("OpenGL04.bmp",Texture[3]); //载入纹理4
LoadGLTextures("OpenGL05.bmp",Texture[4]); //载入纹理5
LoadGLTextures("OpenGL06.bmp",Texture[5]); //载入纹理6
glEnable(GL_TEXTURE_2D); //启用纹理映射
glShadeModel(GL_SMOOTH); //启用阴影平滑
glClearColor(0.0f,0.0f,0.0f,0.0f); //窗口背景选择为黑色
glClearDepth(1.0f); //设置深度缓存
glEnable(GL_DEPTH_TEST); //启用深度测试
glDepthFunc(GL_LEQUAL); //所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //真正精细的透视修正
return true;
}
int OpenGL::DrawGLScene(GLvoid) //从这里开始进行所有绘制
{
static float spin=0.0f;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
glLoadIdentity(); //重设投影矩阵
glTranslatef(0.0f,0.0f,-10.0f); //向内平移10
glRotatef(spin+=0.05f,1.0f,1.0f,1.0f); //自转转spin角度
glBindTexture(GL_TEXTURE_2D,Texture[0]); //选择纹理
glBegin(GL_QUADS);
// 前面
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();
glBindTexture(GL_TEXTURE_2D,Texture[1]); //选择纹理
glBegin(GL_QUADS);
//后面
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); //纹理和四边形的左下
glEnd();
glBindTexture(GL_TEXTURE_2D,Texture[2]); //选择纹理
glBegin(GL_QUADS);
// 顶面
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); //纹理和四边形的右上
glEnd();
glBindTexture(GL_TEXTURE_2D,Texture[3]); //选择纹理
glBegin(GL_QUADS);
//底面
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); //纹理和四边形的右下
glEnd();
glBindTexture(GL_TEXTURE_2D,Texture[4]); //选择纹理
glBegin(GL_QUADS);
// 右面
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); //纹理和四边形的左下
glEnd();
glBindTexture(GL_TEXTURE_2D,Texture[5]); //选择纹理
glBegin(GL_QUADS);
// 左面
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();
return true;
}