关闭

OpenGL曲面纹理贴图技术--波浪的模拟(转 作者 Y_Y)

1716人阅读 评论(0) 收藏 举报
 
    学过OpenGL的人都很容易的把图片贴到四边形和三角行上,但将纹理贴到一般的曲面上认为很困难,其实

通过本文的简单分析,其实很简单。本文以波浪模拟为例,来介绍一般纹理贴图技术,大家很容易举一反三来

模拟其他的现象。代码的蓝本主要来自NeHe。
1.简单的数学知识介绍

向量的乘积(这里指叉乘)。
用程序写出来如下。

//三维点定义
struct cvPoint
{
 
float x,y,z; //点的坐标
}
;
//矢量相乘C=A*B (方向符合右手定则)
void vect_mult(struct cvPoint *A, struct cvPoint *B, struct cvPoint *C)
{
 C
->x=A->* B->-->* B->y;
 C
->y=A->* B->-->* B->z;
 C
->z=A->* B->-->* B->x;
}

 

四边形的法向选取
    四边形的法向选取采用四边形两条对角线向量相乘。问什么不采用四边形的边相乘,因为四边形四顶点点

并不一定共平面,采用四边形两条对角线向量相乘,显然要更精确一些。

波浪方程(其实就是正弦或余弦函数绕z轴旋转的)

double t=0.0;//相位
double sf(double x,double y)
{
 
return cos(sqrt(x*x+y*y)+t);
}

 

2.创建纹理(NeHe)
不清楚的可参考NeHe的教程,清楚地可跳过本节。

 

GLuint texture[3];
AUX_RGBImageRec 
*LoadBMP(char *Filename)     // 载入位图图象
{
 FILE 
*File=NULL;       // 文件句柄
 if(!Filename)        // 确保文件名已

提供
 
{
  
return NULL;       // 如果没提供,

返回 NULL
 }

 File
=fopen(Filename,"r");      // 尝试打开文件
 if(File)        // 文件存在么?
 {
  fclose(File);       
// 关闭句柄
  return auxDIBImageLoad(Filename);    // 载入位图并返

回指针
 }

 
return NULL;        // 如果载入失败

,返回 NULL
}

int LoadGLTextures()        // 载入位图(调用

