欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

opengles之mipmap纹理

程序员文章站 2022-07-02 14:30:07
...

为什么要用mipmap?

     在三维世界中,显示一张图片的大小与摄像机的位置有关,近的地方,图片实际像素大一些,远 的地方,图片实际像素就小一些,比如一张64*64的图片

在近处, 显示出来可能是50*50,远处可能显示出来就是20*20。

    mipmap纹理技术是目前解决纹理分辨率与视点距离关系的最有效途径,它会先将图片压缩成很多逐渐缩小的图片,例如一张64*64的图片,会产生64*64,32*32,16*16,8*8,4*4,2*2,1*1的7张图片,当屏幕上需要绘制像素点为20*20时,程序只是利用32*32和16*16 这两张图片来计算出即将显示为20*20大小的一个图片,这比单独利用32*32的哪张原始图片计算出来的图片效果好很多,速度也快。


效果图:(GL_LINEAR_MIPMAP_LINEAR过滤模式)

opengles之mipmap纹理

Mipmap过滤

Mipmap的纹理过滤模式如下表:

常量 描述
GL_NEAREST 在mip基层上使用最邻近过滤
GL_LINEAR 在mip基层上使用线性过滤
GL_NEAREST_MIPMAP_NEAREST 选择最邻近的mip层,并使用最邻近过滤
GL_NEAREST_MIPMAP_LINEAR 在mip层之间使用线性插值和最邻近过滤
GL_LINEAR_MIPMAP_NEAREST 选择最邻近的mip层,使用线性过滤
GL_LINEAR_MIPMAP_LINEAR 在mip层之间使用线性插值和使用线性过滤,又称三线性mipmap

GL_NEAREST_MIPMAP_NEAREST 过滤模式:

opengles之mipmap纹理

shader实现类:

#pragma once

#include <assert.h>

class    ShaderId
{
public:
	ShaderId()
	{
		_shaderId = -1;
	}
	int _shaderId;
};


/**
*   程序
*/
class   ProgramId
{
public:
	int         _programId;
	ShaderId    _vertex;
	ShaderId    _fragment;
public:
	ProgramId()
	{
		_programId = -1;
	}
public:
	/**
	*   加载函数
	*/
	bool    createProgram(const char* vertex, const char* fragment)
	{
		bool        error = false;
		do
		{
			if (vertex)
			{
				_vertex._shaderId = glCreateShader(GL_VERTEX_SHADER);
				glShaderSource(_vertex._shaderId, 1, &vertex, 0);
				glCompileShader(_vertex._shaderId);

				GLint   compileStatus;
				glGetShaderiv(_vertex._shaderId, GL_COMPILE_STATUS, &compileStatus);
				error = compileStatus == GL_FALSE;
				if (error)
				{
					GLchar messages[256];
					glGetShaderInfoLog(_vertex._shaderId, sizeof(messages), 0, messages);
					assert(messages && 0 != 0);
					break;
				}
			}
			if (fragment)
			{
				_fragment._shaderId = glCreateShader(GL_FRAGMENT_SHADER);
				glShaderSource(_fragment._shaderId, 1, &fragment, 0);
				glCompileShader(_fragment._shaderId);

				GLint   compileStatus;
				glGetShaderiv(_fragment._shaderId, GL_COMPILE_STATUS, &compileStatus);
				error = compileStatus == GL_FALSE;

				if (error)
				{
					GLchar messages[256];
					glGetShaderInfoLog(_fragment._shaderId, sizeof(messages), 0, messages);
					assert(messages && 0 != 0);
					break;
				}
			}
			_programId = glCreateProgram();

			if (_vertex._shaderId)
			{
				glAttachShader(_programId, _vertex._shaderId);
			}
			if (_fragment._shaderId)
			{
				glAttachShader(_programId, _fragment._shaderId);
			}

			glLinkProgram(_programId);

			GLint linkStatus;
			glGetProgramiv(_programId, GL_LINK_STATUS, &linkStatus);
			if (linkStatus == GL_FALSE)
			{
				GLchar messages[256];
				glGetProgramInfoLog(_programId, sizeof(messages), 0, messages);
				break;
			}
			glUseProgram(_programId);

		} while (false);

		if (error)
		{
			if (_fragment._shaderId)
			{
				glDeleteShader(_fragment._shaderId);
				_fragment._shaderId = 0;
			}
			if (_vertex._shaderId)
			{
				glDeleteShader(_vertex._shaderId);
				_vertex._shaderId = 0;
			}
			if (_programId)
			{
				glDeleteProgram(_programId);
				_programId = 0;
			}
		}
		return  true;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glUseProgram(0);
	}
};



