不再多说,首先按《基于MFC的OpenGL编程》Part 2 Setting up OpenGL on Windows中的介绍,把所有该做的东西都先做好。
1.增加变量
float points[45][45][3]; // The Array For The Points On The Grid Of Our "Wave"
int wiggle_count; // Counter Used To Control How Fast Flag Waves
GLfloat xrot; // X Rotation ( NEW )
GLfloat yrot; // Y Rotation ( NEW )
GLfloat zrot; // Z Rotation ( NEW )
GLfloat hold; // Temporarily Holds A Floating Point Value
GLuint texture[1]; // Storage For One Texture ( NEW )
int wiggle_count; // Counter Used To Control How Fast Flag Waves
GLfloat xrot; // X Rotation ( NEW )
GLfloat yrot; // Y Rotation ( NEW )
GLfloat zrot; // Z Rotation ( NEW )
GLfloat hold; // Temporarily Holds A Floating Point Value
GLuint texture[1]; // Storage For One Texture ( NEW )
本例虽然只有一幅图片来作为纹理,但是为了让他看起来能动。不是把它整个的贴在一个矩形里面,而是放到44X44个矩阵里面,所以设置了points这个数组来存储各个顶点的x,y,z值。其它的变量就不解释了。
2.这是用来读入BMP图像的函数,关键代码其实就auxDIBImageLoad(Filename),其它的都是用来防止出错的,程序的健壮性相当的好啊。
AUX_RGBImageRec* CdemoView::LoadBMP(char* Filename)
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL
}
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL
}
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
3.载入纹理:GenT -> BindT ->TImg -> TParameter。这个过程如果熟悉的话,是个很简单的过程,主要参数的意义需要理清楚。NEHE的程序总是很完美,该释放的变量和空间绝不保留。
int CdemoView::LoadGLTextures(void)
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void*)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Data/Tim.bmp"))
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(1, &texture[0]); // Create The Texture
// Typical Texture Generation Using Data From The Bitmap
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX,
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void*)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Data/Tim.bmp"))
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(1, &texture[0]); // Create The Texture
// Typical Texture Generation Using Data From The Bitmap
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 Texture Exists
{
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status
}
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
if (TextureImage[0]) // If Texture Exists
{
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status
}
4.InitializeOpenGL函数需要做一些改动,我把整个函数都贴上来了。主要就是加了对二维纹理映射和数组(即各个矩形顶点)的初始化。
BOOL CdemoView::InitializeOpenGL(void)
{
//Get a DC for the Client Area
m_pDC =new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC ==0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
if (!LoadGLTextures()) // Jump To Texture Loading Routine ( NEW )
{
return FALSE; // If Texture Didn't Load Return FALSE
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping ( NEW )
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glPolygonMode( GL_BACK, GL_FILL ); // Back Face Is Solid
glPolygonMode( GL_FRONT, GL_LINE ); // Front Face Is Made Of Lines
for(int x=0; x<45; x++)
{
for(int y=0; y<45; y++)
{
points[x][y][0]=float((x/5.0f)-4.5f);
points[x][y][1]=float((y/5.0f)-4.5f);
points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f));
}
}
return TRUE;
}
{
//Get a DC for the Client Area
m_pDC =new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC ==0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
if (!LoadGLTextures()) // Jump To Texture Loading Routine ( NEW )
{
return FALSE; // If Texture Didn't Load Return FALSE
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping ( NEW )
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glPolygonMode( GL_BACK, GL_FILL ); // Back Face Is Solid
glPolygonMode( GL_FRONT, GL_LINE ); // Front Face Is Made Of Lines
for(int x=0; x<45; x++)
{
for(int y=0; y<45; y++)
{
points[x][y][0]=float((x/5.0f)-4.5f);
points[x][y][1]=float((y/5.0f)-4.5f);
points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f));
}
}
return TRUE;
}
5.渲染函数了,RenderScene,这个程序的精华也就在这里了。
void CdemoView::RenderScene(void)
{
int x, y;
float float_x, float_y, float_xb, float_yb;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-12.0f);
{
int x, y;
float float_x, float_y, float_xb, float_yb;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-12.0f);
分别以x,y,z轴为中心就行旋转,这样图像作为一个整体会有动态的效果。
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
下面这段要仔细看看,如何把纹理贴到这个44X44的网格上面去。
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
for( x =0; x <44; x++ )
{
for( y =0; y <44; y++ )
{
float_x =float(x)/44.0f;
float_y =float(y)/44.0f;
float_xb =float(x+1)/44.0f;
float_yb =float(y+1)/44.0f;
glTexCoord2f( float_x, float_y);
glVertex3f( points[x][y][0], points[x][y][1], points[x][y][2] );
glTexCoord2f( float_x, float_yb );
glVertex3f( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );
glTexCoord2f( float_xb, float_yb );
glVertex3f( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );
glTexCoord2f( float_xb, float_y );
glVertex3f( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
}
}
glEnd();
glBegin(GL_QUADS);
for( x =0; x <44; x++ )
{
for( y =0; y <44; y++ )
{
float_x =float(x)/44.0f;
float_y =float(y)/44.0f;
float_xb =float(x+1)/44.0f;
float_yb =float(y+1)/44.0f;
glTexCoord2f( float_x, float_y);
glVertex3f( points[x][y][0], points[x][y][1], points[x][y][2] );
glTexCoord2f( float_x, float_yb );
glVertex3f( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );
glTexCoord2f( float_xb, float_yb );
glVertex3f( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );
glTexCoord2f( float_xb, float_y );
glVertex3f( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
}
}
glEnd();
撇开图像整体沿x,y,z轴的旋转,飘动的效果是由下面的代码完成的。
if( wiggle_count ==2 )
{
for( y =0; y <45; y++ )
{
hold=points[0][y][2];
for( x =0; x <44; x++)
{
points[x][y][2] = points[x+1][y][2];
}
points[44][y][2]=hold;
}
wiggle_count =0;
}
{
for( y =0; y <45; y++ )
{
hold=points[0][y][2];
for( x =0; x <44; x++)
{
points[x][y][2] = points[x+1][y][2];
}
points[44][y][2]=hold;
}
wiggle_count =0;
}
}
6.记得在ONCREATE函数下面加上SetTimer这个函数。
void CdemoView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
wiggle_count++;
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
InvalidateRect(NULL,FALSE);
CView::OnTimer(nIDEvent);
}
{
// TODO: Add your message handler code here and/or call default
wiggle_count++;
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
InvalidateRect(NULL,FALSE);
CView::OnTimer(nIDEvent);
}
7.好了,运行程序。效果如下:
纹理贴在正面,背面是由线组成的,所以能看到正面的内容。