opengl曲面贴图

opengl 曲面贴图

opengl 2011-02-12 15:31:16 阅读5 评论1   字号: 订阅

OpenGL曲面纹理贴图技术--波浪的模拟

    学过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->y * B->z -A ->z * B->y;

 C->y=A->z * B->x -A ->x * B->z;

 C->z=A->x * B->y -A ->y * 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, 0, 3, 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, 0, 3, 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的位图以供加载纹理)

 

 

// glqm.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include <windows.h>  // Windows的头文件

#include <stdio.h>  // 标准输入/输出库的头文件

#include <math.h>

#include <GL/glew.h>
#pragma comment (lib, "glew32.lib")


#include <GL/glut.h>
#pragma comment (lib, "winmm.lib")   /* link with Windows MultiMedia lib */
#pragma comment (lib, "opengl32.lib")  /* link with Microsoft OpenGL lib */
#pragma comment (lib, "glu32.lib")  /* link with OpenGL Utility lib */
#pragma comment (lib, "glut32.lib")  /* link with Win32 GLUT lib */


#include <GL/glaux.h>
#pragma comment (lib, "glaux.lib")


#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->y * B->z -A ->z * B->y;
 
 C->y=A->z * B->x -A ->x * B->z;
 
 C->z=A->x * B->y -A ->y * 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];


struct _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, 0, 3, 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, 0, 3, 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.0f, 0.0f, 0.0f, 0.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(5000);
  
  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;  // 选择窗口模式
             
             }
            
             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,  
           
           
            // 必须的窗体风格属性
           
            0, 0,    
           
           
            // 窗口位置
           
            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, // 选定色彩深度
            
             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,           // 不使用重叠层
            
             0, 0, 0          // 忽略层遮罩
            
           };
          
          
          
           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)); 
   
   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);       // 退出程序
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值