class   PROGRAM_P2_C4 :public ProgramId
{
public:
	typedef int attribute;
	typedef int uniform;
public:
	attribute   _position;
	uniform     _color;
	uniform     _MVP;
public:
	PROGRAM_P2_C4()
	{
		_position = -1;
		_color = -1;
		_MVP = -1;
	}
	~PROGRAM_P2_C4()
	{
	}

	/// 初始化函数
	virtual bool    initialize()
	{
		const char* vs =
		{
			"precision lowp float; "
			"uniform   mat4 _MVP;"
			"attribute vec2 _position;"

			"void main()"
			"{"
			"   vec4    pos =   vec4(_position,0,1);"
			"   gl_Position =   _MVP * pos;"
			"}"
		};
		const char* ps =
		{
			"precision  lowp float; "
			"uniform    vec4 _color;"
			"void main()"
			"{"
			"   gl_FragColor   =   _color;"
			"}"
		};

		bool    res = createProgram(vs, ps);
		if (res)
		{
			_position = glGetAttribLocation(_programId, "_position");
			_color = glGetUniformLocation(_programId, "_color");
			_MVP = glGetUniformLocation(_programId, "_MVP");
		}
		return  res;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);
		glEnableVertexAttribArray(_position);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glDisableVertexAttribArray(_position);
		glUseProgram(0);
	}
};
class   PROGRAM_P2_AC4 :public ProgramId
{
public:
	typedef int attribute;
	typedef int uniform;
public:
	attribute   _position;
	attribute   _color;
	uniform     _MVP;
public:
	PROGRAM_P2_AC4()
	{
		_position = -1;
		_color = -1;
		_MVP = -1;
	}
	~PROGRAM_P2_AC4()
	{
	}

	/// 初始化函数
	virtual bool    initialize()
	{
		const char* vs =
		{
			"precision lowp float; "
			"uniform   mat4 _MVP;"
			"attribute vec2 _position;"
			"attribute vec4 _color;"
			"varying   vec4 _outColor;"

			"void main()"
			"{"
			"   vec4    pos =   vec4(_position,0,1);"
			"   _outColor   =   _color;"
			"   gl_Position =   _MVP * pos;"
			"}"
		};
		const char* ps =
		{
			"precision  lowp float; "
			"varying   vec4 _outColor;"
			"void main()"
			"{"
			"   gl_FragColor   =   _outColor;"
			"}"
		};

		bool    res = createProgram(vs, ps);
		if (res)
		{
			_position = glGetAttribLocation(_programId, "_position");
			_color = glGetAttribLocation(_programId, "_color");
			_MVP = glGetUniformLocation(_programId, "_MVP");
		}
		return  res;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);
		glEnableVertexAttribArray(_position);
		glEnableVertexAttribArray(_color);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glDisableVertexAttribArray(_position);
		glDisableVertexAttribArray(_color);
		glUseProgram(0);
	}
};



class   PROGRAM_P2_UV_AC4 :public ProgramId
{
public:
	typedef int attribute;
	typedef int uniform;
public:
	attribute   _position;
	attribute   _color;
	attribute   _uv;
	uniform     _MVP;
	uniform     _texture;
	//!  第二阶段文理
	uniform     _texture1;
	uniform     _uvAnim;
public:
	PROGRAM_P2_UV_AC4()
	{
		_position = -1;
		_color = -1;
		_uv = -1;
		_texture = -1;
		_texture1 = -1;
		_uvAnim = -1;
		_MVP = -1;
	}
	~PROGRAM_P2_UV_AC4()
	{
	}

