OpenGL教程2.docx

上传人:b****5 文档编号:6953428 上传时间:2023-01-13 格式:DOCX 页数:15 大小:24.50KB
下载 相关 举报
OpenGL教程2.docx_第1页
第1页 / 共15页
OpenGL教程2.docx_第2页
第2页 / 共15页
OpenGL教程2.docx_第3页
第3页 / 共15页
OpenGL教程2.docx_第4页
第4页 / 共15页
OpenGL教程2.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

OpenGL教程2.docx

《OpenGL教程2.docx》由会员分享,可在线阅读,更多相关《OpenGL教程2.docx(15页珍藏版)》请在冰豆网上搜索。

OpenGL教程2.docx

OpenGL教程2

#include

#include//HeaderFileForWindows

#include//HeaderFileForStandardInput/Output

#include//HeaderFileForTheOpenGL32Library

#include//HeaderFileForTheGLu32Library

#include//HeaderFileForTheGlauxLibrary

HGLRChRC=NULL;//窗口着色描述表句柄

HDChDC=NULL;//OpenGL渲染描述表句柄

HWNDhWnd=NULL;//保存我们的窗口句柄

HINSTANCEhInstance;//保存程序的实例

boolkeys[256];//保存键盘按键的数组

boolactive=TRUE;//窗口的活动标志,缺省为TRUE

boolfullscreen=TRUE;//全屏标志缺省,缺省设定成全屏模式

GLfloatxrot;//X转变量

GLfloatyrot;//Y转变量

GLfloatzrot;//Z转变量

GLuinttexture[1];//存储一个纹理

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

AUX_RGBImageRec*LoadBMP(char*Filename){//载入位图图象

FILE*File=NULL;//File句柄

if(!

Filename){//确定文件

returnNULL;

}

File=fopen(Filename,"r");//打开文件

if(File){//存在?

fclose(File);//关闭文件

returnauxDIBImageLoad(Filename);//载入位图,返回指针

}

returnNULL;//载入失败

}

