OpenGL源代码之六纹理映射

来源:互联网 发布:17173天谕捏脸数据 编辑:程序博客网 时间:2024/05/01 21:05
更多精彩内容,请见:http://www.16boke.com

by zxy,编程交流QQ群:168424095
//在窗口和全屏模式下切换,按ESC退出。
#include <Windows.h> //Windows的头文件
#include <gl/glut.h> //包含OpenGL实用库
#include <stdio.h> //标志输入/输出库的头文件
#include <gl/glaux.h> //包含OpenGL实用库

#pragma comment( lib, "glaux.lib")  // GLaux连接库 auxDIBImageLoad

HGLRC hRC=NULL; //窗口着色描述表句柄
HDC hDC=NULL;//OpenGL渲染描述表句柄
HWND hWnd=NULL; //保存窗口句柄
HINSTANCE hInstance; //保存程序实例

bool keys[256];//保存键盘按键的数组
bool active=TRUE;//窗口的活动标志,缺省为TRUE
bool fullscreen=TRUE; //全屏标志缺省,缺省设定成全屏模式

GLfloat xrot; //X旋转量
GLfloat yrot; 
GLfloat zrot;
GLuint texture[1];//存储一个纹理

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//WndProc的定义

AUX_RGBImageRec *LoadBMP(char *Filename) //载入位图图像
{
FILE *File=NULL; //文件句柄
if(!Filename)//确保文件名已提供
{
return NULL;
}
File=fopen(Filename,"r");//尝试打开文件


if(File)
{
fclose(File);
return auxDIBImageLoad(Filename);//载入位图并返回指针
}

return NULL;
}

//载入位图并转换成纹理
int LoadGLTextures()
{
int Status=FALSE;//状态指示器
AUX_RGBImageRec *TextureImage[1];//创建纹理的存储空间
memset(TextureImage,0,sizeof(void *)*1);//将指针设为NULL


//载入位图,检查有无错误,如果位图没找到则退出
if(TextureImage[0]=LoadBMP("Data/pugongying.bmp"))
{
Status = TRUE;
glGenTextures(1,&texture[0]);//创建纹理
//使用来自位图数据生成的典型纹理
glBindTexture(GL_TEXTURE_2D,texture[0]);
//生成纹理
glTexImage2D(GL_TEXTURE_2D,0,3,TextureImage[0]->sizeX,
TextureImage[0]->sizeY,0,GL_RGB,GL_UNSIGNED_BYTE,
TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//线形滤波
}
if(TextureImage[0])//纹理是否存在
{
if(TextureImage[0]->data)//纹理图像是否存在
{
free(TextureImage[0]->data);//是否纹理图像占用的内存
}
free(TextureImage[0]);//是否图像结构
}
return Status;
}

//重置OpenGL窗口大小
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();//重置模型观察矩阵
}


int InitGL(GLvoid)//对OpenGL进行设置
{
if(!LoadGLTextures())//调用纹理载入子例程
{
return FALSE;
}


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 DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除屏幕和深度缓存
glLoadIdentity();//重置当前的模型观察矩阵
glTranslatef(0.0f,0.0f,-5.0f);//移入屏幕5.0


glRotatef(xrot,1.0f,0.0f,0.0f);//绕X轴旋转
glRotatef(yrot,0.0f,1.0f,0.0f);//绕Y轴旋转
glRotatef(zrot,0.0f,0.0f,1.0f);//绕Z轴旋转


glBindTexture(GL_TEXTURE_2D,texture[0]);//选择纹理
glScalef(0.5f,0.5f,0.5f);//绘制图形沿X,Y,Z轴各缩小一半,物体变小。

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);//左上


//后面
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);//右下


//顶面
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);//右上


//底面
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);//右下


//右面
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);//右下


//左面
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 +=0.02f;   
yrot +=0.015f; 
zrot +=0.03f;


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)) //能否删除RC
{
MessageBox(NULL,"释放RC失败。","关闭错误",MB_OK | MB_ICONINFORMATION );
}


hRC = NULL;
}


if(hDC && !ReleaseDC(hWnd,hDC)) //能否释放DC
{
MessageBox(NULL,"释放DC失败。","关闭错误",MB_OK | MB_ICONINFORMATION );
hDC = NULL;
}


if(hWnd && !DestroyWindow(hWnd)) //能否销毁窗口
{
MessageBox(NULL,"释放窗口句柄失败。","关闭错误",MB_OK | MB_ICONINFORMATION );
hWnd = NULL;
}


if(!UnregisterClass("OpenGL",hInstance)) //能否注销窗口类
{
MessageBox(NULL,"不能注销窗口类。","关闭错误",MB_OK | MB_ICONINFORMATION );
hInstance = NULL;
}
}


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;
WindowRect.bottom=(long)height;


fullscreen = fullscreenflag;//设置全局全屏标志


hInstance         = GetModuleHandle(NULL);//取得窗口的实例
wc.style          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;//移动时重画,并为窗口取得DC
wc.lpfnWndProc    = WndProc;//WndProc处理消息
wc.cbClsExtra     = 0;//无额外窗口数据Specifies the number of extra bytes to allocate following the window-class structure. 
wc.cbWndExtra     = 0; //无额外窗口数据Specifies the number of extra bytes to allocate following the window instance.
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,"注册窗口失败","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


if(fullscreen)
{
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;


//尝试设置显示模式并返回结果。注:CDS_FULLSCREEN移去了状态条。
if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
//若模式失败,提供两个选项:退出或在窗口内运行。
if(MessageBox(NULL,"全屏模式在当前显卡上设置失败!\n使用窗口模式?",
"提示",MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
fullscreen = FALSE;//选择窗口模式
}
else
{
//弹出一个对话框,告诉用户程序结束
MessageBox(NULL,"程序将被关闭","错误",MB_OK | MB_ICONSTOP);
return FALSE;
}
}
}


