OpenGL教程3.docx
- 文档编号:22824413
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:20
- 大小:24.30KB
OpenGL教程3.docx
《OpenGL教程3.docx》由会员分享,可在线阅读,更多相关《OpenGL教程3.docx(20页珍藏版)》请在冰豆网上搜索。
OpenGL教程3
#include
#include
#include
#include
#include
#include
HDChDC=NULL;
HGLRChRC=NULL;
HWNDhWnd=NULL;
HINSTANCEhInstance;
boolkeys[256];
boolactive=TRUE;
boolfullscreen=TRUE;
GLuinttexture[1];
GLuintbox;//保存盒子的显示列表
GLuinttop;//保存盒子顶部的显示列表
GLuintxloop;//X轴循环变量
GLuintyloop;//Y轴循环变量
GLfloatxrot;
GLfloatyrot;
staticGLfloatboxcol[5][3]={
{1.0f,0.0f,0.0f},{1.0f,0.5f,0.0f},{1.0f,1.0f,0.0f},{0.0f,1.0f,0.0f},{0.0f,1.0f,1.0f}
};//亮:
红,橙,黄,绿,蓝
staticGLfloattopcol[5][3]={
{.5f,0.0f,0.0f},{0.5f,0.25f,0.0f},{0.5f,0.5f,0.0f},{0.0f,0.5f,0.0f},{0.0f,0.5f,0.5f}
};//暗:
红,橙,黄,绿,蓝
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);//DeclarationForWndProc
/*现在正式开始建立显示列表。
你可能注意到了,所有创造盒子的代码都在第一个显示列表里,所有创造顶部的代码都在另一个列表里。
我会努力解释这些细节。
*/
GLvoidBuildLists(){
box=glGenLists
(2);//创建两个显示列表的名称
/*开始的时候我们告诉OpenGL我们要建立两个显示列表。
glGenLists
(2)建立了两个显示列表的空间,并返回第一个显示列表的指针。
“box”指向第一个显示列表,任何时候调用“box”第一个显示列表就会显示出来。
*/
glNewList(box,GL_COMPILE);//创建第一个显示列表t
/*现在开始构造第一个显示列表。
我们已经申请了两个显示列表的空间了,并且有box指针指向第一个显示列表。
所以现在我们应该告诉OpenGL要建立什么类型的显示列表。
我们用glNewList()命令来做这个事情。
你一定注意到了box是第一个参数,这表示OpenGL将把列表存储到box所指向的内存空间。
第二个参数GL_COMPILE告诉OpenGL我们想预先在内存中构造这个列表,这样每次画的时候就不必重新计算怎么构造物体了。
GL_COMPILE类似于编程。
在你写程序的时候,把它装载到编译器里,你每次运行程序都需要重新编译。
而如果他已经编译成了.exe文件,那么每次你只需要点击那个.exe文件就可以运行它了,不需要编译。
当OpenGL编译过显示列表后,就不需要再每次显示的时候重新编译它了。
这就是为什么用显示列表可以加快速度。
*/
glBegin(GL_QUADS);
//BottomFace
glNormal3f(0.0f,-1.0f,0.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);
//FrontFace
glNormal3f(0.0f,0.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);
//BackFace
glNormal3f(0.0f,0.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);
//Rightface
glNormal3f(1.0f,0.0f,0.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);
//LeftFace
glNormal3f(-1.0f,0.0f,0.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();
/*代码画出一个没有顶部的盒子,它不会出现在屏幕上,只会存储在显示列表里。
你可以在glNewList()和glEngList()中间加上任何你想加上的代码。
可以设置颜色,贴图等等。
唯一不能加进去的代码就是会改变显示列表的代码。
显示列表一旦建立,你就不能改变它。
比如你想加上glColor3ub(rand()%255,rand()%255,rand()%255),使得每一次画物体时都会有不同的颜色。
但因为显示列表只会建立一次,所以每次画物体的时候颜色都不会改变。
物体将会保持第一次建立显示列表时的颜色。
如果你想改变显示列表的颜色,你只有在调用显示列表之前改变颜色。
后面将详细解释这一点。
用glEngList()命令,我们告诉OpenGL我们已经完成了一个显示列表。
在glNewList()和glEngList()之间的任何东西就是显示列表的一部分。
*/
glEndList();
/*用glEngList()命令,我们告诉OpenGL我们已经完成了一个显示列表。
在glNewList()和glEngList()之间的任何东西就是显示列表的一部分。
*/
top=box+1;//第二个显示列表的名称
glNewList(top,GL_COMPILE);//盒子顶部的显示列表
glBegin(GL_QUADS);
glNormal3f(0.0f,1.0f,0.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);
glEnd();
glEndList();
}
AUX_RGBImageRec*LoadBMP(char*Filename){
FILE*File=NULL;
if(!
Filename){
returnNULL;
}
File=fopen(Filename,"r");
if(File){
fclose(File);
returnauxDIBImageLoad(Filename);
}
returnNULL;
}
intLoadGLTextures(){
/*贴图纹理的代码和之前教程里的代码是一样的。
我们需要一个可以贴在立方体上的纹理。
我决定使用mipmapping处理让纹理看上去光滑,因为我讨厌看见像素点。
纹理的文件名是“cube.bmp”,存放在data目录下。
*/
intStatus=FALSE;
AUX_RGBImageRec*TextureImage[1];
memset(TextureImage,0,sizeof(void*)*1);
if(TextureImage[0]=LoadBMP("Data/Cube.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]);
}
returnStatus;
}
GLvoidReSizeGLScene(GLsizeiwidth,GLsizeiheight){
if(height==0){
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();
}
intInitGL(GLvoid){
if(!
LoadGLTextures()){
returnFALSE;
}
BuildLists();
/*初始化的代码只有一点改变,加入了一行BuildList()。
请注意代码的顺序,先读入纹理,然后建立显示列表,这样当我们建立显示列表的时候就可以将纹理贴到立方体上了。
*/
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f,0.0f,0.0f,0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_LIGHT0);//使用默认的0号灯
glEnable(GL_LIGHTING);//使用灯光
glEnable(GL_COLOR_MATERIAL);//使用颜色材质
/*使灯光有效。
Light0一般来说是在显卡中预先定义过的,如果Light0不工作,把下面那行注释掉好了。
最后一行的GL_COLOR_MATERIAL使我们可以用颜色来贴纹理。
如果没有这行代码,纹理将始终保持原来的颜色,glColor3f(r,g,b)就没有用了。
总之这行代码是很有用的。
*/
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
returnTRUE;
}
intDrawGLScene(GLvoid){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D,texture[0]);
for(yloop=1;yloop<6;yloop++){//沿Y轴循环
for(xloop=0;xloop glLoadIdentity();glTranslatef(1.4f+(float(xloop)*2.8f)-(float(yloop)*1.4f),((6.0f-float(yloop))*2.4f)-7.0f,-20.0f);//设置盒子的位置 glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f); glRotatef(45.0f+yrot,0.0f,1.0f,0.0f); glColor3fv(boxcol[yloop-1]); glCallList(box); /*颜色设置好了。 现在需要做的就是画出盒子。 不用写出画多边形的代码,只需要用glCallList(box)命令调用显示列表。 盒子将会用glColor3fv()所设置的颜色画出来。 */ glColor3fv(topcol[yloop-1]); glCallList(top); } } /*用一个循环,循环变量用于改变Y轴位置,在Y轴上画5个立方体,所以用从1到5的循环。 */ returnTRUE; } GLvoidKillGLWindow(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;//将RC设为NULL } if(hDC&&! ReleaseDC(hWnd,hDC)){//我们能否释放DC? MessageBox(NULL,"释放DC失败。 ","关闭错误",MB_OK|MB_ICONINFORMATION); hDC=NULL;//将DC设为NULL } if(hWnd&&! DestroyWindow(hWnd)){//能否销毁窗口? MessageBox(NULL,"释放窗口句柄失败。 ","关闭错误",MB_OK|MB_ICONINFORMATION); hWnd=NULL;//将hWnd设为NULL } if(! UnregisterClass("OpenG",hInstance)){//能否注销类? MessageBox(NULL,"不能注销窗口类。 ","关闭错误",MB_OK|MB_ICONINFORMATION); hInstance=NULL;//将hInstance设为NULL } } BOOLCreateGLWindow(char*title,intwidth,intheight,intbits,boolfullscreenflag){ GLuintPixelFormat;//保存查找匹配的结果 WNDCLASSwc;//窗口类结构 DWORDdwExStyle;//扩展窗口风格 DWORDdwStyle;//窗口风格 RECTWindowRect;//取得矩形的左上角和右下角的坐标值 WindowRect.left=(long)0;//将Left设为0 WindowRect.right=(long)width;//将Right设为要求的宽度 WindowRect.top=(long)0;//将Top设为0 WindowRect.bottom=(long)height;//将Bottom设为要求的高度 fullscreen=fullscreenflag;//设置全局全屏标志 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="OpenG";//设定类名字 if(! RegisterClass(&wc)){//尝试注册窗口类 MessageBox(NULL,"注册窗口失败","错误",MB_OK|MB_ICONEXCLAMATION); returnFALSE;//退出并返回FALSE } if(fullscreen){//要尝试全屏模式吗? DEVMODEdmScreenSettings;//设备模式 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使用窗口模式? ","NeHeG",MB_YESNO|MB_ICONEXCLAMATION)==IDYES){ fullscreen=FALSE;//选择窗口模式(Fullscreen=FALSE) }else{ MessageBox(NULL,"程序将被关闭","错误",MB_OK|MB_ICONSTOP); returnFALSE;//退出并返回FALSE } } } if(fullscreen){//仍处于全屏模式吗? /*如果我们仍处于全屏模式,设置扩展窗体风格为WS_EX_APPWINDOW,这将强制我们的窗体可见时处于最前面。 再将窗体的风格设为WS_POPUP。 这个类型的窗体没有边框,使我们的全屏模式得以完美显示。 最后我们禁用鼠标指针。 当您的程序不是交互式的时候,在全屏模式下禁用鼠标指针通常是个好主意。 如果我们使用窗口而不是全屏模式,我们在扩展窗体风格中增加了WS_EX_WINDOWEDGE,增强窗体的3D感观。 窗体风格改用WS_OVERLAPPEDWINDOW,创建一个带标题栏、可变大小的边框、菜单和最大化
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- OpenGL 教程
![提示](https://static.bdocx.com/images/bang_tan.gif)