	/// 初始化函数
	virtual bool    initialize()
	{
		const char* vs =
		{
			"precision lowp float; "
			"uniform   mat4 _MVP;"
			"attribute vec2 _position;"
			"attribute vec2 _uv;"
			"attribute vec4 _color;"
			"varying   vec4 _outColor;"
			"varying   vec2 _outUV;"

			"void main()"
			"{"
			"   vec4    pos =   vec4(_position,0,1);"
			"   _outColor   =   _color;"
			"   _outUV      =   _uv;"
			"   gl_Position =   _MVP * pos;"
			"}"
		};
		const char* ps =
		{
			"precision  lowp float; "
			"uniform   sampler2D _texture;\n"
			"uniform   sampler2D _texture1;\n"
			"uniform   float    _uvAnim;\n"
			"varying   vec4      _outColor;\n"
			"varying   vec2      _outUV;\n"
			"void main()"
			"{"
			"   vec4    tColor0  =   texture2D(_texture,_outUV);\n"
			"   vec2    newUV = vec2(_uvAnim + _outUV.x,_outUV.y);"
			"   vec4    tColor1  =   texture2D(_texture1,newUV);\n"
			"   gl_FragColor    =   tColor0  * tColor1;\n"
			"}"
		};

		bool    res = createProgram(vs, ps);
		if (res)
		{
			_position = glGetAttribLocation(_programId, "_position");
			_color = glGetAttribLocation(_programId, "_color");
			_uv = glGetAttribLocation(_programId, "_uv");
			_texture = glGetUniformLocation(_programId, "_texture");
			_texture1 = glGetUniformLocation(_programId, "_texture1");
			_MVP = glGetUniformLocation(_programId, "_MVP");
			_uvAnim = glGetUniformLocation(_programId, "_uvAnim");


		}
		return  res;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);
		glEnableVertexAttribArray(_position);
		glEnableVertexAttribArray(_uv);
		glEnableVertexAttribArray(_color);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glDisableVertexAttribArray(_position);
		glDisableVertexAttribArray(_uv);
		glDisableVertexAttribArray(_color);
		glUseProgram(0);
	}
};




class   PROGRAM_P3_UV :public ProgramId
{
public:
	typedef int attribute;
	typedef int uniform;
public:
	attribute   _position;
	attribute   _uv;
	uniform     _MVP;
	uniform     _texture;
public:
	PROGRAM_P3_UV()
	{
		_position = -1;
		_uv = -1;
		_texture = -1;
		_MVP = -1;
	}
	~PROGRAM_P3_UV()
	{
	}

	/// 初始化函数
	virtual bool    initialize()
	{
		const char* vs =
		{
			"precision lowp float; "
			"uniform   mat4 _MVP;"
			"attribute vec2 _position;"
			"attribute vec2 _uv;"
			"varying   vec2 _outUV;"

			"void main()"
			"{"
			"   vec4    pos =   vec4(_position,0,1);"
			"   _outUV      =   _uv;"
			"   gl_Position =   _MVP * pos;"
			"}"
		};
		const char* ps =
		{
			"precision  lowp float; "
			"uniform   sampler2D _texture;\n"
			"varying   vec2      _outUV;\n"
			"void main()"
			"{"
			"   vec4    tColor0  =   texture2D(_texture,_outUV);\n"
			"   gl_FragColor    =   tColor0;\n"
			"}"
		};

		bool    res = createProgram(vs, ps);
		if (res)
		{
			_position = glGetAttribLocation(_programId, "_position");
			_uv = glGetAttribLocation(_programId, "_uv");
			_texture = glGetUniformLocation(_programId, "_texture");
			_MVP = glGetUniformLocation(_programId, "_MVP");

		}
		return  res;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);
		glEnableVertexAttribArray(_position);
		glEnableVertexAttribArray(_uv);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glDisableVertexAttribArray(_position);
		glDisableVertexAttribArray(_uv);
		glUseProgram(0);
	}
};




class   PROGRAM_P2_T2_C3 :public ProgramId
{
public:
	typedef int location;
public:
	location    _positionAttr;
	location    _colorAttr;
	location    _uvAttr;
	location    _MVP;
	location    _texture;
public:
	PROGRAM_P2_T2_C3()
	{
		_positionAttr = -1;
		_colorAttr = -1;
		_uvAttr = -1;
		_MVP = -1;
	}
	~PROGRAM_P2_T2_C3()
	{
	}