if(fullscreen)
{
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);//调整窗口达到真正要求的大小


//窗体自适应各种分辨率以居中方式显示
LONG nX, nY;


nX = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
nY = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;


if(!(hWnd = CreateWindowEx(dwExStyle, //扩展窗体风格
"OpenGL", //类名字
title,    //窗口标题
WS_CLIPSIBLINGS | WS_CLIPCHILDREN| //必须的窗体风格属性
dwStyle,   //选择的窗体属性
nX,nY,   //窗口位置
WindowRect.right - WindowRect.left, //计算调整好的窗口宽度
WindowRect.bottom - WindowRect.top, //计算调整好的窗体高度
NULL, //无父窗口
NULL, //无菜单
hInstance, //实例
NULL))) //不向WM_CREATE传递任何东西
{
KillGLWindow();//重置显示区
MessageBox(NULL,"不能创建一个窗口设备描述表","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


static PIXELFORMATDESCRIPTOR pfd = //pdf告诉窗口希望的东西,即窗口使用的像素格式
{
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,                 //Reserved
0,0,0              //忽略层遮罩
};


if(!(hDC = GetDC(hWnd))) //是否取得设备描述表
{
KillGLWindow();//重置显示区
MessageBox(NULL,"不能创建一种相匹配的像素格式","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


if(!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) //Windows是否找到相应的像素格式
{
KillGLWindow();//重置显示区
MessageBox(NULL,"不能设置像素格式","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


if(!SetPixelFormat(hDC,PixelFormat,&pfd)) //是否能够设置像素格式
{
KillGLWindow();//重置显示区
MessageBox(NULL,"不能设置像素格式","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


if (!(hRC = wglCreateContext(hDC))) //能否取得着色描述表
{
KillGLWindow();//重置显示区
MessageBox(NULL,"不能创建OpenGL渲染描述表","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


if(!wglMakeCurrent(hDC,hRC)) //尝试激活着色描述表
{
KillGLWindow();
MessageBox(NULL,"不能激活当前的OpenGL渲染描述表","错误",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


ShowWindow(hWnd,SW_SHOW);//显示窗口
SetForegroundWindow(hWnd);//提供优先级别
SetFocus(hWnd);//设置键盘的焦点至此窗口
ResizeGLScene(width,height);//设置透视GL屏幕


if (!InitGL()) //初始化新建的GL窗口
{
KillGLWindow();
MessageBox(NULL,"Initialization","ERROR",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}


return TRUE;
}


//处理所有的窗口消息
LRESULT CALLBACK WndProc(HWND hWnd,//窗口的句柄
UINT uMsg,//窗口的消息
WPARAM wParam,//附加的消息内容
LPARAM lParam) //附加的消息内容
{
switch(uMsg) //检查检查Windows消息
{
case WM_ACTIVATE:  //监视窗口激活消息
{
if(!HIWORD(wParam)) //检查最小化状态
{
active = TRUE; //程序处于激活状态
}
else
{
active = FALSE;//程序不再激活
}


return 0;//返回消息循环
}


case WM_SYSCOMMAND: //系统中断命令
{
switch(wParam) //检查系统调用
{
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: //有键放开
{
keys[wParam] = FALSE;
return 0;
}
case WM_SIZE: //调整OpenGL窗口大小
{
ResizeGLScene(LOWORD(lParam),HIWORD(lParam));//LOWORD=width,HIWORD=height
return 0;
}
}


//向DefWindowProc传递所有未处理的消息
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}


//Windows程序的入口,调用窗口创建例程,处理窗口消息,并监视人机交互。
int WINAPI WinMain(HINSTANCE hInstance,//当前窗口实例
  HINSTANCE hPrevInstance, //前一个窗口实例
  LPSTR lpCmdLine, //命令行参数
  int nCmdShow) //窗口显示状态
{
MSG msg;//Windows消息结构
BOOL done=FALSE;//用来退出循环的BOOL变量
//提示用户选择运行模式
if (MessageBox(NULL,"你想在全屏模式下运行么?","设置全屏模式",MB_YESNO | MB_ICONQUESTION) == IDNO)
{
fullscreen = FALSE; //设置为窗口模式
}


//创建OpenGL窗口
if(!CreateGLWindow("OpenGL程序框架",640,480,16,fullscreen))
{
return 0;       //失败退出
}


while(!done)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //是否有消息在等待
{
if(msg.message == WM_QUIT) //收到退出消息
{
done = TRUE;
}
else //处理窗口消息
{
TranslateMessage(&msg);  //翻译消息
DispatchMessage(&msg);   //发送消息
}
}
else //如果没有消息
{
//绘制场景。监视ESC键和来自DrawGLScene()的退出消息
if(active)
{
if(keys[VK_ESCAPE])
{
done = TRUE;
}
else //没有退出,刷新屏幕
{
DrawGLScene();//绘制场景
SwapBuffers(hDC);//交换缓存(双缓存)
}
}
if(keys[VK_F1])
{
keys[VK_F1]=FALSE;
KillGLWindow();
fullscreen = !fullscreen;//切换全屏/窗口模式
//重建OpenGL窗口
if(!CreateGLWindow("3D旋转实例",640,480,16,fullscreen))
{
return 0;
}
}
}
}


//关闭程序
KillGLWindow(); //销毁窗口
return (msg.wParam); //退出程序
}


更多精彩内容,请见:http://www.16boke.com
原创粉丝点击