电子商务网站建设期末试题及答案网络股权设计培训课程
电子商务网站建设期末试题及答案,网络股权设计培训课程,如何做seo,连云港建设工程质量监督站网站1 前言1.1 开发该框架的动机 OpenGL ES 是一个渲染指令接口集合#xff0c;每渲染一帧图像都是一系列渲染指令的排列组合。常用的渲染指令约有 70 个#xff0c;记住这些渲染指令及其排列组合方式#xff0c;是一件痛苦的事情。另外#xff0c;在图形开发中#xff0c;经…1 前言1.1 开发该框架的动机 OpenGL ES 是一个渲染指令接口集合每渲染一帧图像都是一系列渲染指令的排列组合。常用的渲染指令约有 70 个记住这些渲染指令及其排列组合方式是一件痛苦的事情。另外在图形开发中经常因为功耗、丢帧等问题需要性能优化如何从框架层面进行性能优化是一件有挑战的问题。 基于上述原因笔者手撕了一个 nimi 版的渲染框架将这些常用的渲染指令有条理地封装、组织、归类方便愉快并高效地进行 OpenGL ES 渲染开发。笔者在 OpenGL ES 领域从业也有些时日对现有碎片化的知识进行归纳凝练形成系统的认知是件势在必行的事。1.2 一个 mini 版的渲染框架应该具备哪些能力 一个 mini 版的渲染框架需要对 OpenGL ES 的常用指令进行归类如下图封装 EGL、error check、Shader Program、Mesh、VAO、VBO、IBO、Texture、FBO 等类方便开发者快速开发渲染程序将更多的注意力聚焦在业务上而不是如何去组织 OpenGL ES 指令上。img1.3 为什么强调 mini 版渲染框架 从渲染指令的角度来看OpenGL ES 3.0 约有 300 个渲染指令本文框架只封装其中最常用的 70 个指令覆盖程度仍有较大提升空间。 从功能的角度来看笔者深知一个成熟完备的渲染框架应该具备相机、光源、光照模型Lambert、Phong、PBR 等、阴影、射线拾取、重力、碰撞检测、粒子系统等功能。 鉴于上述原因笔者审慎地保留了 mini 前缀。1.4 本框架的优势 本框架具有以下优势。封装友好对常用的 EGL 和 GL 指令约 70 个进行封装提供了 EGL 环境搭建、着色器程序生成、网格构建、纹理贴图、离屏渲染、异常检测等基础能力方便开发者快速开发渲染程序将精力从繁杂的渲染指令中解放出来将更多的注意力聚焦到业务上。代码规整框架中多处设计了 bind 和 unbind 接口用于绑定和解绑 OpenGL ES 状态机相关 “插槽”如VBO、IBO、VAO 中都设计了 bind 和 unbind 接口ShaderProgram、Texture、FBO、TextureAction 中都设计了 bind 接口另外在 FBO 中设计了 begin 和 end 接口很直观地告诉用户夹在这中间的内容将渲染到 FBO。接口规整简洁方便用户记忆。易于扩展定义了 TextureAction 接口并提供 bind 函数GLTexture、FBO 都继承了 TextureAction用户自定义的渲染器或特效类也可以继承 TextureAction将它们统一视为纹理活动可绑定这在特效叠加或后处理中非常有用方便管理多渲染目标图层易于扩展。性能高效封装了 VBO、IBO、VAO用于缓存顶点数据、索引、格式等信息到显存减少 CPU 到 GPU 的数据传输提高渲染效率缓存了 attribute 和 uniform 变量的 location避免 CPU 频繁向 GPU 查询 location进一步提高渲染效率基于 C 语言实现渲染框架代码执行效率较高。跨平台基于 C 语言实现具有更好的跨平台特性封装了 core_lib使得平台相关头文件可以轻松替换封装了 Application使得平台相关 api 可以轻松替换。方便调试设计了 EGL_CALL 和 GL_CALL 两个宏对每个 EGL 和 GL 指令进行异常检测方便调试渲染指令并且通过预编译宏 DEBUG 开关动态控制是否生成异常检测的代码Release 版本会自动屏蔽异常检测代码避免带来额外功耗。2 渲染框架 经过深思熟虑笔者给该渲染框架命名为 glcore命名空间也是 glcore。Windows 上 OpenGL 环境搭建主要有 GLFW / freeglut Glad / GLEW 方案详见 → Windows上OpenGL环境搭建本文采用目前广泛使用的 GLFW Glad 方案。Android 版本的 glcore 实现详见 → 在Android上手撕一个mini版的渲染框架。 本文完整资源包含 glcore 框架和第 4 节的应用详见 →【OpenGL ES】一个mini版的Windows渲染框架。2.1 框架结构img2.2 CMakeLists CMakeLists.txt# 设置库名set(LIB_GL_CORE_NAME glcore)# 递归添加源文件列表file(GLOB_RECURSE GL_CORE_SOURCES ./src/ *.cpp)# 添加预构建库add_library(${LIB_GL_CORE_NAME} ${GL_CORE_SOURCES})# 将当前目录设为公共头文件目录 (任何链接glcore库的目标都能自动获得这个头文件路径)target_include_directories(${LIB_GL_CORE_NAME} PUBLIC ./)2.3 核心头文件 核心头文件分为对内和对外的即内部依赖 core_lib外部开放 core。 core_lib.h#pragma once/*** glcore 依赖的核心 GL 库, 便于将 glcore 移植到其他平台* Android: EGL GLESv3* Windows: glfw / freeglut glad / glew** author little fat sheep*/#include glad/glad.h#include GLFW/glfw3.h 之所以要单独拎出 core_lib.h是为了方便将该框架迁移到其他平台如 Android 上依赖的三方渲染库是 EGL GLESv3如果不抽出 core_lib.h就需要将很多地方的 glfw3.h glad.h 改为 egl.h gl3.h 工作量大也容易漏改。另外还可以很方便地替换渲染环境如将 glfw3.h glad.h 替换为 freeglut.h glew.h。 core.h#pragma once/*** glcore核心头文件* 该头文件是留给外部使用的, glcore内部不能使用, 避免自己包含自己* author little fat sheep*/// OpenGL ES API#include core_lib.h// glcore 核心头文件#include application.h#include elg_surface_view.h#include format.h#include frame_buffer_object.h#include gl_inspector.h#include gl_texture.h#include mesh.h#include mesh_utils.h#include shader_program.h#include texture_action.h#include vertex_attribute.h core.h 只提供给外部使用方便外部只需要包含一个头文件就能获取 glcore 的基础能力。2.4 Application Application 主要用于管理全局环境使用单例模式方便获取一些全局的变量。它也是 glcore 中唯一一个依赖平台相关的接口除日志 log 接口外如m_window 是 Windows 特有的如果将 glcore 迁移到 Android 中就需要将该变量替换为 ANativeWindow* 类型将这些平台相关变量都集中在 Application 中迁移平台时修改起来也比较容易避免太分散容易漏掉。另外还可以很方便地替换渲染环境如渲染平台替换为 freeglut 时需要将 GLFWwindow 替换为 void*因为 freeglut 未提供类似 window 的数据结构。 application.h#pragma once#include core_lib.h#define app Application::getInstance()namespace glcore{/*** 应用程序, 存储全局的参数, 便于访问* author little fat sheep*/class Application {private:static Application* sInstance;public:int width 0;int height 0;float aspect 1.0f;private:GLFWwindow* m_window nullptr;public:static Application* getInstance();~Application();void resize(int width, int height);GLFWwindow* getWindow() { return m_window; }void setWindow(GLFWwindow* window);void releaseWindow();private:Application() {};};} // namespace glcore application.cpp#include glcore/application.hnamespace glcore{Application* Application::sInstance nullptr;Application *Application::getInstance(){if (sInstance nullptr){sInstance new Application();}return sInstance;}Application::~Application(){}void Application::resize(int width, int height){this-width width;this-height height;this-aspect (float) width / (float) height;}void Application::setWindow(GLFWwindow* window){m_window window;int width, height;glfwGetFramebufferSize(window, width, height);resize(width, height);}void Application::releaseWindow(){if (m_window){m_window nullptr;}}} // namespace glcore2.5 GLInspector GLInspector 主要用于异常信息检测另外设计了 EGL_CALL 和 GL_CALL 两个宏分别对 EGL 和 GL 指令进行装饰。如果定义了 DEBUG 宏就会对每个 EGL 和 GL 指令进行异常检测方便调试代码如果未定义了 DEBUG 宏就不会进行异常检测。 用户可以在 CMakeLists.txt 中添加预编译宏 DEBUG这样就可以根据 Release 和 Debug 版本自动构建不同的版本。if (CMAKE_BUILD_TYPE STREQUAL Debug)# 添加预编译宏add_definitions(-DDEBUG)endif () gl_inspector.h#pragma once#include core_lib.h#ifdef DEBUG#define EGL_CALL(func) func;GLInspector::checkEGLError();#define GL_CALL(func) func;GLInspector::checkGLError();#else#define EGL_CALL(func) func;#define GL_CALL(func) func;#endifnamespace glcore{/*** OpenGL ES命令报错监视器* author little fat sheep*/class GLInspector{public:static void checkEGLError(const char* tag); // 检查EGL配置static void checkEGLError(); // 通用检查EGL错误static void printShaderInfoLog(GLuint shader, const char* tag); // 打印Shader错误日志static void printProgramInfoLog(GLuint program, const char* tag); // 打印Program错误日志static void checkGLError(const char* tag); // 检查GL报错信息static void checkGLError(); // 通用检查GL错误};} // namespace glcore gl_inspector.cpp#include iostream#include assert.h#include string#include glcore/core_lib.h#include glcore/gl_inspector.h// 以下内容为了不报错临时添加的 (glfw/freeglut已经创建了egl环境)#define EGL_SUCCESS 0x3000#define EGL_NOT_INITIALIZED 0x3001#define EGL_BAD_ACCESS 0x3002#define EGL_BAD_ALLOC 0x3003#define EGL_BAD_ATTRIBUTE 0x3004#define EGL_BAD_CONFIG 0x3005#define EGL_BAD_CONTEXT 0x3006#define EGL_BAD_SURFACE 0x3007#define EGL_BAD_DISPLAY 0x3008#define EGL_BAD_CURRENT_SURFACE 0x3009#define EGL_BAD_NATIVE_PIXMAP 0x300A#define EGL_BAD_NATIVE_WINDOW 0x300D#define EGL_BAD_PARAMETER 0x300C#define EGL_BAD_MATCH 0x3010#define EGL_CONTEXT_LOST 0x300E// 以上内容为了不报错临时添加的#define TAG GLInspectorint eglGetError() { return 0; }using namespace std;namespace glcore{void GLInspector::checkEGLError(const char *tag){int error eglGetError();if (error ! EGL_SUCCESS) {printf(%s: %s failed: 0x%x\n, TAG, tag, error);}}void GLInspector::checkEGLError(){GLenum errorCode eglGetError();if (errorCode ! EGL_SUCCESS) {string error;switch (errorCode){case EGL_BAD_DISPLAY:error EGL_BAD_DISPLAY;break;case EGL_NOT_INITIALIZED:error EGL_NOT_INITIALIZED;break;case EGL_BAD_CONFIG:error EGL_BAD_CONFIG;break;case EGL_BAD_CONTEXT:error EGL_BAD_CONTEXT;break;case EGL_BAD_NATIVE_WINDOW:error EGL_BAD_NATIVE_WINDOW;break;case EGL_BAD_SURFACE:error EGL_BAD_SURFACE;break;case EGL_BAD_CURRENT_SURFACE:error EGL_BAD_CURRENT_SURFACE;break;case EGL_BAD_ACCESS:error EGL_BAD_ACCESS;break;case EGL_BAD_ALLOC:error EGL_BAD_ALLOC;break;case EGL_BAD_ATTRIBUTE:error EGL_BAD_ATTRIBUTE;break;case EGL_BAD_PARAMETER:error EGL_BAD_PARAMETER;break;case EGL_BAD_NATIVE_PIXMAP:error EGL_BAD_NATIVE_PIXMAP;break;case EGL_BAD_MATCH:error EGL_BAD_MATCH;break;case EGL_CONTEXT_LOST:error EGL_CONTEXT_LOST;break;default:error UNKNOW;break;}printf(checkEGLError failed: %s, 0x%x, error.c_str(), errorCode);assert(false);}}void GLInspector::printShaderInfoLog(GLuint shader, const char* tag){char infoLog[512];glGetShaderInfoLog(shader, 512, nullptr, infoLog);printf(%s: %s failed: %s\n, TAG, tag, infoLog);}void GLInspector::printProgramInfoLog(GLuint program, const char* tag){char infoLog[512];glGetProgramInfoLog(program, 512, nullptr, infoLog);printf(%s: %s failed: %s\n, TAG, tag, infoLog);}void GLInspector::checkGLError(const char *tag) {GLenum error glGetError();if(error ! GL_NO_ERROR) {printf(%s: %s failed: 0x%x\n, TAG, tag, error);}}void GLInspector::checkGLError(){GLenum errorCode glGetError();if (errorCode ! GL_NO_ERROR){string error;switch (errorCode){case GL_INVALID_ENUM:error GL_INVALID_ENUM;break;case GL_INVALID_VALUE:error GL_INVALID_VALUE;break;case GL_INVALID_OPERATION:error GL_INVALID_OPERATION;break;case GL_INVALID_INDEX:error GL_INVALID_INDEX;break;case GL_INVALID_FRAMEBUFFER_OPERATION:error GL_INVALID_FRAMEBUFFER_OPERATION;break;case GL_OUT_OF_MEMORY:error GL_OUT_OF_MEMORY;break;default:error UNKNOW;break;}printf(checkError failed: %s, 0x%x\n, error.c_str(), errorCode);assert(false);}}} // namespace glcore2.6 EGLSurfaceView EGLSurfaceView 主要承载了 EGL 环境搭建。EGL 详细介绍见 → 【OpenGL ES】EGLFBO离屏渲染。 由于 GLFW 中已经创建了 EGL 环境EGLSurfaceView 实际上是多余的为了保持 glcore 在各个平台上的代码具有高度一致性并且方便随时自主创建 EGL 环境这里仍然保留了 EGLSurfaceView。本文中主要使用到 EGLSurfaceView 的内部类 Renderer起到定制渲染流程规范的作用。 elg_surface_view.h#pragma once#include core_lib.h// 以下内容为了不报错临时添加的 (glfw/freeglut创建了egl环境)typedef void* EGLDisplay;typedef void* EGLConfig;typedef void* EGLContext;typedef void* EGLSurface;// 以上内容为了不报错临时添加的namespace glcore{/*** EGL环境封装类* glfw和freeglut中创建了egl环境, 因此该类可以去掉,* 但是为了方便将glcore迁移到需要用户搭建egl环境的平台中,* 暂时保留该类.** author little fat sheep*/class EGLSurfaceView{public:class Renderer;private:Renderer* m_renderer nullptr;EGLDisplay m_eglDisplay;EGLConfig m_eglConfig;EGLContext m_eglContext;EGLSurface m_eglSurface;bool m_firstCreateSurface true;public:EGLSurfaceView();~EGLSurfaceView();void setRenderer(Renderer* renderer);bool surfaceCreated();void surfaceChanged(int width, int height);void drawFrame();void surfaceDestroy();private:void createDisplay();void createConfig();void createContext();void createSurface();void makeCurrent();public:/*** 渲染器接口, 类比GLSurfaceView.Renderer* author little fat sheep*/class Renderer {public:virtual ~Renderer() {};virtual void onSurfaceCreated() 0;virtual void onSurfaceChanged(int width, int height) 0;virtual void onDrawFrame() 0;};};} // namespace glcore elg_surface_view.cpp#include iostream#include glcore/application.h#include glcore/elg_surface_view.h#include glcore/gl_inspector.h#define TAG EGLSurfaceView// 以下内容为了不报错临时添加的 (glfw/freeglut已经创建了egl环境)#define EGL_RED_SIZE 0x3024#define EGL_GREEN_SIZE 0x3023#define EGL_BLUE_SIZE 0x3022#define EGL_ALPHA_SIZE 0x3021#define EGL_DEPTH_SIZE 0x3025#define EGL_RENDERABLE_TYPE 0x3040#define EGL_OPENGL_ES3_BIT 0x0040#define EGL_SURFACE_TYPE 0x3033#define EGL_WINDOW_BIT 0x0004#define EGL_NONE 0x3038#define EGL_CONTEXT_CLIENT_VERSION 0x3098#define EGL_DEFAULT_DISPLAY ((EGLDisplay)0)#define EGL_NO_DISPLAY ((EGLDisplay)0)#define EGL_NO_CONTEXT ((EGLContext)0)#define EGL_NO_SURFACE ((EGLSurface)0)typedef int32_t EGLint;EGLDisplay eglGetDisplay(EGLDisplay a1) { return nullptr; }void eglInitialize(EGLDisplay a1, int* a3, int* a4) {}void eglChooseConfig(EGLDisplay a1, const EGLint* a2, EGLConfig* a3, EGLint a4, EGLint* a5) {}EGLContext eglCreateContext(EGLDisplay a1, EGLConfig a2, EGLContext a3, const EGLint* a4) { return nullptr; }EGLSurface eglCreateWindowSurface(EGLDisplay a1, EGLConfig a2, void* a3, const EGLint* a4) { return nullptr; }void eglMakeCurrent(EGLDisplay a1, EGLSurface a2, EGLSurface a3, EGLContext a4) {}void eglSwapBuffers(EGLDisplay a1, EGLSurface a2) {}void eglDestroySurface(EGLDisplay a1, EGLSurface a2) {}void eglDestroyContext(EGLDisplay a1, EGLContext a2) {}void eglTerminate(EGLDisplay a1) {}// 以上内容为了不报错临时添加的namespace glcore{EGLSurfaceView::EGLSurfaceView(){printf(%s: init\n, TAG);createDisplay();createConfig();createContext();}EGLSurfaceView::~EGLSurfaceView(){printf(%s: destroy\n, TAG);if (m_renderer){delete m_renderer;m_renderer nullptr;}if (m_eglDisplay m_eglDisplay ! EGL_NO_DISPLAY){// 与显示设备解绑EGL_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));// 销毁 EGLSurfaceif (m_eglSurface m_eglSurface ! EGL_NO_SURFACE){EGL_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));delete m_eglSurface;}// 销毁 EGLContextif (m_eglContext m_eglContext ! EGL_NO_CONTEXT){EGL_CALL(eglDestroyContext(m_eglDisplay, m_eglContext));delete m_eglContext;}// 销毁 EGLDisplay (显示设备)EGL_CALL(eglTerminate(m_eglDisplay));delete m_eglDisplay;}app-releaseWindow();delete app;}void EGLSurfaceView::setRenderer(Renderer *renderer){printf(%s: setRenderer\n, TAG);m_renderer renderer;}bool EGLSurfaceView::surfaceCreated(){printf(%s: surfaceCreated\n, TAG);app-resize(app-width, app-height);createSurface();makeCurrent();if (m_renderer m_firstCreateSurface){m_renderer-onSurfaceCreated();m_firstCreateSurface false;}return true;}void EGLSurfaceView::surfaceChanged(int width, int height){printf(%s: surfaceChanged, width: %d, height: %d\n, TAG, width, height);app-resize(width, height);if (m_renderer){m_renderer-onSurfaceChanged(width, height);}}void EGLSurfaceView::drawFrame(){if (!m_eglSurface || m_eglSurface EGL_NO_SURFACE || !m_renderer){return;}m_renderer-onDrawFrame();EGL_CALL(eglSwapBuffers(m_eglDisplay, m_eglSurface));}void EGLSurfaceView::surfaceDestroy(){printf(%s: surfaceDestroy\n, TAG);if (m_eglDisplay m_eglDisplay ! EGL_NO_DISPLAY){// 与显示设备解绑EGL_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));// 销毁 EGLSurfaceif (m_eglSurface m_eglSurface ! EGL_NO_SURFACE){EGL_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));m_eglSurface nullptr;}}app-releaseWindow();}// 1.创建EGLDisplayvoid EGLSurfaceView::createDisplay(){EGL_CALL(m_eglDisplay eglGetDisplay(EGL_DEFAULT_DISPLAY));EGL_CALL(eglInitialize(m_eglDisplay, nullptr, nullptr));}// 2.创建EGLConfigvoid EGLSurfaceView::createConfig(){if (m_eglDisplay m_eglDisplay ! EGL_NO_DISPLAY){const EGLint configAttrs[] {EGL_RED_SIZE, 8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,EGL_DEPTH_SIZE, 8,EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,EGL_SURFACE_TYPE, EGL_WINDOW_BIT,EGL_NONE};EGLint numConfigs;EGL_CALL(eglChooseConfig(m_eglDisplay, configAttrs, m_eglConfig, 1, numConfigs));}}// 3.创建EGLContextvoid EGLSurfaceView::createContext(){if (m_eglConfig){const EGLint contextAttrs[] {EGL_CONTEXT_CLIENT_VERSION, 3,EGL_NONE};EGL_CALL(m_eglContext eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs));}}// 4.创建EGLSurfacevoid EGLSurfaceView::createSurface(){if (m_eglContext m_eglContext ! EGL_NO_CONTEXT) {EGL_CALL(m_eglSurface eglCreateWindowSurface(m_eglDisplay, m_eglConfig, app-getWindow(), nullptr));}}// 5.绑定EGLSurface和EGLContext到显示设备EGLDisplayvoid EGLSurfaceView::makeCurrent(){if (m_eglSurface m_eglSurface ! EGL_NO_SURFACE){EGL_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));}}} // namespace glcore2.7 ShaderProgram ShaderProgram 主要用于编译 Shader、链接 Program、设置 attribute 属性、更新 uniform 属性。 glGetAttribLocation、glGetUniformLocation 两个接口需要 CPU 向 GPU 查询 location 信息并且会频繁调用为提高性能笔者设计了 m_attributes 和 m_uniforms 两个 map 存储 name 到 location 的映射方便快速获取 location避免 CPU 频繁与 GPU 交互以提高渲染性能。 shader_program.h#pragma once#include map#include core_lib.husing namespace std;namespace glcore{/*** 着色器程序* author little fat sheep*/class ShaderProgram{public:static constexpr char* ATTRIBUTE_POSITION a_position; // 着色器中位置属性名static constexpr char* ATTRIBUTE_NORMAL a_normal; // 着色器中位法线性名static constexpr char* ATTRIBUTE_COLOR a_color; // 着色器中颜色属性名static constexpr char* ATTRIBUTE_TEXCOORD a_texCoord; // 着色器中纹理坐标属性名static constexpr char* ATTRIBUTE_TANGENT a_tangent; // 着色器中切线属性名static constexpr char* ATTRIBUTE_BINORMAL a_binormal; // 着色器中副切线属性名static constexpr char* UNIFORM_TEXTURE u_texture; // 着色器中纹理名static constexpr char* UNIFORM_VP u_projectionViewMatrix; // 着色器中VP名private:GLuint m_program;mapconst char*, int m_attributes;mapconst char*, int m_uniforms;public:ShaderProgram(const char* vertexCode, const char* fragmentCode);~ShaderProgram();void bind();GLuint getHandle() { return m_program; }// 操作attribute属性void enableVertexAttribArray(const char* name);void enableVertexAttribArray(int location);void setVertexAttribPointer(const char* name, int size, int type, bool normalize, int stride, int offset);void setVertexAttribPointer(int location, int size, int type, bool normalize, int stride, int offset);void disableVertexAttribArray(const char* name);void disableVertexAttribArray(int location);// 操作uniform属性void setUniformi(const char* name, int value);void setUniformi(int location, int value);void setUniformi(const char* name, int value1, int value2);void setUniformi(int location, int value1, int value2);void setUniformi(const char* name, int value1, int value2, int value3);void setUniformi(int location, int value1, int value2, int value3);void setUniformi(const char* name, int value1, int value2, int value3, int value4);void setUniformi(int location, int value1, int value2, int value3, int value4);void setUniformf(const char* name, float value);void setUniformf(int location, float value);void setUniformf(const char* name, float value1, float value2);void setUniformf(int location, float value1, float value2);void setUniformf(const char* name, float value1, float value2, int value3);void setUniformf(int location, float value1, float value2, int value3);void setUniformf(const char* name, float value1, float value2, int value3, int value4);void setUniformf(int location, float value1, float value2, int value3, int value4);void setUniform1fv(const char* name, int length, const float values[]);void setUniform1fv(int location, int count, float const values[]);void setUniform2fv(const char* name, int count, const float values[]);void setUniform2fv(int location, int count, const float values[]);void setUniform3fv(const char* name, int count, const float values[]);void setUniform3fv(int location, int count, const float values[]);void setUniform4fv(const char* name, int count, const float values[]);void setUniform4fv(int location, int count, const float values[]);void setUniformMatrix2fv(const char* name, int count, bool transpose, const float *value);void setUniformMatrix2fv(int location, int count, bool transpose, const float *value);void setUniformMatrix3fv(const char* name, int count, bool transpose, const float *value);void setUniformMatrix3fv(int location, int count, bool transpose, const float *value);void setUniformMatrix4fv(const char* name, int count, bool transpose, const float *value);void setUniformMatrix4fv(int location, int count, bool transpose, const float *value);int fetchAttributeLocation(const char* name);int fetchUniformLocation(const char* name);private:void compileShaders(const char* vertexCode, const char* fragmentCode);GLuint loadShader(GLenum type, const char* source);GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);};} // namespace glcore shader_program.cpp#include iostream#include glcore/gl_inspector.h#include glcore/shader_program.h#define TAG ShaderProgramnamespace glcore{ShaderProgram::ShaderProgram(const char* vertexCode, const char* fragmentCode){compileShaders(vertexCode, fragmentCode);}ShaderProgram::~ShaderProgram(){if (m_program){GL_CALL(glUseProgram(0));GL_CALL(glDeleteProgram(m_program));m_program 0;}m_attributes.clear();m_uniforms.clear();}void ShaderProgram::bind(){GL_CALL(glUseProgram(m_program));}void ShaderProgram::enableVertexAttribArray(const char* name){int location fetchAttributeLocation(name);enableVertexAttribArray(location);}void ShaderProgram::enableVertexAttribArray(int location){GL_CALL(glEnableVertexAttribArray(location));}void ShaderProgram::setVertexAttribPointer(const char *name, int size, int type, bool normalize, int stride, int offset){int location fetchAttributeLocation(name);