intLoadGLTextures(){//载入位图并转换成纹理

intStatus=FALSE;//状态指示器

/*然后设置一个叫做Status的变量。

我们使用它来跟踪是否能够载入位图以及能否创建纹理。

Status缺省设为FALSE(表示没有载入或创建任何东东)。

*/

AUX_RGBImageRec*TextureImage[1];//创建纹理的存储空间

memset(TextureImage,0,sizeof(void*)*1);//将指针设为NULL,

//清除图像记录,确保其内容为空

if(TextureImage[0]=LoadBMP("Data/NeHe.bmp")){

//载入位图,检查有无错误,如果位图没找到则退出

Status=TRUE;

glGenTextures(1,&texture[0]);//创建纹理

/*使用来自位图数据生成的典型纹理。

现在使用中TextureImage[0]的数据创建纹理。

第一行glGenTextures(1,&texture[0])告诉OpenGL我们想生成一个纹理名字(如果您想载入多个纹理,加大数字)。

值得注意的是,开始我们使用GLuinttexture[1]来创建一个纹理的存储空间,您也许会认为第一个纹理就是存放在&texture[1]中的,但这是错的。

正确的地址应该是&texture[0]。

同样如果使用GLuinttexture[2]的话,第二个纹理存放在texture[1]中。

『译者注:

学C的,在这里应该没有障碍,数组就是从零开始的嘛。

』第二行glBindTexture(GL_TEXTURE_2D,texture[0])告诉OpenGL将纹理名字texture[0]绑定到纹理目标上。

2D纹理只有高度(在Y轴上)和宽度(在X轴上)。

主函数将纹理名字指派给纹理数据。

本例中我们告知OpenGL,&texture[0]处的内存已经可用。

我们创建的纹理将存储在&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);

//*生成纹理下来我们创建真正的纹理。

下面一行告诉OpenGL此纹理是一个2D纹理(GL_TEXTURE_2D)。

参数“0”代表图像的详细程度,通常就由它为零去了。

参数三是数据的成分数。

因为图像是由红色数据,绿色数据,蓝色数据三种组分组成。

TextureImage[0]->sizeX是纹理的宽度。

如果您知道宽度,您可以在这里填入,但计算机可以很容易的为您指出此值。

TextureImage[0]->sizey是纹理的高度。

参数零是边框的值,一般就是“0”。

GL_RGB告诉OpenGL图像数据由红、绿、蓝三色数据组成。

GL_UNSIGNED_BYTE意味着组成图像的数据是无符号字节类型的。

最后...TextureImage[0]->data告诉OpenGL纹理数据的来源。

此例中指向存放在TextureImage[0]记录中的数据。

*/

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

/*线形滤波下面的两行告诉OpenGL在显示图像时,当它比放大得原始的纹理大(GL_TEXTURE_MAG_FILTER)或缩小得比原始得纹理小(GL_TEXTURE_MIN_FILTER)时OpenGL采用的滤波方式。

通常这两种情况下我都采用GL_LINEAR。

这使得纹理从很远处到离屏幕很近时都平滑显示。

使用GL_LINEAR需要CPU和显卡做更多的运算。

如果您的机器很慢,您也许应该采用GL_NEAREST。

过滤的纹理在放大的时候,看起来斑驳的很『译者注:

马赛克啦』。

您也可以结合这两种滤波方式。

在近处时使用GL_LINEAR,远处时GL_NEAREST*/

}

if(TextureImage[0]){//纹理存在?

if(TextureImage[0]->data){//纹理图像存在?

free(TextureImage[0]->data);//释放内存

}

free(TextureImage[0]);//释放图像结构

}

/*现在我们释放前面用来存放位图数据的内存。

我们先查看位图数据是否存放在处。

如果是的话,再查看数据是否已经存储。

如果已经存储的话,删了它。

接着再释放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;

}

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);

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);

returnTRUE;

}

intDrawGLScene(GLvoid){

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0f,0.0f,-5.0f);

glRotatef(xrot,1.0f,0.0f,0.0f);

glRotatef(yrot,0.0f,1.0f,0.0f);

glRotatef(zrot,0.0f,0.0f,1.0f);

glBindTexture(GL_TEXTURE_2D,texture[0]);

/*选择我们使用的纹理。

如果您在您的场景中使用多个纹理,您应该使用来glBindTexture(GL_TEXTURE_2D,texture[所使用纹理对应的数字])选择要绑定的纹理。

当您想改变纹理时,应该绑定新的纹理。

有一点值得指出的是,您不能在glBegin()和glEnd()之间绑定纹理,必须在glBegin()之前或glEnd()之后绑定。

注意我们在后面是如何使用glBindTexture来指定和绑定纹理的。

*/

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);

//BackFace

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);

//TopFace

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);

//BottomFace

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);

//Rightface

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

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();

/*为了将纹理正确的映射到四边形上,您必须将纹理的右上角映射到四边形的右上角,纹理的左上角映射到四边形的左上角,纹理的右下角映射到四边形的右下角,纹理的左下角映射到四边形的左下角。

如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。

glTexCoord2f的第一个参数是X坐标。

0.0f是纹理的左侧。

0.5f是纹理的中点,1.0f是纹理的右侧。

glTexCoord2f的第二个参数是Y坐标。

0.0f是纹理的底部。

0.5f是纹理的中点,1.0f是纹理的顶部。

所以纹理的左上坐标是X:

0.0f,Y:

1.0f,四边形的左上顶点是X:

-1.0f,Y:

1.0f。

其余三点依此类推。

试着玩玩glTexCoord2f的X,Y坐标参数。

把1.0f改为0.5f将只显示纹理的左半部分,把0.0f改为0.5f将只显示纹理的右半部分。

*/

xrot+=0.3f;

yrot+=0.2f;

zrot+=0.4f;

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,创建一个带标题栏、可变大小的边框、菜单和最大化/最小化按钮的窗体。

*/

dwExStyle=WS_EX_APPWINDOW;//扩展窗体风格

dwStyle=WS_PO

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 其它

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1