2026-02-11 19:40:26 +08:00
|
|
|
|
#pragma once
|
|
|
|
|
|
|
2026-02-16 23:14:12 +08:00
|
|
|
|
#include <extra2d/graphics/core/render_backend.h>
|
2026-02-20 13:07:43 +08:00
|
|
|
|
#include <extra2d/graphics/opengl/gl_buffer.h>
|
|
|
|
|
|
#include <extra2d/graphics/opengl/gl_framebuffer.h>
|
|
|
|
|
|
#include <extra2d/graphics/opengl/gl_pipeline.h>
|
|
|
|
|
|
#include <extra2d/graphics/opengl/gl_sprite_batch.h>
|
2026-02-16 23:14:12 +08:00
|
|
|
|
#include <extra2d/graphics/shader/shader_interface.h>
|
2026-02-11 19:40:26 +08:00
|
|
|
|
|
2026-02-20 13:07:43 +08:00
|
|
|
|
|
2026-02-13 10:00:39 +08:00
|
|
|
|
#include <array>
|
2026-02-11 19:40:26 +08:00
|
|
|
|
#include <glad/glad.h>
|
2026-02-12 21:50:21 +08:00
|
|
|
|
#include <vector>
|
2026-02-11 19:40:26 +08:00
|
|
|
|
|
|
|
|
|
|
namespace extra2d {
|
|
|
|
|
|
|
2026-02-17 22:36:02 +08:00
|
|
|
|
// 前向声明
|
2026-02-20 14:43:34 +08:00
|
|
|
|
class GLFWWindow;
|
2026-02-17 22:36:02 +08:00
|
|
|
|
class GLContext;
|
|
|
|
|
|
class GLFramebuffer;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// OpenGL 渲染器实现
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
class GLRenderer : public RenderBackend {
|
|
|
|
|
|
public:
|
2026-02-13 10:00:39 +08:00
|
|
|
|
GLRenderer();
|
|
|
|
|
|
~GLRenderer() override;
|
|
|
|
|
|
|
|
|
|
|
|
// RenderBackend 接口实现
|
2026-02-20 14:43:34 +08:00
|
|
|
|
bool init(GLFWWindow *window) override;
|
2026-02-13 10:00:39 +08:00
|
|
|
|
void shutdown() override;
|
|
|
|
|
|
|
|
|
|
|
|
void beginFrame(const Color &clearColor) override;
|
|
|
|
|
|
void endFrame() override;
|
|
|
|
|
|
void setViewport(int x, int y, int width, int height) override;
|
|
|
|
|
|
void setVSync(bool enabled) override;
|
|
|
|
|
|
|
|
|
|
|
|
void setBlendMode(BlendMode mode) override;
|
|
|
|
|
|
void setViewProjection(const glm::mat4 &matrix) override;
|
|
|
|
|
|
|
|
|
|
|
|
// 变换矩阵栈
|
|
|
|
|
|
void pushTransform(const glm::mat4 &transform) override;
|
|
|
|
|
|
void popTransform() override;
|
|
|
|
|
|
glm::mat4 getCurrentTransform() const override;
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
|
|
|
|
|
|
int channels) override;
|
|
|
|
|
|
Ptr<Texture> loadTexture(const std::string &filepath) override;
|
|
|
|
|
|
|
|
|
|
|
|
void beginSpriteBatch() override;
|
|
|
|
|
|
void drawSprite(const Texture &texture, const Rect &destRect,
|
|
|
|
|
|
const Rect &srcRect, const Color &tint, float rotation,
|
|
|
|
|
|
const Vec2 &anchor) override;
|
|
|
|
|
|
void drawSprite(const Texture &texture, const Vec2 &position,
|
|
|
|
|
|
const Color &tint) override;
|
|
|
|
|
|
void endSpriteBatch() override;
|
2026-02-17 20:16:07 +08:00
|
|
|
|
void flush() override;
|
2026-02-13 10:00:39 +08:00
|
|
|
|
|
|
|
|
|
|
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
|
|
|
|
|
float width) override;
|
|
|
|
|
|
void drawRect(const Rect &rect, const Color &color, float width) override;
|
|
|
|
|
|
void fillRect(const Rect &rect, const Color &color) override;
|
|
|
|
|
|
void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
|
|
|
|
|
int segments, float width) override;
|
|
|
|
|
|
void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
|
|
|
|
|
int segments) override;
|
|
|
|
|
|
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
|
|
|
|
|
const Color &color, float width) override;
|
|
|
|
|
|
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
|
|
|
|
|
const Color &color) override;
|
|
|
|
|
|
void drawPolygon(const std::vector<Vec2> &points, const Color &color,
|
|
|
|
|
|
float width) override;
|
|
|
|
|
|
void fillPolygon(const std::vector<Vec2> &points,
|
|
|
|
|
|
const Color &color) override;
|
|
|
|
|
|
|
|
|
|
|
|
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
|
|
|
|
|
|
bool useSDF = false) override;
|
|
|
|
|
|
void drawText(const FontAtlas &font, const std::string &text,
|
|
|
|
|
|
const Vec2 &position, const Color &color) override;
|
|
|
|
|
|
void drawText(const FontAtlas &font, const std::string &text, float x,
|
|
|
|
|
|
float y, const Color &color) override;
|
|
|
|
|
|
|
|
|
|
|
|
Stats getStats() const override { return stats_; }
|
|
|
|
|
|
void resetStats() override;
|
2026-02-11 19:40:26 +08:00
|
|
|
|
|
2026-02-17 22:36:02 +08:00
|
|
|
|
// GLFramebuffer 相关方法
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 创建帧缓冲对象
|
|
|
|
|
|
* @param desc 帧缓冲描述
|
|
|
|
|
|
* @return 创建的帧缓冲智能指针
|
|
|
|
|
|
*/
|
2026-02-20 13:07:43 +08:00
|
|
|
|
Ptr<GLFramebuffer> createFramebuffer(const FramebufferDesc &desc);
|
2026-02-17 22:36:02 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 绑定帧缓冲(作为渲染目标)
|
|
|
|
|
|
* @param framebuffer 帧缓冲对象指针,传入 nullptr 则绑定默认帧缓冲
|
|
|
|
|
|
*/
|
2026-02-20 13:07:43 +08:00
|
|
|
|
void bindFramebuffer(GLFramebuffer *framebuffer);
|
2026-02-17 22:36:02 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 解绑帧缓冲(恢复到默认帧缓冲)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void unbindFramebuffer();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 获取默认帧缓冲
|
|
|
|
|
|
* @return 默认帧缓冲智能指针
|
|
|
|
|
|
*/
|
|
|
|
|
|
Ptr<GLFramebuffer> getDefaultFramebuffer() const;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 清除当前绑定的帧缓冲
|
|
|
|
|
|
* @param color 清除颜色
|
|
|
|
|
|
* @param clearColor 是否清除颜色缓冲
|
|
|
|
|
|
* @param clearDepth 是否清除深度缓冲
|
|
|
|
|
|
* @param clearStencil 是否清除模板缓冲
|
|
|
|
|
|
*/
|
2026-02-20 13:07:43 +08:00
|
|
|
|
void clearFramebuffer(const Color &color, bool clearColor = true,
|
2026-02-17 22:36:02 +08:00
|
|
|
|
bool clearDepth = true, bool clearStencil = false);
|
|
|
|
|
|
|
2026-02-11 19:40:26 +08:00
|
|
|
|
private:
|
2026-02-13 10:00:39 +08:00
|
|
|
|
// 形状批处理常量
|
|
|
|
|
|
static constexpr size_t MAX_CIRCLE_SEGMENTS = 128;
|
|
|
|
|
|
static constexpr size_t MAX_SHAPE_VERTICES = 8192; // 最大形状顶点数
|
2026-02-13 10:25:07 +08:00
|
|
|
|
static constexpr size_t MAX_LINE_VERTICES = 16384; // 最大线条顶点数
|
2026-02-13 10:00:39 +08:00
|
|
|
|
|
|
|
|
|
|
// 形状顶点结构(包含颜色)
|
|
|
|
|
|
struct ShapeVertex {
|
|
|
|
|
|
float x, y;
|
|
|
|
|
|
float r, g, b, a;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-20 14:43:34 +08:00
|
|
|
|
GLFWWindow *window_;
|
2026-02-13 10:00:39 +08:00
|
|
|
|
GLSpriteBatch spriteBatch_;
|
2026-02-15 11:12:27 +08:00
|
|
|
|
Ptr<IShader> shapeShader_;
|
2026-02-20 13:07:43 +08:00
|
|
|
|
Ptr<IShader> sdfFontShader_; // SDF字体专用着色器
|
2026-02-13 10:00:39 +08:00
|
|
|
|
|
2026-02-20 13:07:43 +08:00
|
|
|
|
GLuint shapeVao_; // 形状 VAO(手动管理,用于顶点属性配置)
|
|
|
|
|
|
GLBuffer shapeBuffer_; // 形状 VBO(使用 GLBuffer 管理)
|
|
|
|
|
|
GLuint lineVao_; // 线条 VAO(手动管理,用于顶点属性配置)
|
|
|
|
|
|
GLBuffer lineBuffer_; // 线条 VBO(使用 GLBuffer 管理)
|
2026-02-13 10:00:39 +08:00
|
|
|
|
|
|
|
|
|
|
glm::mat4 viewProjection_;
|
|
|
|
|
|
std::vector<glm::mat4> transformStack_;
|
|
|
|
|
|
Stats stats_;
|
|
|
|
|
|
bool vsync_;
|
|
|
|
|
|
|
|
|
|
|
|
// 形状批处理缓冲区(预分配,避免每帧内存分配)
|
|
|
|
|
|
std::array<ShapeVertex, MAX_SHAPE_VERTICES> shapeVertexCache_;
|
|
|
|
|
|
size_t shapeVertexCount_ = 0;
|
|
|
|
|
|
GLenum currentShapeMode_ = GL_TRIANGLES;
|
|
|
|
|
|
|
2026-02-13 10:25:07 +08:00
|
|
|
|
// 线条批处理缓冲区
|
|
|
|
|
|
std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_;
|
|
|
|
|
|
size_t lineVertexCount_ = 0;
|
|
|
|
|
|
float currentLineWidth_ = 1.0f;
|
|
|
|
|
|
|
2026-02-17 22:36:02 +08:00
|
|
|
|
// OpenGL 管线状态管理
|
|
|
|
|
|
GLPipeline pipeline_;
|
2026-02-13 10:00:39 +08:00
|
|
|
|
|
2026-02-17 20:16:07 +08:00
|
|
|
|
// 自动批处理状态
|
2026-02-20 13:07:43 +08:00
|
|
|
|
bool batchActive_ = false; // 批处理是否激活
|
|
|
|
|
|
bool autoBatchEnabled_ = true; // 是否启用自动批处理
|
|
|
|
|
|
const Texture *currentBatchTexture_ = nullptr; // 当前批处理的纹理
|
|
|
|
|
|
std::vector<SpriteData> pendingSprites_; // 待提交的精灵
|
2026-02-17 20:16:07 +08:00
|
|
|
|
static constexpr size_t MAX_BATCH_SPRITES = 1000; // 最大批处理精灵数
|
|
|
|
|
|
|
2026-02-17 22:36:02 +08:00
|
|
|
|
// 帧缓冲管理
|
2026-02-20 13:07:43 +08:00
|
|
|
|
mutable Ptr<GLFramebuffer> defaultFramebuffer_; // 默认帧缓冲(延迟创建)
|
|
|
|
|
|
GLFramebuffer *currentFramebuffer_ = nullptr; // 当前绑定的帧缓冲
|
2026-02-17 22:36:02 +08:00
|
|
|
|
|
2026-02-13 10:00:39 +08:00
|
|
|
|
void initShapeRendering();
|
2026-02-20 13:07:43 +08:00
|
|
|
|
void ensureBatchActive(); // 确保批处理已激活
|
|
|
|
|
|
void submitPendingSprites(); // 提交待处理的精灵
|
2026-02-13 10:00:39 +08:00
|
|
|
|
void flushShapeBatch();
|
2026-02-13 10:25:07 +08:00
|
|
|
|
void flushLineBatch();
|
2026-02-13 10:00:39 +08:00
|
|
|
|
void addShapeVertex(float x, float y, const Color &color);
|
2026-02-13 10:25:07 +08:00
|
|
|
|
void addLineVertex(float x, float y, const Color &color);
|
2026-02-13 10:00:39 +08:00
|
|
|
|
void submitShapeBatch(GLenum mode);
|
2026-02-11 19:40:26 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace extra2d
|