Extra2D/include/renderer/render_target.h

334 lines
8.9 KiB
C
Raw Normal View History

2026-02-11 19:40:26 +08:00
#pragma once
#include <core/color.h>
#include <core/ref_counted.h>
#include <graphics/opengl/gl_texture.h>
#include <graphics/texture.h>
2026-02-11 19:40:26 +08:00
#include <mutex>
namespace extra2d {
// ============================================================================
// 渲染目标配置
// ============================================================================
struct RenderTargetConfig {
int width = 800; // 宽度
int height = 600; // 高度
PixelFormat colorFormat = PixelFormat::RGBA8; // 颜色格式
bool hasDepth = true; // 是否包含深度缓冲
bool hasDepthBuffer = true; // 兼容旧API的别名 (同hasDepth)
bool hasStencil = false; // 是否包含模板缓冲
int samples = 1; // 多重采样数 (1 = 无MSAA)
bool autoResize = true; // 是否自动调整大小
};
// ============================================================================
// 渲染目标 - 基于FBO的离屏渲染
// ============================================================================
class RenderTarget : public RefCounted {
2026-02-11 19:40:26 +08:00
public:
RenderTarget();
~RenderTarget();
// 禁止拷贝
RenderTarget(const RenderTarget &) = delete;
RenderTarget &operator=(const RenderTarget &) = delete;
// 允许移动
RenderTarget(RenderTarget &&other) noexcept;
RenderTarget &operator=(RenderTarget &&other) noexcept;
// ------------------------------------------------------------------------
// 创建和销毁
// ------------------------------------------------------------------------
/**
* @brief
*/
bool create(const RenderTargetConfig &config);
/**
* @brief create的别名API
*/
bool init(const RenderTargetConfig &config) { return create(config); }
/**
* @brief
*/
bool createFromTexture(IntrusivePtr<Texture> texture, bool hasDepth = false);
2026-02-11 19:40:26 +08:00
/**
* @brief
*/
void destroy();
/**
* @brief destroy的别名API
*/
void shutdown() { destroy(); }
/**
* @brief
*/
bool isValid() const { return fbo_ != 0; }
// ------------------------------------------------------------------------
// 尺寸和格式
// ------------------------------------------------------------------------
int width() const { return width_; }
int height() const { return height_; }
Vec2 size() const {
2026-02-11 19:40:26 +08:00
return Vec2(static_cast<float>(width_), static_cast<float>(height_));
}
PixelFormat getColorFormat() const { return colorFormat_; }
// ------------------------------------------------------------------------
// 绑定和解绑
// ------------------------------------------------------------------------
/**
* @brief
*/
void bind();
/**
* @brief
*/
void unbind();
/**
* @brief
*/
void clear(const Color &color = Colors::Transparent);
// ------------------------------------------------------------------------
// 纹理访问
// ------------------------------------------------------------------------
/**
* @brief
*/
IntrusivePtr<Texture> getColorTexture() const { return colorTexture_; }
2026-02-11 19:40:26 +08:00
/**
* @brief
*/
IntrusivePtr<Texture> getDepthTexture() const { return depthTexture_; }
2026-02-11 19:40:26 +08:00
// ------------------------------------------------------------------------
// 视口和裁剪
// ------------------------------------------------------------------------
/**
* @brief
*/
void setViewport(int x, int y, int width, int height);
/**
* @brief
*/
void getFullViewport(int &x, int &y, int &width, int &height) const;
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/**
* @brief
*/
bool resize(int width, int height);
/**
* @brief
*/
void copyTo(RenderTarget &target);
/**
* @brief blitTo的别名API
* @param target
* @param color
* @param depth
*/
void blitTo(RenderTarget &target, bool color = true, bool depth = false);
/**
* @brief
*/
void copyToScreen(int screenWidth, int screenHeight);
/**
* @brief
*/
bool saveToFile(const std::string &filepath);
// ------------------------------------------------------------------------
// 静态方法
// ------------------------------------------------------------------------
/**
* @brief
*/
static IntrusivePtr<RenderTarget> createFromConfig(const RenderTargetConfig &config);
2026-02-11 19:40:26 +08:00
/**
* @brief ID
*/
static GLuint getCurrentFBO();
/**
* @brief
*/
static void bindDefault();
/**
* @brief FBO ID使
*/
GLuint getFBO() const { return fbo_; }
protected:
GLuint fbo_ = 0; // 帧缓冲对象
GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板)
IntrusivePtr<Texture> colorTexture_; // 颜色纹理
IntrusivePtr<Texture> depthTexture_; // 深度纹理(可选)
2026-02-11 19:40:26 +08:00
int width_ = 0;
int height_ = 0;
PixelFormat colorFormat_ = PixelFormat::RGBA8;
bool hasDepth_ = false;
bool hasStencil_ = false;
int samples_ = 1;
bool createFBO();
void deleteFBO();
};
// ============================================================================
// 多重采样渲染目标用于MSAA
// ============================================================================
class MultisampleRenderTarget : public RenderTarget {
public:
/**
* @brief
*/
bool create(int width, int height, int samples = 4);
/**
* @brief
*/
void resolveTo(RenderTarget &target);
/**
* @brief
*/
void destroy();
private:
GLuint colorRBO_ = 0; // 多重采样颜色渲染缓冲
};
// ============================================================================
// 渲染目标栈(用于嵌套渲染)
// ============================================================================
class RenderTargetStack {
public:
static RenderTargetStack &getInstance();
/**
* @brief
*/
void push(RenderTarget *target);
/**
* @brief
*/
void pop();
/**
* @brief
*/
RenderTarget *getCurrent() const;
/**
* @brief
*/
size_t size() const;
/**
* @brief
*/
void clear();
private:
RenderTargetStack() = default;
~RenderTargetStack() = default;
std::vector<RenderTarget *> stack_;
mutable std::mutex mutex_;
};
// ============================================================================
// 渲染目标管理器 - 全局渲染目标管理
// ============================================================================
class RenderTargetManager {
public:
/**
* @brief
*/
static RenderTargetManager &getInstance();
/**
* @brief
* @param width
* @param height
*/
bool init(int width, int height);
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
IntrusivePtr<RenderTarget> createRenderTarget(const RenderTargetConfig &config);
2026-02-11 19:40:26 +08:00
/**
* @brief
*/
RenderTarget *getDefaultRenderTarget() const {
return defaultRenderTarget_.get();
}
/**
* @brief
*/
void resize(int width, int height);
/**
* @brief
*/
bool isInitialized() const { return initialized_; }
private:
RenderTargetManager() = default;
~RenderTargetManager() = default;
RenderTargetManager(const RenderTargetManager &) = delete;
RenderTargetManager &operator=(const RenderTargetManager &) = delete;
IntrusivePtr<RenderTarget> defaultRenderTarget_;
std::vector<IntrusivePtr<RenderTarget>> renderTargets_;
2026-02-11 19:40:26 +08:00
bool initialized_ = false;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::getInstance()
#define E2D_RENDER_TARGET_MANAGER() \
::extra2d::RenderTargetManager::getInstance()
} // namespace extra2d