OpenGL教程2Word格式文档下载.docx
《OpenGL教程2Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《OpenGL教程2Word格式文档下载.docx(15页珍藏版)》请在冰豆网上搜索。
//存储一个纹理
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是纹理的宽度。
如果您知道宽度,您可以在这里填入,但计算机可以很容易的为您指出此值。
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]->
//释放内存
}
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);
intInitGL(GLvoid){
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);
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
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,1.0f,-1.0f);
glVertex3f(1.0f,1.0f,-1.0f);
glVertex3f(1.0f,-1.0f,-1.0f);
//TopFace
//BottomFace
//Rightface
//LeftFace
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;
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);
wglDeleteContext(hRC)){//我们能否删除RC?
MessageBox(NULL,"
释放RC失败。
hRC=NULL;
//将RC设为NULL
if(hDC&
&
!
ReleaseDC(hWnd,hDC)){//我们能否释放DC?
释放DC失败。
hDC=NULL;
//将DC设为NULL
if(hWnd&
DestroyWindow(hWnd)){//能否销毁窗口?
释放窗口句柄失败。
hWnd=NULL;
//将hWnd设为NULL
UnregisterClass("
OpenG"
hInstance)){//能否注销类?
不能注销窗口类。
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="
;
//设定类名字
RegisterClass(&
wc)){//尝试注册窗口类
注册窗口失败"
错误"
MB_OK|MB_ICONEXCLAMATION);
//退出并返回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