	/// 初始化函数
	virtual bool initialize()
	{
		const char* vs =
		{
			"uniform mat4 _MVP;"
			"attribute vec3 _position;"
			"attribute vec4 _color;"
			"attribute vec2 _uv;"

			"varying vec4 _outColor;"
			"varying vec2 _outUV;"
			"void main()"
			"{"
			" vec4 pos=vec4(_position.x,_position.y,_position.z,1);"
			"gl_Position=_MVP*pos;"
			"_outColor=_color;"
			"_outUV=_uv;"
			"}"
		};

		const char* ps =
		{
			"precision lowp float;"
			"uniform sampler2D _texture;"
			"varying vec4 _outColor;"
			"varying vec2 _outUV;"
			"void main()"
			"{"
			"vec4 color=texture2D(_texture,_outUV);"
			"gl_FragColor=color*_outColor;"//向量相乘变暗,相加变亮
			"}"
		};
		bool res = createProgram(vs,ps);
		if (res)
		{
			_positionAttr = glGetAttribLocation(_programId, "_position");
			_colorAttr = glGetAttribLocation(_programId, "_color");
			_uvAttr = glGetAttribLocation(_programId, "_uv");
			_MVP = glGetUniformLocation(_programId, "_MVP");
			_texture = glGetUniformLocation(_programId, "_texture");
		}
		return  res;
	}

	/**
	*   使用程序
	*/
	virtual void    begin()
	{
		glUseProgram(_programId);
		glEnableVertexAttribArray(_positionAttr);
		glEnableVertexAttribArray(_uvAttr);
		glEnableVertexAttribArray(_colorAttr);

	}
	/**
	*   使用完成
	*/
	virtual void    end()
	{
		glDisableVertexAttribArray(_positionAttr);
		glDisableVertexAttribArray(_uvAttr);
		glDisableVertexAttribArray(_colorAttr);
		glUseProgram(0);
	}
};

窗口绘制类

#pragma once

#include <Windows.h>
#include <tchar.h>
#include <math.h>

#include <EGL/egl.h>
#include <gles2/gl2.h>

#include "freeImage/FreeImage.h"

#include "CELLMath.hpp"
#include "CELLShader.hpp"

namespace   CELL
{

	class   FirstCameraInfor
	{
	public:
		FirstCameraInfor()
		{
			_moveSpeed = 5;
			_eye = CELL::float3(0.0f, 10.0f, 0.0f);
			_look = CELL::float3(0.5f, -0.4f, -0.5f);
			_up = CELL::float3(0, 1, 0);
			_right = CELL::float3(1, 0, 0);
		}
		CELL::float3    _eye;
		CELL::float3    _look;
		CELL::float3    _up;
		CELL::float3    _right;
		float           _moveSpeed;
	public:

		void    updateCamera(float fElapsed)
		{

			CELL::float3    tmpLook = _look;
			CELL::float3    dir = _look - _eye;
			dir = normalize(dir);
			//! 这里调用windows函数获取键盘的状态
			unsigned char keys[256];
			GetKeyboardState(keys);

			if (keys[VK_UP] & 0x80)
			{
				_eye -= dir*-_moveSpeed * fElapsed;
				_look -= dir*-_moveSpeed * fElapsed;
			}

			if (keys[VK_DOWN] & 0x80)
			{
				_eye += (dir*-_moveSpeed) * fElapsed;
				_look += (dir*-_moveSpeed) * fElapsed;
			}

			if (keys[VK_LEFT] & 0x80)
			{
				_eye -= (_right*_moveSpeed) * fElapsed;
				_look -= (_right*_moveSpeed) * fElapsed;
			}

			if (keys[VK_RIGHT] & 0x80)
			{
				_eye += (_right*_moveSpeed) * fElapsed;
				_look += (_right*_moveSpeed) * fElapsed;
			}
		}
	};