上面的代码)并转换成纹理
{
 
int Status=FALSE;       // 状态指示器
 AUX_RGBImageRec *TextureImage[1];     // 创建纹理的存

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

NULL
 
// 载入位图,检查有无错误,如果位图没找到则退出
 if(TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
 
{
  Status
=TRUE;       // 将 Status 设

为 TRUE
  glGenTextures(
3&texture[0]);     // 创建纹理
  
  
// 创建 Nearest 滤波贴图
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
  glTexImage2D(GL_TEXTURE_2D, 
03, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  
// 创建线性滤波纹理
  glBindTexture(GL_TEXTURE_2D, texture[1]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 
03, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  
// 创建 MipMapped 纹理
  glBindTexture(GL_TEXTURE_2D, texture[2]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); 
  gluBuild2DMipmaps(GL_TEXTURE_2D, 
3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); 
 }

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

存在
  
{
   free(TextureImage[
0]->data);    // 释放纹理图像

占用的内存
  }
  
  free(TextureImage[
0]);      // 释放图像结构
 }

 
return Status;        // 返回 Status
}



3.曲面纹理贴图的关键
    曲面纹理贴图的关键就是把曲面分成小块(本文采用四边形),纹理贴图也要相对应的分成小块,然后相

对应的把纹理贴到相对应的曲面小块。注意一定要相对应,连顶点都要相对应。
    先将曲面分割,并存储其分割的顶点。

 

float ver[21][21][3];
GLvoid initVer()
{
 
int i,j;
 
float dx=D_PI*8/20.0,dy=D_PI*8/20.0;
 
for(i=0;i<=20;i++)
  
for(j=0;j<=20;j++)
  
{
   ver[i][j][
0]=i*dx-D_PI*4;
   ver[i][j][
1]=j*dy-D_PI*4;
   ver[i][j][
2]=(float)sf(ver[i][j][0],ver[i][j][1]);
  }

}

开始贴图
cvPoint pa,pb,pc;
for(int i=0;i<20;i++)
    
for(int j=0;j<20;j++)
    
{
        
//第一条对角线
        pa.x=ver[i+1][j+1][0]-ver[i][j][0];
        pa.y
=ver[i+1][j+1][1]-ver[i][j][1];
        pa.z
=ver[i+1][j+1][2]-ver[i][j][2];
        
//第二条对角线
        pb.x=ver[i][j+1][0]-ver[i+1][j][0];
        pb.y
=ver[i][j+1][1]-ver[i+1][j][1];
        pb.z
=ver[i][j+1][2]-ver[i+1][j][2];

        vect_mult(
&pa,&pb,&pc);//计算法向,注意顺序
        glNormal3f(pc.x,pc.y,pc.z);
        
//注意要一一对应
        glBegin(GL_QUADS);
        glTexCoord2f(
0.05*i,0.05*j);
        glVertex3f(ver[i][j][
0],ver[i][j][1],ver[i][j][2]);
        glTexCoord2f(
0.05*(i+1),0.05*j);
        glVertex3f(ver[i
+1][j][0],ver[i+1][j][1],ver[i+1][j][2]);
        glTexCoord2f(
0.05*(i+1),0.05*(j+1));
        glVertex3f(ver[i
+1][j+1][0],ver[i+1][j+1][1],ver[i+1][j+1][2]);
        glTexCoord2f(
0.05*i,0.05*(j+1));
        glVertex3f(ver[i][j
+1][0],ver[i][j+1][1],ver[i][j+1][2]);
        glEnd();
    }



动起来
这个So Simple!改变相位即可。

t+=0.05;

 

搞定,曲面纹理贴图技术就这么简单。

完整的代码(运行前,先在创建Data文件夹,并放一张256×256的位图以供加载纹理)

#include <windows.h>  // Windows的头文件
#include <GL/gl.h>  // 包含最新的gl.h,glu.h库
#include <GL/glu.h>  // 包含OpenGL实用库
#include <GL/glaux.h>
#include 
<stdio.h>  // 标准输入/输出库的头文件
#include <math.h>
#define D_PI 3.141592653
#pragma warning(disable:4305)
#pragma warning(disable:4244)

struct cvPoint
{
 
float x,y,z; //点的坐标
}
;
//矢量相乘C=A*B 
void vect_mult(struct cvPoint *A, struct cvPoint *B, struct cvPoint *C)
{
 C
->x=A->* B->-->* B->y;
 C
->y=A->* B->-->* B->z;
 C
->z=A->* B->-->* B->x;
}


double t=0.0;
double sf(double x,double y)
{
 
return cos(sqrt(x*x+y*y)+t);
}

float ver[21][21][3];
GLvoid initVer()
{
 
int i,j;
 
float dx=D_PI*8/20.0,dy=D_PI*8/20.0;
 
for(i=0;i<=20;i++)
  
for(j=0;j<=20;j++)
  
{
   ver[i][j][
0]=i*dx-D_PI*4;
   ver[i][j][
1]=j*dy-D_PI*4;
   ver[i][j][
2]=(float)sf(ver[i][j][0],ver[i][j][1]);
  }

}



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

bool keys[256];   // 保存键盘按键的数组
bool active=TRUE;  // 窗口的活动标志,缺省为TRUE
bool fullscreen=TRUE; // 全屏标志缺省,缺省设定成全屏模式
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); // WndProc的定义

int rx=0,ry=0,rz=0;

BOOL light;         
// 光源的开/关
bool lp;
GLfloat LightAmbient[]
={0.5f,0.5f,0.5f,1.0f}
GLfloat LightDiffuse[]
={1.0f,1.0f,1.0f,1.0f};
GLfloat LightPosition[]
={0.0f,0.0f,2.0f,1.0f};
GLuint texture[
3];

AUX_RGBImageRec 
*LoadBMP(char *Filename)     // 载入位图图象
{
 FILE 
*File=NULL;       // 文件句柄
 if(!Filename)        // 确保文件名已

提供
 
{
  
return NULL;       // 如果没提供,

返回 NULL
 }

 File
=fopen(Filename,"r");      // 尝试打开文件
 if(File)        // 文件存在么?
 {
  fclose(File);       
// 关闭句柄
  return auxDIBImageLoad(Filename);    // 载入位图并返

回指针
 }

 
return NULL;        // 如果载入失败

,返回 NULL
}

int LoadGLTextures()        // 载入位图(调用

上面的代码)并转换成纹理
{
 
int Status=FALSE;       // 状态指示器
 AUX_RGBImageRec *TextureImage[1];     // 创建纹理的存

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

NULL
 
// 载入位图,检查有无错误,如果位图没找到则退出
 if(TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
 
{
  Status
=TRUE;       // 将 Status 设

为 TRUE
  glGenTextures(
3&texture[0]);     // 创建纹理
  
  
// 创建 Nearest 滤波贴图
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
  glTexImage2D(GL_TEXTURE_2D, 
03, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  
// 创建线性滤波纹理
  glBindTexture(GL_TEXTURE_2D, texture[1]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 
03, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  
// 创建 MipMapped 纹理
  glBindTexture(GL_TEXTURE_2D, texture[2]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); 
  gluBuild2DMipmaps(GL_TEXTURE_2D, 
3, TextureImage[0]->sizeX, TextureImage[0]-

>sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); 
 }

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

存在
  
{
   free(TextureImage[
0]->data);    // 释放纹理图像

占用的内存
  }
  
  free(TextureImage[
0]);      // 释放图像结构
 }

 
return Status;        // 返回 Status
}



GLvoid ReSizeGLScene(GLsizei width, GLsizei height)  
// 重置OpenGL窗口大小
{
 
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进行所有设置
{
 initVer();
 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); 
 glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
 glEnable(GL_LIGHT1);

 
if(!LoadGLTextures())
 
{
  
return false;
 }

    glEnable(GL_TEXTURE_2D);

 glShadeModel(GL_SMOOTH);       
// 启用

阴影平滑
 glClearColor(
0.0f0.0f0.0f0.5f);    // 黑色背景
 glClearDepth(1.0f);         

// 设置深度缓存
 glEnable(GL_DEPTH_TEST);       // 启用

深度测试
 glDepthFunc(GL_LEQUAL);        
// 所作

深度测试的类型
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 
// 告诉系统对透视进行修正
 return TRUE;          

// 初始化 OK
}


int DrawGLScene(GLvoid)         // 从这

里开始进行所有的绘制
{
 glClear(GL_COLOR_BUFFER_BIT 
| GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
 glLoadIdentity();

 glTranslatef(
0,0,-6.0);

 glRotatef(
float(rx),1.0,0.0,0.0);
 glRotatef(
float(ry),0.0,1.0,0.0);
 glRotatef(
float(rz),0.0,0.0,1.0);
 
 glBindTexture(GL_TEXTURE_2D, texture[
0]);

    initVer();
//重新赋值
 cvPoint pa,pb,pc;
 glPushMatrix();
 glScalef(
0.1,0.1,0.1);
 glTranslatef(
-D_PI/2,-D_PI/2,0);
 glRotatef(
-60,1,0,0);
 glRotatef(
-30,0,0,1);
 
for(int i=0;i<20;i++)
  
for(int j=0;j<20;j++)
  
{
   
//第一条对角线
   pa.x=ver[i+1][j+1][0]-ver[i][j][0];
   pa.y
=ver[i+1][j+1][1]-ver[i][j][1];
   pa.z
=ver[i+1][j+1][2]-ver[i][j][2];
            
//第二条对角线
   pb.x=ver[i][j+1][0]-ver[i+1][j][0];
   pb.y
=ver[i][j+1][1]-ver[i+1][j][1];
   pb.z
=ver[i][j+1][2]-ver[i+1][j][2];

   vect_mult(
&pa,&pb,&pc);//计算法向,注意顺序
   glNormal3f(pc.x,pc.y,pc.z);
   glBegin(GL_QUADS);
   glTexCoord2f(
0.05*i,0.05*j);
   glVertex3f(ver[i][j][
0],ver[i][j][1],ver[i][j][2]);
   glTexCoord2f(
0.05*(i+1),0.05*j);
   glVertex3f(ver[i
+1][j][0],ver[i+1][j][1],ver[i+1][j][2]);
   glTexCoord2f(
0.05*(i+1),0.05*(j+1));
   glVertex3f(ver[i
+1][j+1][0],ver[i+1][j+1][1],ver[i+1][j+1][2]);
   glTexCoord2f(
0.05*i,0.05*(j+1));
   glVertex3f(ver[i][j
+1][0],ver[i][j+1][1],ver[i][j+1][2]);
   glEnd();
  }

 glPopMatrix();

 glEnable(GL_LIGHTING);
 t
+=0.05;//改变相位
 Sleep(20);
 
return TRUE;          

// 一切 OK
}


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;          

// 将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
 }

}


/* 这个函数创建我们OpenGL窗口,参数为:        

 *
 * title   - 窗口标题        

    *
 * width   - 窗口宽度        

    *
 * height   - 窗口高度        

    *
 * bits   - 颜色的位深(8/16/32)       

  *
 * fullscreenflag - 是否使用全屏模式,全屏模式(TRUE),窗口模式(FALSE)  
*/

 
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;    // 将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);
  
return FALSE;          

 
// 退出并返回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,"全屏模式在当前显卡上设置失败!使用窗口模

式?
","NeHe G",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
   {
    
//如果用户选择窗口模式,变量fullscreen 的值变为FALSE,程序继续运


    fullscreen
=FALSE;  // 选择窗口模式

(Fullscreen
=FALSE)
   }

   
else
   
{
    
//如果用户选择退出,弹出消息窗口告知用户程序将结束。并返回FALSE

告诉程序窗口未能成功创建。程序退出。
    MessageBox(NULL,
"程序将被关闭","错误",MB_OK|MB_ICONSTOP);
    
return FALSE;        

 
// 退出并返回 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);  // 调整窗口达到

真正要求的大小

 
// 创建窗口
 if (!(hWnd=CreateWindowEx( dwExStyle,       

// 扩展窗体风格
        "OpenG",    

   
// 类名字
        title,     

   
// 窗口标题
        dwStyle |    

   
// 必须的窗体风格属性
        WS_CLIPSIBLINGS |   

  
// 必须的窗体风格属性
        WS_CLIPCHILDREN,   

  
// 必须的窗体风格属性
        00,     

   
// 窗口位置
        WindowRect.right-

WindowRect.left, 
// 计算调整好的窗口宽度
        WindowRect.bottom-

WindowRect.top, 
// 计算调整好的窗口高度
        NULL,     

   
// 无父窗口
        NULL,     

   
// 无菜单
        hInstance,    

   
// 实例
        NULL)))     

   
// 不向WM_CREATE传递任何东东
 {
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"窗口创建错误","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

FALSE
 }


 
static PIXELFORMATDESCRIPTOR pfd=    //pfd 告诉窗口我们所希望

的东东,即窗口使用的像素格式
 
{
  
sizeof(PIXELFORMATDESCRIPTOR),    // 上述格式描述符的大小
  1,           

// 版本号
  PFD_DRAW_TO_WINDOW |      // 格式支持窗口
  PFD_SUPPORT_OPENGL |      // 格式必须支持

OpenGL
  PFD_DOUBLEBUFFER,       
// 必须

支持双缓冲
  PFD_TYPE_RGBA,        
// 申请 

RGBA 格式
  bits,          

// 选定色彩深度
  000000,       // 忽略

的色彩位
  
0,           

// 无Alpha缓存
  0,           

// 忽略Shift Bit
  0,           

// 无累加缓存
  0000,         

// 忽略聚集位
  16,           

// 16位 Z-缓存 (深度缓存) 
  0,           

// 无蒙板缓存
  0,           

// 无辅助缓存
  PFD_MAIN_PLANE,        // 主绘

图层
  
0,           

// 不使用重叠层
  000          

// 忽略层遮罩
 }
;
 
 
if (!(hDC=GetDC(hWnd)))       // 取得设备描述

表了么
?
 
{
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"不能创建一个窗口设备描述表","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

FALSE
 }


 
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Windows 找到相应的象素格式了吗?
 {
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"不能创建一种相匹配的像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

FALSE
 }


 
if(!SetPixelFormat(hDC,PixelFormat,&pfd))  // 能够设置象素格式么?
 {
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"不能设置像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

FALSE
 }


 
if (!(hRC=wglCreateContext(hDC)))    // 能否取得OpenGL渲染描

述表
?
 
{
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"不能创建OpenGL渲染描述表","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

FALSE
 }


 
if(!wglMakeCurrent(hDC,hRC))     // 尝试激活着色描述表
 {
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"不能激活当前的OpenGL渲然描述表","

",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // 返回 

FALSE
 }


 ShowWindow(hWnd,SW_SHOW);      
// 显示窗口
 SetForegroundWindow(hWnd);      // 略略提高优先


 SetFocus(hWnd);         
// 设置

键盘的焦点至此窗口
 ReSizeGLScene(width, height);     
// 设置透视 GL 屏幕

 
if (!InitGL())         // 初始

化新建的GL窗口
 
{
  KillGLWindow();        
// 重置

显示区
  MessageBox(NULL,
"初始化失败","错误",MB_OK|MB_ICONEXCLAMATION);
  
return FALSE;        // 返回 

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;     // 如果是,设为

TRUE
   
return 0;        

// 返回
  }


  
case WM_KEYUP:        // 有键

放开么
?
  
{
   keys[wParam] 
= FALSE;     // 如果是,设为

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


int WINAPI WinMain(HINSTANCE hInstance,   // 当前窗口实例
     HINSTANCE hPrevInstance,  // 前一个窗口实


     LPSTR  lpCmdLine,   
// 命令

行参数
     
int   nCmdShow)   

// 窗口显示状态
{
 MSG  msg;         

// Windowsx消息结构
 BOOL done=FALSE;        // 用来

退出循环的Bool 变量

 
// 提示用户选择运行模式
 if (MessageBox(NULL,"你想在全屏模式下运行么?""设置全屏模

",MB_YESNO|MB_ICONQUESTION)==IDNO)
 {
  fullscreen
=FALSE;       // FALSE

为窗口模式
 }


 
// 创建OpenGL窗口
 if (!CreateGLWindow("NeHe's OpenGL 程序框架",640,480,16,fullscreen))
 
{
  
return 0;         

// 失败退出
 }


 
while(!done)         // 保持

循环直到 done
=TRUE
 
{
  
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // 有消息在等待吗?
  {
   
if (msg.message==WM_QUIT)    // 收到退出消息?
   {
    done
=TRUE;       

// 是,则done=TRUE
   }

   
else         

// 不是,处理窗口消息
   {
    TranslateMessage(
&msg);    // 翻译消息
    DispatchMessage(&msg);    // 发送消息
   }

  }

  
else          

// 如果没有消息
  {
   
// 绘制场景。监视ESC键和来自DrawGLScene()的退出消息
   if (active)        

// 程序激活的么?
   {
    
if (keys[VK_ESCAPE])    // ESC 按下了么?
    {
     done
=TRUE;      

// ESC 发出退出信号
    }

    
else        

// 不是退出的时候,刷新屏幕
    {
     DrawGLScene();     
// 绘制

场景
     SwapBuffers(hDC);    
// 交换

缓存 (双缓存)
     
if (keys['L'&& !lp)    // L 键

已按下并且松开了
?
     
{
      lp
=TRUE;    // lp 设

为 TRUE
      light
=!light;    // 切换

光源的 TRUE
/FALSE
      
if (!light)    // 如果

没有光源
      
{
       glDisable(GL_LIGHTING);  
// 禁用

光源
      }

      
else     // 否则
      {
       glEnable(GL_LIGHTING);  
// 启用

光源
      }

     }

     
if (!keys['L'])     // L键松

开了么
?
     
{
      lp
=FALSE;    // 若是

,则将lp设为FALSE
     }

    }

   }


   
if (keys[VK_F1])      // F1键

按下了么
?
   
{
    keys[VK_F1]
=FALSE;     // 若是

,使对应的Key数组中的值为 FALSE
    KillGLWindow();      
// 销毁

当前的窗口
    fullscreen
=!fullscreen;    // 切换 全屏 / 

窗口 模式
    
// 重建 OpenGL 窗口
    if (!CreateGLWindow("NeHe's OpenGL 程序框

",640,480,16,fullscreen))
    {
     
return 0;      

// 如果窗口未能创建,程序退出
    }

   }

  }

 }


 
// 关闭程序
 KillGLWindow();         // 销毁

窗口
 
return (msg.wParam);       // 退出程序
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:222941次
    • 积分:2905
    • 等级:
    • 排名:第12178名
    • 原创:59篇
    • 转载:5篇
    • 译文:0篇
    • 评论:47条
    最新评论