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; public: PROGRAM_P2_UV_AC4() { _position = -1; _color = -1; _uv = -1; _texture = -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" "varying vec4 _outColor;\n" "varying vec2 _outUV;\n" "void main()" "{" " vec4 tColor = texture2D(_texture,_outUV);\n" " gl_FragColor = tColor * _outColor;\n" "}" }; bool res = createProgram(vs, ps); if (res) { _position = glGetAttribLocation(_programId, "_position"); _color = glGetAttribLocation(_programId, "_color"); _uv = glGetAttribLocation(_programId, "_uv"); _texture = glGetUniformLocation(_programId, "_texture"); _MVP = glGetUniformLocation(_programId, "_MVP"); } return res; } /** * 使用程序 */ virtual void begin() { glUseProgram(_programId); glEnableVertexAttribArray(_position); glEnableVertexAttribArray(_uv); glEnableVertexAttribArray(_color); } /** * 使用完成 */ virtual void end() { glDisableVertexAttribArray(_position); glDisableVertexAttribArray(_uv); glDisableVertexAttribArray(_color); 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 CELLWinApp { public: //! 实例句柄 HINSTANCE _hInstance; //! 窗口句柄 HWND _hWnd; //! 窗口的高度 int _width; //! 窗口的宽度 int _height; /// for gles2.0 EGLConfig _config; EGLSurface _surface; EGLContext _context; EGLDisplay _display; //! 增加shader PROGRAM_P2_UV_AC4 _shader; unsigned _textureId; 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() { 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 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 (size_t 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_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* *当纹理坐标超出[0,0]到[1,1]的范围时纹理坐标的处理由wrap参数指定, *1--GL_REPEAT:坐标的整数部分被忽略,重复纹理,这是OpenGL纹理默认的处理方式. *2--GL_MIRRORED_REPEAT: 纹理也会被重复,但是当纹理坐标的整数部分是奇数时会使用镜像重复。 *3--GL_CLAMP_TO_EDGE: 坐标会被截断到[0,1]之间。结果是坐标值大的被截断到纹理的边缘部分,形成了一个拉伸的边缘(stretched edge pattern)。 */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); /** * 将图片的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 ); char subData[100 * 100 * 3]; memset(subData, 255, sizeof(subData)); /** 功能:提供修改图像的功能,因为修改一个纹理比重新创建一个纹理开销小很多,对于一些视频捕捉程序可以先将视频图像存储在更大的初始图像中 (图像大小要是2^n,opengl2.0后没有这个限制),创建一个渲染用的纹理,然后反复调用glTexSubImage2D(修改的图像区域不用是2^n)函数从视频图像区域读取到渲染 纹理图像中,渲染用的纹理图像只需要创建一次即可。 函数原型 glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) target:必须是glCopyTexImage2D中对应的target可用值 level:mipmap等级 xoffset,yoffset是要修改的图像左上角偏移,width,height是要修改的图像宽高像素修改的范围在原图之外并不受影响 format,type:表示图像的数据格式和类型 pixels:子图像的纹理数据 */ glTexSubImage2D(GL_TEXTURE_2D, 0, 100, 100, 100, 100, GL_RGB, GL_UNSIGNED_BYTE, subData); /** * 释放内存 */ 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() { struct Vertex { CELL::float2 pos; CELL::float2 uv; CELL::Rgba4Byte color; }; //! 清空缓冲区 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); //! 视口,在Windows窗口指定的位置和大小上绘制OpenGL内容 glViewport(0, 0, _width, _height); //! 创建一个投影矩阵 glBindTexture(GL_TEXTURE_2D, _textureId); CELL::matrix4 screenProj = CELL::ortho<float>(0, float(_width), float(_height), 0, -100.0f, 100); _shader.begin(); { float x = 100; float y = 100; float w = 400; float h = 400; float rt = 2; Vertex vertex[] = { CELL::float2(x, y), CELL::float2(0, 0), CELL::Rgba4Byte(255, 255, 255, 255), CELL::float2(x + w, y), CELL::float2(rt, 0), CELL::Rgba4Byte(255, 255, 255, 255), CELL::float2(x, y + h), CELL::float2(0, rt), CELL::Rgba4Byte(255, 255, 255, 255), CELL::float2(x + w, y + h), CELL::float2(rt, rt), CELL::Rgba4Byte(255, 255, 255, 255), }; CELL::matrix4 matMVP = screenProj; glUniformMatrix4fv(_shader._MVP, 1, false, matMVP.data()); glUniform1i(_shader._texture, 0); glVertexAttribPointer(_shader._position, 2, GL_FLOAT, false, sizeof(Vertex), vertex); glVertexAttribPointer(_shader._uv, 2, GL_FLOAT, false, sizeof(Vertex), &vertex[0].uv); glVertexAttribPointer(_shader._color, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &vertex[0].color); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } _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(); _textureId = loadTexture("Debug/data/image/5.jpg"); 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/9837754