	class   CELLWinApp
	{
	public:
		//! 实例句柄
		HINSTANCE   _hInstance;
		//! 窗口句柄
		HWND        _hWnd;
		//! 窗口的高度
		int         _width;
		//! 窗口的宽度
		int         _height;
		/// for gles2.0
		EGLConfig   _config;
		EGLSurface  _surface;
		EGLContext  _context;
		EGLDisplay  _display;
		//! 增加shader
		PROGRAM_P2_T2_C3    _shader;
		unsigned            _textureId;
		FirstCameraInfor    _camera;
	public:
		CELLWinApp(HINSTANCE hInstance)
			:_hInstance(hInstance)
		{
			WNDCLASSEX  winClass;
			winClass.lpszClassName = _T("CELLWinApp");
			winClass.cbSize = sizeof(winClass);
			winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
			winClass.lpfnWndProc = wndProc;
			winClass.hInstance = hInstance;
			winClass.hIcon = 0;
			winClass.hIconSm = 0;
			winClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
			winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
			winClass.lpszMenuName = NULL;
			winClass.cbClsExtra = 0;
			winClass.cbWndExtra = 0;
			RegisterClassEx(&winClass);

			_textureId = 0;
		}
		virtual ~CELLWinApp()
		{
			UnregisterClass(_T("CELLWinApp"), _hInstance);
		}

		/**
		*   初始化 OpenGLES2.0
		*/
		bool    initOpenGLES20()
		{
			const EGLint attribs[] =
			{
				EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
				EGL_BLUE_SIZE, 8,
				EGL_GREEN_SIZE, 8,
				EGL_RED_SIZE, 8,
				EGL_DEPTH_SIZE, 24,
				EGL_NONE
			};
			EGLint 	format(0);
			EGLint	numConfigs(0);
			EGLint  major;
			EGLint  minor;

			//! 1
			_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

			//! 2init
			eglInitialize(_display, &major, &minor);

			//! 3
			eglChooseConfig(_display, attribs, &_config, 1, &numConfigs);

			eglGetConfigAttrib(_display, _config, EGL_NATIVE_VISUAL_ID, &format);
			//! 4 
			_surface = eglCreateWindowSurface(_display, _config, _hWnd, NULL);

			//! 5
			EGLint attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
			_context = eglCreateContext(_display, _config, 0, attr);
			//! 6
			if (eglMakeCurrent(_display, _surface, _surface, _context) == EGL_FALSE)
			{
				return false;
			}

			eglQuerySurface(_display, _surface, EGL_WIDTH, &_width);
			eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height);

			return  true;

		}
		/**
		*   销毁OpenGLES2.0
		*/
		void    destroyOpenGLES20()
		{
			glDeleteTextures(1, &_textureId);

			if (_display != EGL_NO_DISPLAY)
			{
				eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
				if (_context != EGL_NO_CONTEXT)
				{
					eglDestroyContext(_display, _context);
				}
				if (_surface != EGL_NO_SURFACE)
				{
					eglDestroySurface(_display, _surface);
				}
				eglTerminate(_display);
			}
			_display = EGL_NO_DISPLAY;
			_context = EGL_NO_CONTEXT;
			_surface = EGL_NO_SURFACE;
		}

		virtual unsigned loadMimMap(char* fileNames[], int size)
		{
			unsigned textureId = 0;
			//生成纹理 函数原型:glGenTextures(GLsizei n, GLuint *textures)
			//n:用来生成纹理的数量 textures:存储纹理索引的第一个元素指针
			glGenTextures(1, &textureId);
			//绑定纹理
			glBindTexture(GL_TEXTURE_2D,textureId);
			//指定纹理的放大,缩小滤波方式,即当图片放大时的插值方式
		    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

			for (int j = 0; j < size;++j)
			{
				//1-获取图片格式
				FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(fileNames[j],0);
				//2-加载图片
				FIBITMAP *dib = FreeImage_Load(fifmt,fileNames[j],0);
				//3-转换为rgb 24色
				dib = FreeImage_ConvertTo24Bits(dib);

				//4-获取数据指针
				BYTE *pixels = (BYTE*)FreeImage_GetBits(dib);

				int width = FreeImage_GetWidth(dib);
				int height = FreeImage_GetHeight(dib);

				//像素反转 opengles需要的像素格式RGB,windows图像格式BGR
				for (int i = 0; i < width*height*3; i+=3)
				{
					BYTE temp = pixels[i];
					pixels[i] = pixels[i + 2];
					pixels[i + 2] = temp;
				}

				//将图片的rgb数据上传给opengl
				glTexImage2D(
					GL_TEXTURE_2D,//指定是二维图片
					j,//指定级别,纹理可以做mipmap,距离近的就采用级别大的,远则使用较小纹理 j越大则纹理越小
					GL_RGB,//纹理使用的存储格式
					width,//宽度,老一点的显卡,不支持不规则纹理,即宽,高要是2^n
					height,
					0,//是否带边框
					GL_RGB,//数据的格式,在bmp中,windows存储的数据格式是bgr
					GL_UNSIGNED_BYTE,//数据是8bit数据
					pixels
					);

				FreeImage_Unload(dib);

			}

			return textureId;
		}
		
