282 lines
7.5 KiB
C++
282 lines
7.5 KiB
C++
// GLESRenderer.cpp
|
|
#include "EngineFrame/Render/GLESRenderer.h"
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <glm/ext/matrix_float4x4.hpp>
|
|
#include <glm/ext/matrix_transform.hpp>
|
|
#include <glm/ext/matrix_clip_space.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
// 顶点着色器源码
|
|
const char *vertexShaderSource = R"(
|
|
#version 300 es
|
|
precision mediump float;
|
|
|
|
layout(location = 0) in vec2 aPosition;
|
|
layout(location = 1) in vec2 aTexCoord;
|
|
|
|
out vec2 vTexCoord;
|
|
|
|
uniform mat4 uProjection;
|
|
uniform mat4 uModel;
|
|
|
|
void main() {
|
|
gl_Position = uProjection * uModel * vec4(aPosition, 0.0, 1.0);
|
|
vTexCoord = aTexCoord;
|
|
}
|
|
)";
|
|
|
|
// 片段着色器源码
|
|
const char *fragmentShaderSource = R"(
|
|
#version 300 es
|
|
precision mediump float;
|
|
|
|
in vec2 vTexCoord;
|
|
out vec4 FragColor;
|
|
|
|
uniform sampler2D uTexture;
|
|
uniform vec4 uColor;
|
|
|
|
void main() {
|
|
FragColor = texture(uTexture, vTexCoord) * uColor;
|
|
}
|
|
)";
|
|
|
|
GLESRenderer::GLESRenderer(SDL_Window *window) : m_window(window), m_glContext(nullptr)
|
|
{
|
|
}
|
|
|
|
GLESRenderer::~GLESRenderer()
|
|
{
|
|
if (m_glContext)
|
|
{
|
|
SDL_GL_DeleteContext(m_glContext);
|
|
}
|
|
|
|
glDeleteProgram(m_shaderProgram);
|
|
glDeleteShader(m_vertexShader);
|
|
glDeleteShader(m_fragmentShader);
|
|
glDeleteBuffers(1, &m_vbo);
|
|
glDeleteVertexArrays(1, &m_vao);
|
|
}
|
|
|
|
bool GLESRenderer::Initialize()
|
|
{
|
|
// 设置 OpenGL ES 属性
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
|
|
|
// 创建 OpenGL ES 上下文
|
|
m_glContext = SDL_GL_CreateContext(m_window);
|
|
if (!m_glContext)
|
|
{
|
|
std::cerr << "Failed to create OpenGL ES context: " << SDL_GetError() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// 初始化 GLEW (如果需要) 或者直接使用 OpenGL ES 函数
|
|
|
|
// 创建着色器程序
|
|
if (!CreateShaderProgram())
|
|
{
|
|
std::cerr << "Failed to create shader program" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// 设置视口
|
|
int w, h;
|
|
SDL_GetWindowSize(m_window, &w, &h);
|
|
glViewport(0, 0, w, h);
|
|
|
|
// 设置正交投影
|
|
SetOrthographicProjection(w, h);
|
|
|
|
// 启用混合
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
// 创建VAO和VBO
|
|
glGenVertexArrays(1, &m_vao);
|
|
glGenBuffers(1, &m_vbo);
|
|
|
|
glBindVertexArray(m_vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
|
|
|
// 设置顶点属性指针
|
|
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);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GLESRenderer::Clear()
|
|
{
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
// 清空批处理
|
|
m_renderBatch.clear();
|
|
}
|
|
|
|
void GLESRenderer::Present()
|
|
{
|
|
// 按Z顺序排序
|
|
std::stable_sort(m_renderBatch.begin(), m_renderBatch.end(),
|
|
[](const RenderCommand &a, const RenderCommand &b)
|
|
{
|
|
return a.z_order < b.z_order;
|
|
});
|
|
|
|
// 使用着色器程序
|
|
glUseProgram(m_shaderProgram);
|
|
|
|
// 设置投影矩阵
|
|
GLint projLoc = glGetUniformLocation(m_shaderProgram, "uProjection");
|
|
// 这里需要设置正交投影矩阵
|
|
|
|
// 渲染批处理中的所有命令
|
|
for (const auto &cmd : m_renderBatch)
|
|
{
|
|
// 绑定纹理
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, cmd.texture);
|
|
glUniform1i(glGetUniformLocation(m_shaderProgram, "uTexture"), 0);
|
|
|
|
// 计算模型矩阵(位置、旋转、缩放)
|
|
glm::mat4 model = glm::mat4(1.0f);
|
|
model = glm::translate(model, glm::vec3(cmd.dstrect.x, cmd.dstrect.y, 0.0f));
|
|
|
|
if (cmd.angle != 0)
|
|
{
|
|
// 应用旋转
|
|
model = glm::translate(model, glm::vec3(cmd.center.x, cmd.center.y, 0.0f));
|
|
model = glm::rotate(model, glm::radians(static_cast<float>(cmd.angle)), glm::vec3(0.0f, 0.0f, 1.0f));
|
|
model = glm::translate(model, glm::vec3(-cmd.center.x, -cmd.center.y, 0.0f));
|
|
}
|
|
|
|
model = glm::scale(model, glm::vec3(cmd.dstrect.w, cmd.dstrect.h, 1.0f));
|
|
|
|
// 设置模型矩阵
|
|
GLint modelLoc = glGetUniformLocation(m_shaderProgram, "uModel");
|
|
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
|
|
|
|
// 绘制矩形
|
|
glBindVertexArray(m_vao);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
// 交换缓冲区
|
|
SDL_GL_SwapWindow(m_window);
|
|
}
|
|
|
|
void GLESRenderer::RenderCopy(GLuint texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect)
|
|
{
|
|
RenderCommand cmd;
|
|
cmd.texture = texture;
|
|
if (dstrect)
|
|
cmd.dstrect = *dstrect;
|
|
cmd.angle = 0;
|
|
cmd.flip = SDL_FLIP_NONE;
|
|
cmd.z_order = 0; // 需要从Sprite获取Z顺序
|
|
|
|
m_renderBatch.push_back(cmd);
|
|
}
|
|
|
|
void GLESRenderer::RenderCopyEx(GLuint texture, const SDL_Rect *srcrect, const SDL_Rect *dstrect,
|
|
double angle, const SDL_Point *center, SDL_RendererFlip flip)
|
|
{
|
|
RenderCommand cmd;
|
|
cmd.texture = texture;
|
|
if (dstrect)
|
|
cmd.dstrect = *dstrect;
|
|
cmd.angle = angle;
|
|
if (center)
|
|
cmd.center = *center;
|
|
cmd.flip = flip;
|
|
cmd.z_order = 0; // 需要从Sprite获取Z顺序
|
|
|
|
m_renderBatch.push_back(cmd);
|
|
}
|
|
|
|
bool GLESRenderer::CompileShader(const char *source, GLenum type, GLuint &shader)
|
|
{
|
|
shader = glCreateShader(type);
|
|
glShaderSource(shader, 1, &source, NULL);
|
|
glCompileShader(shader);
|
|
|
|
GLint success;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
GLchar infoLog[512];
|
|
glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
|
std::cerr << "Shader compilation failed: " << infoLog << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GLESRenderer::LinkProgram(GLuint program)
|
|
{
|
|
glLinkProgram(program);
|
|
|
|
GLint success;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
|
if (!success)
|
|
{
|
|
GLchar infoLog[512];
|
|
glGetProgramInfoLog(program, 512, NULL, infoLog);
|
|
std::cerr << "Program linking failed: " << infoLog << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GLESRenderer::CreateShaderProgram()
|
|
{
|
|
if (!CompileShader(vertexShaderSource, GL_VERTEX_SHADER, m_vertexShader))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!CompileShader(fragmentShaderSource, GL_FRAGMENT_SHADER, m_fragmentShader))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_shaderProgram = glCreateProgram();
|
|
glAttachShader(m_shaderProgram, m_vertexShader);
|
|
glAttachShader(m_shaderProgram, m_fragmentShader);
|
|
|
|
if (!LinkProgram(m_shaderProgram))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
glDeleteShader(m_vertexShader);
|
|
glDeleteShader(m_fragmentShader);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GLESRenderer::SetOrthographicProjection(int width, int height)
|
|
{
|
|
// 设置正交投影矩阵
|
|
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(width),
|
|
static_cast<float>(height), 0.0f,
|
|
-1.0f, 1.0f);
|
|
|
|
glUseProgram(m_shaderProgram);
|
|
GLint projLoc = glGetUniformLocation(m_shaderProgram, "uProjection");
|
|
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
|
|
} |