#include "RenderManager.h" #include #include "Texture.h" RenderManager::RenderManager(SDL_Window *window) { _window = window; // 创建OpenGL上下文 _ctx = SDL_GL_CreateContext(window); if (!_ctx) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL context create failed: %s\n", SDL_GetError()); } // 初始化GLAD if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GLAD init failed!\n"); } // 获取窗口大小 int width, height; SDL_GetWindowSize(window, &width, &height); // 设置视口 glViewport(0, 0, width, height); // 设置窗口尺寸 _windowWidth = width; _windowHeight = height; // 游戏的初始正交投影矩阵 _GameOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f); // UI的初始正交投影矩阵 _UIOrthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f); // 设置清屏颜色 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 启用混合模式 glEnable(GL_BLEND); // 默认设置标准alpha混合 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 初始化着色器程序 InitShaderProgram(); // 初始化绘制2D纹理缓冲程序 Init2DTextureProgram(); // 设定默认使用的着色器程序和缓冲程序 SetCurrentShaderProgram("normal"); SetCurrentBufferObject("2DTexture"); } RenderManager::~RenderManager() { // 释放着色器程序 for (auto &[name, program] : _shaderProgramMap) { glDeleteProgram(program); } // 释放缓冲对象 for (auto &[name, program] : _RenderParamsMap) { glDeleteVertexArrays(1, &program.VAO); glDeleteBuffers(1, &program.VBO); glDeleteBuffers(1, &program.EBO); } // 释放OpenGL上下文 SDL_GL_DeleteContext(_ctx); } void RenderManager::InitShaderProgram() { std::ifstream shaderFile("shader/config.json"); nlohmann::json shaderConfig; shaderFile >> shaderConfig; for (auto &[groupName, groupData] : shaderConfig["shader"].items()) { if (!groupData.is_object()) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误,跳过\n", groupName.c_str()); continue; } if (!groupData.contains("vertex") || !groupData["vertex"].is_string()) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 vertex 路径,跳过\n", groupName.c_str()); continue; } if (!groupData.contains("fragment") || !groupData["fragment"].is_string()) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 fragment 路径,跳过\n", groupName.c_str()); continue; } std::string vertPath = groupData["vertex"].get(); std::string fragPath = groupData["fragment"].get(); GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertPath); GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath); if (vertexShader == 0 || fragmentShader == 0) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器编译失败,跳过\n", groupName.c_str()); continue; } GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); GLint programLinksuccess; glGetProgramiv(program, GL_LINK_STATUS, &programLinksuccess); if (!programLinksuccess) { char infoLog[512]; glGetProgramInfoLog(program, 512, nullptr, infoLog); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器链接失败,失败原因: %s\n", groupName.c_str(), infoLog); } _shaderProgramMap[groupName] = program; glDeleteShader(vertexShader); glDeleteShader(fragmentShader); } } void RenderManager::Init2DTextureProgram() { // 初始化顶点数据(矩形的四个顶点) float vertices[] = { 0.0f, 0.0f, 0.0f, 0.0f, // 左下(单位坐标) 1.0f, 0.0f, 1.0f, 0.0f, // 右下 1.0f, 1.0f, 1.0f, 1.0f, // 右上 0.0f, 1.0f, 0.0f, 1.0f // 左上 }; // 索引数组 unsigned int indices[] = {0, 1, 2, 2, 3, 0}; GLuint VAO, VBO, EBO; // 创建VAO/VBO/EBO glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glEnableVertexAttribArray(1); // 创建完解绑 glBindVertexArray(0); SetCurrentShaderProgram("normal"); glUseProgram(_currentShaderProgram); // 获取uniform变量位置 GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel"); GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj"); GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture"); if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无法获取着色器 uniform 变量位置\n"); } std::vector uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc}; DrawLogicFunc drawFunc = [this]( RefPtr textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata) { GLuint texture = textureObj->getID(); if (!texture || !dstrect) return; glUseProgram(_currentShaderProgram); glm::mat4 model = glm::mat4(1.0f); // 平移 model = glm::translate(model, glm::vec3(dstrect->x, dstrect->y, 0.0f)); // 计算旋转中心 float centerX = center ? center->x : dstrect->w * 0.5f; float centerY = center ? center->y : dstrect->h * 0.5f; // 旋转中心平移 model = glm::translate(model, glm::vec3(centerX, centerY, 0.0f)); // 旋转 if (angle != 0.0) { model = glm::rotate(model, glm::radians(static_cast(angle)), glm::vec3(0.0f, 0.0f, 1.0f)); } // 旋转中心平移 model = glm::translate(model, glm::vec3(-centerX, -centerY, 0.0f)); // 缩放和翻转 float scaleX = dstrect->w; float scaleY = dstrect->h; // 应用翻转(通过负缩放实现) if (flip & SDL_FLIP_HORIZONTAL) scaleX = -scaleX; if (flip & SDL_FLIP_VERTICAL) scaleY = -scaleY; model = glm::scale(model, glm::vec3(scaleX, scaleY, 1.0f)); // 翻转后的位置补偿 if (flip & SDL_FLIP_HORIZONTAL) { model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 0.0f)); } if (flip & SDL_FLIP_VERTICAL) { model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0f)); } // 设置着色器 uniforms glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_OrthoMatrix)); // 绑定纹理并设置采样器 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(_currentRenderParams.UnimLocs[2], 0); // 处理纹理裁剪 float texWidth = (float)textureObj->getSize().width; float texHeight = (float)textureObj->getSize().height; // 计算纹理坐标 float minu, minv, maxu, maxv; if (srcrect) { minu = (float)srcrect->x / texWidth; minv = (float)srcrect->y / texHeight; maxu = (float)(srcrect->x + srcrect->w) / texWidth; maxv = (float)(srcrect->y + srcrect->h) / texHeight; } else { minu = 0.0f; minv = 0.0f; maxu = 1.0f; maxv = 1.0f; } // 计算顶点位置(单位矩形,通过模型变换进行缩放和平移) float minx = 0.0f; float miny = 0.0f; float maxx = 1.0f; float maxy = 1.0f; // 创建顶点数据(位置 + 纹理坐标) float vertices[] = { // 位置 // 纹理坐标 minx, miny, minu, minv, // 左上 maxx, miny, maxu, minv, // 右上 maxx, maxy, maxu, maxv, // 右下 minx, maxy, minu, maxv // 左下 }; // 更新VBO数据 glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); // 绘制纹理 glBindVertexArray(_currentRenderParams.VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); }; GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, drawFunc}; AddBufferObject("2DTexture", bufferObject); } void RenderManager::SetCurrentShaderProgram(std::string name) { if (_shaderProgramMap.find(name) != _shaderProgramMap.end()) { this->_currentShaderProgram = _shaderProgramMap[name]; } else SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到着色器程序: %s\n", name.c_str()); } void RenderManager::SetCurrentBufferObject(std::string name) { if (_RenderParamsMap.find(name) != _RenderParamsMap.end()) { this->_currentRenderParams = _RenderParamsMap[name]; } else SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str()); } void RenderManager::ClearScreen() { glClear(GL_COLOR_BUFFER_BIT); _frameRenderCount = 0; } void RenderManager::SwapBuffer() { SDL_GL_SwapWindow(_window); } void RenderManager::SetClipRect(const SDL_Rect *rect) { glEnable(GL_SCISSOR_TEST); glScissor(rect->x, _windowHeight - rect->y - rect->h, rect->w, rect->h); } void RenderManager::CloseClipRect() { glDisable(GL_SCISSOR_TEST); } void RenderManager::DrawTexture(RefPtr textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata) { _frameRenderCount++; if (_currentRenderParams.DrawFunc != nullptr) _currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata); else SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染逻辑函数\n"); } void RenderManager::SetOrthoMatrixType(int type) { if (type == 0) _OrthoMatrix = _GameOrthoMatrix; else _OrthoMatrix = _UIOrthoMatrix; } glm::mat4 RenderManager::GetOrthoMatrix() { return _OrthoMatrix; } void RenderManager::SetOrthoMatrix(glm::mat4 matrix) { _OrthoMatrix = matrix; } GLuint RenderManager::CompileShader(GLenum type, std::string Path) { std::ifstream Source("shader/" + Path); if (!Source.is_open()) { SDL_LogError(0, "Failed to open shader file: %s\n", Path.c_str()); return 0; } std::string ShaderSource((std::istreambuf_iterator(Source)), std::istreambuf_iterator()); const char *SourcePtr = ShaderSource.c_str(); GLuint ShaderId = glCreateShader(type); glShaderSource(ShaderId, 1, &SourcePtr, NULL); glCompileShader(ShaderId); // 检查编译错误 GLint success; glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(ShaderId, 512, nullptr, infoLog); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Shader compile error: %s\n", infoLog); glDeleteShader(ShaderId); return 0; } return ShaderId; } void RenderManager::AddBufferObject(std::string name, GL_RenderParams bufferObject) { _RenderParamsMap[name] = bufferObject; }