		virtual unsigned    loadTexture(const char* fileName)
		{
			unsigned    textureId = 0;
			//1 获取图片格式
			FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(fileName, 0);

			//2 加载图片
			FIBITMAP    *dib = FreeImage_Load(fifmt, fileName, 0);

			//3 转化为rgb 24色
			dib = FreeImage_ConvertTo24Bits(dib);



			//4 获取数据指针
			BYTE    *pixels = (BYTE*)FreeImage_GetBits(dib);

			int     width = FreeImage_GetWidth(dib);
			int     height = FreeImage_GetHeight(dib);

			for (int i = 0; i < width * height * 3; i += 3)
			{
				BYTE temp = pixels[i];
				pixels[i] = pixels[i + 2];
				pixels[i + 2] = temp;
			}
			/**
			*   产生一个纹理Id,可以认为是纹理句柄,后面的操作将书用这个纹理id
			*/
			glGenTextures(1, &textureId);

			/**
			*   使用这个纹理id,或者叫绑定(关联)
			*/
			glBindTexture(GL_TEXTURE_2D, textureId);
			/**
			*   指定纹理的放大,缩小滤波,使用线性方式,即当图片放大的时候插值方式
			*/
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);


			/**
			*   将图片的rgb数据上传给opengl.
			*/
			glTexImage2D(
				GL_TEXTURE_2D,      //! 指定是二维图片
				0,                  //! 指定为第一级别,纹理可以做mipmap,即lod,离近的就采用级别大的,远则使用较小的纹理
				GL_RGB,             //! 纹理的使用的存储格式
				width,              //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。
				height,             //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。
				0,                  //! 是否的边
				GL_RGB,             //! 数据的格式,bmp中,windows,操作系统中存储的数据是bgr格式
				GL_UNSIGNED_BYTE,   //! 数据是8bit数据
				pixels
				);
			/**
			*   释放内存
			*/
			FreeImage_Unload(dib);

