Extra2D/src/renderer/renderer_module.cpp

555 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "glad/glad.h"
#include <algorithm>
#include <event/events.h>
#include <glm/gtc/type_ptr.hpp>
#include <renderer/renderer_module.h>
#include <utils/logger.h>
// SDL for window size query
#include <SDL.h>
namespace extra2d {
RendererModule::RendererModule() = default;
RendererModule::~RendererModule() = default;
RendererModule::RendererModule(RendererModule &&other) noexcept
: materialPool_(std::move(other.materialPool_)),
meshPool_(std::move(other.meshPool_)),
texturePool_(std::move(other.texturePool_)),
commandBuffer_(std::move(other.commandBuffer_)),
commandCount_(other.commandCount_),
uniformManager_(std::move(other.uniformManager_)),
defaultMaterialHandle_(other.defaultMaterialHandle_),
defaultQuadHandle_(other.defaultQuadHandle_),
defaultTextureHandle_(other.defaultTextureHandle_),
onRenderBeginListener_(std::move(other.onRenderBeginListener_)),
onRenderSubmitListener_(std::move(other.onRenderSubmitListener_)),
onRenderEndListener_(std::move(other.onRenderEndListener_)),
onResizeListener_(std::move(other.onResizeListener_)),
onShowListener_(std::move(other.onShowListener_)),
glInitialized_(other.glInitialized_), stats_(other.stats_),
viewportX_(other.viewportX_), viewportY_(other.viewportY_),
viewportWidth_(other.viewportWidth_),
viewportHeight_(other.viewportHeight_) {
// 重置源对象状态
other.commandCount_ = 0;
other.defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE;
other.defaultQuadHandle_ = INVALID_MESH_HANDLE;
other.defaultTextureHandle_ = INVALID_TEXTURE_HANDLE;
other.glInitialized_ = false;
other.stats_ = {};
other.viewportX_ = 0;
other.viewportY_ = 0;
other.viewportWidth_ = 0;
other.viewportHeight_ = 0;
}
RendererModule &RendererModule::operator=(RendererModule &&other) noexcept {
if (this != &other) {
// 清理当前资源
if (glInitialized_) {
destroyDefaultResources();
uniformManager_.shutdown();
}
// 移动资源
materialPool_ = std::move(other.materialPool_);
meshPool_ = std::move(other.meshPool_);
texturePool_ = std::move(other.texturePool_);
commandBuffer_ = std::move(other.commandBuffer_);
commandCount_ = other.commandCount_;
uniformManager_ = std::move(other.uniformManager_);
defaultMaterialHandle_ = other.defaultMaterialHandle_;
defaultQuadHandle_ = other.defaultQuadHandle_;
defaultTextureHandle_ = other.defaultTextureHandle_;
onRenderBeginListener_ = std::move(other.onRenderBeginListener_);
onRenderSubmitListener_ = std::move(other.onRenderSubmitListener_);
onRenderEndListener_ = std::move(other.onRenderEndListener_);
onResizeListener_ = std::move(other.onResizeListener_);
onShowListener_ = std::move(other.onShowListener_);
glInitialized_ = other.glInitialized_;
stats_ = other.stats_;
viewportX_ = other.viewportX_;
viewportY_ = other.viewportY_;
viewportWidth_ = other.viewportWidth_;
viewportHeight_ = other.viewportHeight_;
// 重置源对象状态
other.commandCount_ = 0;
other.defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE;
other.defaultQuadHandle_ = INVALID_MESH_HANDLE;
other.defaultTextureHandle_ = INVALID_TEXTURE_HANDLE;
other.glInitialized_ = false;
other.stats_ = {};
other.viewportX_ = 0;
other.viewportY_ = 0;
other.viewportWidth_ = 0;
other.viewportHeight_ = 0;
}
return *this;
}
bool RendererModule::init() {
E2D_LOG_INFO("Initializing RendererModule...");
// 绑定事件监听器
onRenderBeginListener_.bind([this]() { onRenderBegin(); });
onRenderSubmitListener_.bind(
[this](const RenderCommand &cmd) { onRenderSubmit(cmd); });
onRenderSetCameraListener_.bind(
[this](const Mat4 &viewProj) { onRenderSetCamera(viewProj); });
onRenderEndListener_.bind([this]() { onRenderEnd(); });
onResizeListener_.bind([this](int32_t w, int32_t h) { onResize(w, h); });
// 延迟 GL 初始化到窗口显示时
onShowListener_.bind([this]() { onWindowShow(); });
E2D_LOG_INFO("RendererModule initialized (waiting for GL context)");
return true;
}
void RendererModule::onWindowShow() {
if (glInitialized_) {
return;
}
E2D_LOG_INFO("Initializing OpenGL context...");
// 初始化 UBO 管理器(需要 GL 上下文)
if (!uniformManager_.initialize()) {
E2D_LOG_ERROR("Failed to initialize UniformBufferManager");
return;
}
// 创建默认资源(需要 GL 上下文)
if (!createDefaultResources()) {
E2D_LOG_ERROR("Failed to create default resources");
return;
}
// 获取实际窗口大小并设置视口
// 查询当前 SDL 窗口大小
int windowWidth = 800, windowHeight = 600;
SDL_Window *sdlWindow = SDL_GL_GetCurrentWindow();
if (sdlWindow) {
SDL_GetWindowSize(sdlWindow, &windowWidth, &windowHeight);
E2D_LOG_INFO("Setting initial viewport to window size: {}x{}", windowWidth,
windowHeight);
} else {
E2D_LOG_WARN("Could not get SDL window, using default viewport 800x600");
}
setViewport(0, 0, static_cast<int32>(windowWidth),
static_cast<int32>(windowHeight));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glInitialized_ = true;
E2D_LOG_INFO("OpenGL context initialized successfully");
}
void RendererModule::shutdown() {
E2D_LOG_INFO("Shutting down RendererModule...");
// 只有在 GL 初始化后才销毁 GL 相关资源
if (glInitialized_) {
// 销毁默认资源
destroyDefaultResources();
// 关闭 UBO 管理器
uniformManager_.shutdown();
}
// 清理资源池
materialPool_.slots.clear();
while (!materialPool_.freeIndices.empty())
materialPool_.freeIndices.pop();
meshPool_.slots.clear();
while (!meshPool_.freeIndices.empty())
meshPool_.freeIndices.pop();
texturePool_.slots.clear();
while (!texturePool_.freeIndices.empty())
texturePool_.freeIndices.pop();
glInitialized_ = false;
E2D_LOG_INFO("RendererModule shutdown complete");
}
MaterialHandle RendererModule::registerMaterial(Ptr<Material> material) {
uint64_t handle = materialPool_.acquire();
auto *slot = materialPool_.get(handle);
if (slot) {
slot->material = material;
}
return handle;
}
MeshHandle RendererModule::registerMesh(Ptr<Mesh> mesh) {
uint64_t handle = meshPool_.acquire();
auto *slot = meshPool_.get(handle);
if (slot) {
slot->mesh = mesh;
}
return handle;
}
TextureHandle RendererModule::registerTexture(Ptr<Texture> texture) {
uint64_t handle = texturePool_.acquire();
auto *slot = texturePool_.get(handle);
if (slot) {
slot->texture = texture;
}
return handle;
}
void RendererModule::unregisterMaterial(MaterialHandle handle) {
materialPool_.release(handle);
}
void RendererModule::unregisterMesh(MeshHandle handle) {
meshPool_.release(handle);
}
void RendererModule::unregisterTexture(TextureHandle handle) {
texturePool_.release(handle);
}
Ptr<Material> RendererModule::getMaterial(MaterialHandle handle) {
auto *slot = materialPool_.get(handle);
return slot ? slot->material : nullptr;
}
Ptr<Mesh> RendererModule::getMesh(MeshHandle handle) {
auto *slot = meshPool_.get(handle);
return slot ? slot->mesh : nullptr;
}
Ptr<Texture> RendererModule::getTexture(TextureHandle handle) {
auto *slot = texturePool_.get(handle);
return slot ? slot->texture : nullptr;
}
void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) {
viewportX_ = x;
viewportY_ = y;
viewportWidth_ = width;
viewportHeight_ = height;
// 更新视口适配器
viewportAdapter_.update(width, height);
// 获取适配后的视口
auto result = viewportAdapter_.getResult();
glViewport(static_cast<GLint>(result.viewport.x),
static_cast<GLint>(result.viewport.y),
static_cast<GLsizei>(result.viewport.w),
static_cast<GLsizei>(result.viewport.h));
}
void RendererModule::clear(const Color &color, uint32_t flags) {
GLbitfield mask = 0;
if (flags & CLEAR_COLOR_FLAG) {
glClearColor(color.r, color.g, color.b, color.a);
mask |= GL_COLOR_BUFFER_BIT;
}
if (flags & CLEAR_DEPTH_FLAG) {
mask |= GL_DEPTH_BUFFER_BIT;
}
if (flags & CLEAR_STENCIL_FLAG) {
mask |= GL_STENCIL_BUFFER_BIT;
}
if (mask != 0) {
glClear(mask);
}
}
void RendererModule::onRenderBegin() {
// 如果 GL 未初始化,跳过渲染
if (!glInitialized_) {
return;
}
// 清除屏幕(黑色背景)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 清空命令缓冲区
commandCount_ = 0;
// 重置统计
stats_ = {};
// 重置 UBO 管理器
uniformManager_.resetMaterialUBOs();
}
void RendererModule::onRenderSubmit(const RenderCommand &cmd) {
// 如果 GL 未初始化,跳过提交
if (!glInitialized_) {
return;
}
// 检查缓冲区是否已满
if (commandCount_ >= MAX_RENDER_COMMANDS) {
E2D_LOG_WARN("Render command buffer full!");
return;
}
// 直接存入预分配缓冲区(无动态分配)
commandBuffer_[commandCount_++] = cmd;
stats_.commandsSubmitted++;
}
void RendererModule::onRenderSetCamera(const Mat4 &viewProj) {
// 如果 GL 未初始化,跳过
if (!glInitialized_) {
return;
}
// 保存视图投影矩阵
viewProjectionMatrix_ = viewProj;
// 更新全局 UBO 中的视图投影矩阵
uniformManager_.updateGlobalUBO(&viewProj, sizeof(Mat4));
}
void RendererModule::onRenderEnd() {
// 如果 GL 未初始化,跳过渲染
if (!glInitialized_) {
return;
}
// 排序命令
sortCommands();
// 批处理并绘制
batchAndDraw();
// 输出统计
E2D_LOG_DEBUG("Render: {} commands, {} draw calls, {} batches",
stats_.commandsExecuted, stats_.drawCalls, stats_.batches);
}
void RendererModule::onResize(int32 width, int32 height) {
setViewport(0, 0, width, height);
}
void RendererModule::sortCommands() {
// 使用 std::sort 对命令进行排序
std::sort(commandBuffer_.begin(), commandBuffer_.begin() + commandCount_,
[](const RenderCommand &a, const RenderCommand &b) {
return a.sortKey < b.sortKey;
});
}
void RendererModule::batchAndDraw() {
MaterialHandle lastMaterial = INVALID_MATERIAL_HANDLE;
MeshHandle lastMesh = INVALID_MESH_HANDLE;
uint32_t batchStart = 0;
uint32_t batchCount = 0;
for (uint32_t i = 0; i < commandCount_; ++i) {
const auto &cmd = commandBuffer_[i];
if (cmd.type != RenderCommandType::DrawMesh) {
// 处理非绘制命令
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
batchCount = 0;
}
executeCommand(cmd);
continue;
}
// 检查是否需要刷新批次
if (cmd.drawMesh.material != lastMaterial ||
cmd.drawMesh.mesh != lastMesh) {
// 刷新上一批次
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
}
lastMaterial = cmd.drawMesh.material;
lastMesh = cmd.drawMesh.mesh;
batchStart = i;
batchCount = 1;
} else {
++batchCount;
}
stats_.commandsExecuted++;
}
// 刷新最后一批
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
}
}
void RendererModule::drawBatch(uint32_t start, uint32_t count,
MaterialHandle materialHandle,
MeshHandle meshHandle) {
auto material = getMaterial(materialHandle);
// 如果材质无效,使用默认材质
if (!material) {
material = getMaterial(defaultMaterialHandle_);
}
auto mesh = getMesh(meshHandle);
// 如果网格无效,使用默认四边形
if (!mesh) {
mesh = getMesh(defaultQuadHandle_);
}
if (!material || !mesh)
return;
// 获取着色器
auto shader = material->getShader();
if (!shader)
return;
// 绑定着色器
shader->bind();
// 设置视图投影矩阵
shader->setMat4("uViewProjection", glm::value_ptr(viewProjectionMatrix_));
// 设置材质参数
// 注意:直接使用默认值,因为材质数据布局可能不匹配
// tintColor 和 opacity 由着色器默认值处理
shader->setVec4("uTintColor", 1.0f, 1.0f, 1.0f, 1.0f);
shader->setFloat("uOpacity", 1.0f);
// 绑定材质中的纹理
const auto &textureSlots = material->getTextures();
bool hasMaterialTexture = false;
for (const auto &slot : textureSlots) {
if (slot.handle != INVALID_TEXTURE_HANDLE) {
auto texture = getTexture(slot.handle);
if (texture) {
texture->bind(slot.slot);
// 设置采样器 uniform
shader->setInt(slot.uniformName, static_cast<int>(slot.slot));
hasMaterialTexture = true;
}
}
}
// 如果材质没有纹理,绑定默认纹理
if (!hasMaterialTexture && defaultTextureHandle_ != INVALID_TEXTURE_HANDLE) {
auto defaultTexture = getTexture(defaultTextureHandle_);
if (defaultTexture) {
defaultTexture->bind(0);
shader->setInt("uTexture", 0);
}
}
// 绑定网格
mesh->bind();
// 对每个实例单独绘制
for (uint32_t i = 0; i < count; ++i) {
Transform transform = commandBuffer_[start + i].getTransform();
float matrix[16];
transform.toMatrix(matrix);
// 设置模型矩阵
shader->setMat4("uModelMatrix", matrix);
// 设置顶点颜色
Color color = commandBuffer_[start + i].getColor();
shader->setVec4("uColor", color.r, color.g, color.b, color.a);
// 绘制
mesh->draw();
stats_.drawCalls++;
}
}
void RendererModule::executeCommand(const RenderCommand &cmd) {
switch (cmd.type) {
case RenderCommandType::SetViewport:
setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width,
cmd.viewport.height);
break;
case RenderCommandType::Clear:
clear(cmd.clear.color, cmd.clear.flags);
break;
default:
break;
}
}
bool RendererModule::createDefaultResources() {
// 创建默认着色器
auto defaultShader = makePtr<Shader>();
if (!defaultShader->loadFromFile("shader/default.vert",
"shader/default.frag")) {
E2D_LOG_ERROR("Failed to load default shader");
return false;
}
// 创建默认材质布局
auto defaultLayout = makePtr<MaterialLayout>();
defaultLayout->addParam("tintColor", MaterialParamType::Color);
defaultLayout->addParam("opacity", MaterialParamType::Float);
defaultLayout->finalize();
// 创建默认材质
auto defaultMaterial = makePtr<Material>();
defaultMaterial->setLayout(defaultLayout);
defaultMaterial->setShader(defaultShader);
defaultMaterial->setColor("tintColor", Color::White);
defaultMaterial->setFloat("opacity", 1.0f);
defaultMaterialHandle_ = registerMaterial(defaultMaterial);
// 创建默认四边形
auto defaultQuad = Mesh::createQuad(Vec2(1.0f, 1.0f));
defaultQuadHandle_ = registerMesh(defaultQuad);
// 创建默认纹理1x1 白色)
auto defaultTexture = makePtr<Texture>();
uint8_t whitePixel[4] = {255, 255, 255, 255};
defaultTexture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8);
defaultTextureHandle_ = registerTexture(defaultTexture);
E2D_LOG_INFO("Default resources created");
return true;
}
void RendererModule::destroyDefaultResources() {
if (defaultMaterialHandle_ != INVALID_MATERIAL_HANDLE) {
unregisterMaterial(defaultMaterialHandle_);
defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE;
}
if (defaultQuadHandle_ != INVALID_MESH_HANDLE) {
unregisterMesh(defaultQuadHandle_);
defaultQuadHandle_ = INVALID_MESH_HANDLE;
}
if (defaultTextureHandle_ != INVALID_TEXTURE_HANDLE) {
unregisterTexture(defaultTextureHandle_);
defaultTextureHandle_ = INVALID_TEXTURE_HANDLE;
}
}
} // namespace extra2d