Extra2D/src/renderer/renderer_module.cpp

555 lines
16 KiB
C++
Raw Normal View History

#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