			return  textureId;
		}



	protected:
		static  LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
		{

			CELLWinApp*  pThis = (CELLWinApp*)GetWindowLong(hWnd, GWL_USERDATA);
			if (pThis)
			{
				return  pThis->onEvent(hWnd, msg, wParam, lParam);
			}
			if (WM_CREATE == msg)
			{
				CREATESTRUCT*   pCreate = (CREATESTRUCT*)lParam;
				SetWindowLong(hWnd, GWL_USERDATA, (DWORD_PTR)pCreate->lpCreateParams);
			}
			return  DefWindowProc(hWnd, msg, wParam, lParam);
		}
	public:
		/**
		*   事件函数
		*/
		virtual LRESULT onEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
		{
			switch (msg)
			{
			case WM_CLOSE:
			case WM_DESTROY:
			{
				::PostQuitMessage(0);
			}
				break;
			case WM_MOUSEMOVE:
				break;
			default:
				return  DefWindowProc(hWnd, msg, wParam, lParam);
			}
			return  S_OK;

		}

		virtual void    render()
		{
			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
			glViewport(0, 0, _width, _width);

			struct Vertex
			{
				float x, y, z;
				float u, v;
				float r, g, b, a;
			};


			_camera.updateCamera(0.016f);

			//摄像机观察矩阵
			CELL::matrix4   matView = CELL::lookAt(_camera._eye, _camera._look, _camera._up);


			float   gSize = 100;
			float   gPos = -5;
			float   rept = 100;

			Vertex grounds[] =
			{
				{ -gSize, gPos, -gSize, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f },
				{ gSize, gPos, -gSize, rept, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f },
				{ gSize, gPos, gSize, rept, rept, 1.0f, 1.0f, 1.0f, 1.0f },

				{ -gSize, gPos, -gSize, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f },
				{ gSize, gPos, gSize, rept, rept, 1.0f, 1.0f, 1.0f, 1.0f },
				{ -gSize, gPos, gSize, 0.0f, rept, 1.0f, 1.0f, 1.0f, 1.0f },
			};


			_shader.begin();
			{
				//物体变换矩阵
				CELL::matrix4   matWorld(1);
				//投影矩阵
				CELL::matrix4   matProj = CELL::perspective(45.0f, (GLfloat)_width / (GLfloat)_height, 0.1f, 100.0f);

				//总的变换矩阵
				CELL::matrix4   MVP = matProj * matView * matWorld;

				glUniform1i(_shader._texture, 0);
				//! 绘制地面
				glBindTexture(GL_TEXTURE_2D, _textureId);
				//更新shader中各个变量的值
				glUniformMatrix4fv(_shader._MVP, 1, false, MVP.data());

				glVertexAttribPointer(_shader._positionAttr, 3, GL_FLOAT, false, sizeof(Vertex), &grounds[0].x);
				glVertexAttribPointer(_shader._uvAttr, 2, GL_FLOAT, false, sizeof(Vertex), &grounds[0].u);
				glVertexAttribPointer(_shader._colorAttr, 4, GL_FLOAT, false, sizeof(Vertex), &grounds[0].r);

				glDrawArrays(GL_TRIANGLES, 0, sizeof(grounds) / sizeof(grounds[0]));

			}
			_shader.end();


		}
		/**
		*   主函数
		*/
		int     main(int width, int height)
		{
			_hWnd = CreateWindowEx(NULL,
				_T("CELLWinApp"),
				_T("CELLWinApp"),
				WS_OVERLAPPEDWINDOW,
				CW_USEDEFAULT,
				CW_USEDEFAULT,
				width,
				height,
				NULL,
				NULL,
				_hInstance,
				this
				);

			if (_hWnd == 0)
			{
				return  -1;
			}
			UpdateWindow(_hWnd);

			ShowWindow(_hWnd, SW_SHOW);

			if (!initOpenGLES20())
			{
				return  false;
			}
			_shader.initialize();

			char*   files[] =
			{
				"Debug/data/image/tex33X32.bmp",
				"Debug/data/image/tex16X16.bmp",
				"Debug/data/image/tex8x8.bmp",
				"Debug/data/image/tex4x4.bmp",
				"Debug/data/image/tex2X2.bmp",
				"Debug/data/image/tex1x1.bmp",
			};

			_textureId = loadMimMap(files, sizeof(files) / sizeof(files[0]));
			_camera._eye = CELL::float3(1, 1, 1);
			_camera._look = CELL::float3(0.5f, -0.4f, -5.5f);
			_camera._up = CELL::float3(0.0f, 1.0f, 0.0f);
			_camera._right = CELL::float3(1.0f, 0.0f, 0.0f);


			MSG msg = { 0 };
			while (msg.message != WM_QUIT)
			{
				if (msg.message == WM_DESTROY ||
					msg.message == WM_CLOSE)
				{
					break;
				}
				/**
				*   有消息,处理消息,无消息,则进行渲染绘制
				*/
				if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				else
				{
					render();
					eglSwapBuffers(_display, _surface);
				}
			}
			/**
			*   销毁OpenGLES20
			*/
			destroyOpenGLES20();

			return  0;
		}
	};
}

程序入口

#include "CELLWinApp.hpp"



int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(hInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	UNREFERENCED_PARAMETER(nCmdShow);


	CELL::CELLWinApp  app(hInstance);
	app.main(800, 600);

	return 0;
}

完整代码下载地址:http://download.csdn.net/detail/hb707934728/9837338