渲染后端加入

This commit is contained in:
2026-02-17 13:28:38 +08:00
commit a5379b3816
49 changed files with 44512 additions and 0 deletions

View File

@@ -0,0 +1,216 @@
#pragma once
#include <fostbite2D/module/module.h>
#include <fostbite2D/config/app_config.h>
#include <fostbite2D/platform/window.h>
#include <string>
namespace frostbite2D {
/**
* @brief 应用程序类
*/
class Application {
public:
/**
* @brief 获取单例实例
* @return 应用程序实例引用
*/
static Application& get();
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
/**
* @brief 添加模块
* @param m 模块引用
*/
void use(Module& m);
/**
* @brief 批量添加模块
* @param modules 模块指针列表
*/
void use(std::initializer_list<Module*> modules);
/**
* @brief 使用默认配置初始化
* @return 初始化成功返回 true
*/
bool init();
/**
* @brief 使用指定配置初始化
* @param config 应用配置
* @return 初始化成功返回 true
*/
bool init(const AppConfig& config);
/**
* @brief 使用配置文件初始化
* @param configPath 配置文件路径
* @return 初始化成功返回 true
*/
bool init(const std::string& configPath);
/**
* @brief 关闭应用程序
*/
void shutdown();
/**
* @brief 运行主循环
*/
void run();
/**
* @brief 请求退出
*/
void quit();
/**
* @brief 暂停应用程序
*/
void pause();
/**
* @brief 恢复应用程序
*/
void resume();
/**
* @brief 检查是否暂停
* @return 暂停状态返回 true
*/
bool isPaused() const { return paused_; }
/**
* @brief 检查是否运行中
* @return 运行中返回 true
*/
bool isRunning() const { return running_; }
// /**
// * @brief 获取窗口
// * @return 窗口引用
// */
// IWindow& window() { return *window_; }
// /**
// * @brief 获取渲染器
// * @return 渲染器引用
// */
// RenderBackend& renderer();
// /**
// * @brief 获取场景服务
// * @return 场景服务共享指针
// */
// SharedPtr<class ISceneService> scenes();
// /**
// * @brief 获取计时器服务
// * @return 计时器服务共享指针
// */
// SharedPtr<class ITimerService> timers();
// /**
// * @brief 获取事件服务
// * @return 事件服务共享指针
// */
// SharedPtr<class IEventService> events();
// /**
// * @brief 获取相机服务
// * @return 相机服务共享指针
// */
// SharedPtr<class ICameraService> camera();
// /**
// * @brief 进入场景
// * @param scene 场景指针
// */
// void enterScene(Ptr<class Scene> scene);
/**
* @brief 获取帧间隔时间
* @return 帧间隔时间(秒)
*/
float deltaTime() const { return deltaTime_; }
/**
* @brief 获取总运行时间
* @return 总运行时间(秒)
*/
float totalTime() const { return totalTime_; }
/**
* @brief 获取当前帧率
* @return 帧率
*/
int fps() const { return currentFps_; }
/**
* @brief 获取应用配置
* @return 应用配置常量引用
*/
const AppConfig& getConfig() const;
private:
Application() = default;
~Application();
/**
* @brief 初始化核心模块
* @return 初始化成功返回 true
*/
bool initCoreModules();
/**
* @brief 设置所有模块
*/
void setupAllModules();
/**
* @brief 销毁所有模块
*/
void destroyAllModules();
/**
* @brief 注册核心服务
*/
void registerCoreServices();
/**
* @brief 主循环
*/
void mainLoop();
/**
* @brief 更新
*/
void update();
/**
* @brief 渲染
*/
void render();
std::vector<Module*> modules_;
Window* window_ = nullptr;
bool initialized_ = false;
bool running_ = false;
bool paused_ = false;
bool shouldQuit_ = false;
float deltaTime_ = 0.0f;
float totalTime_ = 0.0f;
double lastFrameTime_ = 0.0;
int frameCount_ = 0;
float fpsTimer_ = 0.0f;
int currentFps_ = 0;
};
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <fostbite2D/config/platform_config.h>
#include <fostbite2D/platform/window.h>
#include <string>
namespace frostbite2D {
/**
* @file app_config.h
* @brief 应用级别配置
*
* 本文件仅包含应用级别的配置项,不包含任何模块特定配置。
* 各模块应该在自己的模块文件中定义配置结构,并实现 IModuleConfig 接口。
*
* 模块配置通过 ModuleRegistry 注册,由 ConfigManager 统一管理。
* 这种设计遵循开闭原则,新增模块无需修改引擎核心代码。
*/
/**
* @brief 应用配置结构体
* 仅包含应用级别的配置项,模块配置由各模块自行管理
*/
struct AppConfig {
std::string appName = "frostbite2D App";
std::string appVersion = "1.0.0";
std::string organization = "";
std::string configFile = "config.json";
WindowConfig windowConfig;
PlatformType targetPlatform = PlatformType::Auto;
/**
* @brief 创建默认配置
* @return 默认的应用配置实例
*/
static AppConfig createDefault();
};
} // namespace frostbite2D

View File

@@ -0,0 +1,86 @@
#pragma once
#include <fostbite2D/core/types.h>
namespace frostbite2D {
/**
* @file platform_config.h
* @brief 平台配置接口
*
* 平台配置只提供平台能力信息,不再直接修改应用配置。
* 各模块通过 IModuleConfig::applyPlatformConstraints() 处理平台约束。
*/
/**
* @brief 平台类型枚举
*/
enum class PlatformType {
Auto,
Windows,
Switch,
Linux,
macOS
};
/**
* @brief 平台能力结构
*/
struct PlatformCapabilities {
bool supportsWindowed = true;
bool supportsFullscreen = true;
bool supportsBorderless = true;
bool supportsCursor = true;
bool supportsCursorHide = true;
bool supportsDPIAwareness = true;
bool supportsVSync = true;
bool supportsMultiMonitor = true;
bool supportsClipboard = true;
bool supportsGamepad = true;
bool supportsTouch = false;
bool supportsKeyboard = true;
bool supportsMouse = true;
bool supportsResize = true;
bool supportsHighDPI = true;
int maxTextureSize = 16384;
int preferredScreenWidth = 1920;
int preferredScreenHeight = 1080;
float defaultDPI = 96.0f;
bool hasWindowSupport() const { return supportsWindowed || supportsFullscreen || supportsBorderless; }
bool hasInputSupport() const { return supportsKeyboard || supportsMouse || supportsGamepad || supportsTouch; }
bool isDesktop() const { return supportsKeyboard && supportsMouse && supportsWindowed; }
bool isConsole() const { return !supportsWindowed && supportsGamepad; }
};
/**
* @brief 平台配置抽象接口
*/
class PlatformConfig {
public:
virtual ~PlatformConfig() = default;
virtual PlatformType platformType() const = 0;
virtual const char* platformName() const = 0;
virtual const PlatformCapabilities& capabilities() const = 0;
virtual int getRecommendedWidth() const = 0;
virtual int getRecommendedHeight() const = 0;
virtual bool isResolutionSupported(int width, int height) const = 0;
};
/**
* @brief 创建平台配置实例
* @param type 平台类型,默认为 Auto自动检测
* @return 平台配置的智能指针
*/
UniquePtr<PlatformConfig> createPlatformConfig(PlatformType type = PlatformType::Auto);
/**
* @brief 获取平台类型名称
* @param type 平台类型枚举值
* @return 平台名称字符串
*/
const char* getPlatformTypeName(PlatformType type);
}

View File

@@ -0,0 +1,156 @@
#pragma once
#include <Fostbite2D/core/types.h>
#include <algorithm>
#include <glm/vec4.hpp>
namespace frostbite2D {
/// RGB 颜色(字节,每通道 0-255
struct Color3B {
uint8_t r = 255;
uint8_t g = 255;
uint8_t b = 255;
constexpr Color3B() = default;
constexpr Color3B(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}
constexpr bool operator==(const Color3B &other) const {
return r == other.r && g == other.g && b == other.b;
}
constexpr bool operator!=(const Color3B &other) const {
return !(*this == other);
}
Color3B operator+(const Color3B &other) const {
return Color3B(
static_cast<uint8_t>(std::min(255, static_cast<int>(r) + other.r)),
static_cast<uint8_t>(std::min(255, static_cast<int>(g) + other.g)),
static_cast<uint8_t>(std::min(255, static_cast<int>(b) + other.b)));
}
Color3B operator-(const Color3B &other) const {
return Color3B(
static_cast<uint8_t>(std::max(0, static_cast<int>(r) - other.r)),
static_cast<uint8_t>(std::max(0, static_cast<int>(g) - other.g)),
static_cast<uint8_t>(std::max(0, static_cast<int>(b) - other.b)));
}
};
/// RGBA 颜色(浮点数,每通道 0.0 - 1.0
struct Color {
float r = 0.0f;
float g = 0.0f;
float b = 0.0f;
float a = 1.0f;
constexpr Color() = default;
constexpr Color(float r, float g, float b, float a = 1.0f)
: r(r), g(g), b(b), a(a) {}
/// 从 0xRRGGBB 整数构造
constexpr explicit Color(uint32_t rgb, float a = 1.0f)
: r(static_cast<float>((rgb >> 16) & 0xFF) / 255.0f),
g(static_cast<float>((rgb >> 8) & 0xFF) / 255.0f),
b(static_cast<float>((rgb) & 0xFF) / 255.0f), a(a) {}
/// 从 0-255 整数构造
static constexpr Color fromRGBA(uint8_t r, uint8_t g, uint8_t b,
uint8_t a = 255) {
return Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
}
/// 转换为 glm::vec4
glm::vec4 toVec4() const { return {r, g, b, a}; }
/// 线性插值
static Color lerp(const Color &a, const Color &b, float t) {
t = std::clamp(t, 0.0f, 1.0f);
return Color(a.r + (b.r - a.r) * t, a.g + (b.g - a.g) * t,
a.b + (b.b - a.b) * t, a.a + (b.a - a.a) * t);
}
bool operator==(const Color &other) const {
return r == other.r && g == other.g && b == other.b && a == other.a;
}
bool operator!=(const Color &other) const { return !(*this == other); }
// 算术运算符
Color operator+(const Color &other) const {
return Color(r + other.r, g + other.g, b + other.b, a + other.a);
}
Color operator-(const Color &other) const {
return Color(r - other.r, g - other.g, b - other.b, a - other.a);
}
Color operator*(float scalar) const {
return Color(r * scalar, g * scalar, b * scalar, a * scalar);
}
Color operator/(float scalar) const {
return Color(r / scalar, g / scalar, b / scalar, a / scalar);
}
Color &operator+=(const Color &other) {
r += other.r;
g += other.g;
b += other.b;
a += other.a;
return *this;
}
Color &operator-=(const Color &other) {
r -= other.r;
g -= other.g;
b -= other.b;
a -= other.a;
return *this;
}
Color &operator*=(float scalar) {
r *= scalar;
g *= scalar;
b *= scalar;
a *= scalar;
return *this;
}
Color &operator/=(float scalar) {
r /= scalar;
g /= scalar;
b /= scalar;
a /= scalar;
return *this;
}
};
// 命名颜色常量
namespace Colors {
inline constexpr Color White{1.0f, 1.0f, 1.0f, 1.0f};
inline constexpr Color Black{0.0f, 0.0f, 0.0f, 1.0f};
inline constexpr Color Red{1.0f, 0.0f, 0.0f, 1.0f};
inline constexpr Color Green{0.0f, 1.0f, 0.0f, 1.0f};
inline constexpr Color Blue{0.0f, 0.0f, 1.0f, 1.0f};
inline constexpr Color Yellow{1.0f, 1.0f, 0.0f, 1.0f};
inline constexpr Color Cyan{0.0f, 1.0f, 1.0f, 1.0f};
inline constexpr Color Magenta{1.0f, 0.0f, 1.0f, 1.0f};
inline constexpr Color Orange{1.0f, 0.647f, 0.0f, 1.0f};
inline constexpr Color Purple{0.502f, 0.0f, 0.502f, 1.0f};
inline constexpr Color Pink{1.0f, 0.753f, 0.796f, 1.0f};
inline constexpr Color Gray{0.502f, 0.502f, 0.502f, 1.0f};
inline constexpr Color LightGray{0.827f, 0.827f, 0.827f, 1.0f};
inline constexpr Color DarkGray{0.412f, 0.412f, 0.412f, 1.0f};
inline constexpr Color Brown{0.647f, 0.165f, 0.165f, 1.0f};
inline constexpr Color Gold{1.0f, 0.843f, 0.0f, 1.0f};
inline constexpr Color Silver{0.753f, 0.753f, 0.753f, 1.0f};
inline constexpr Color SkyBlue{0.529f, 0.808f, 0.922f, 1.0f};
inline constexpr Color LimeGreen{0.196f, 0.804f, 0.196f, 1.0f};
inline constexpr Color Coral{1.0f, 0.498f, 0.314f, 1.0f};
inline constexpr Color Transparent{0.0f, 0.0f, 0.0f, 0.0f};
} // namespace Colors
} // namespace frostbite2D

View File

@@ -0,0 +1,552 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <fostbite2D/core/types.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
namespace frostbite2D {
// ---------------------------------------------------------------------------
// 常量
// ---------------------------------------------------------------------------
constexpr float PI_F = 3.14159265358979323846f;
constexpr float DEG_TO_RAD = PI_F / 180.0f;
constexpr float RAD_TO_DEG = 180.0f / PI_F;
// ---------------------------------------------------------------------------
// 2D 向量
// ---------------------------------------------------------------------------
struct Vec2 {
float x = 0.0f;
float y = 0.0f;
constexpr Vec2() = default;
constexpr Vec2(float x, float y) : x(x), y(y) {}
explicit Vec2(const glm::vec2 &v) : x(v.x), y(v.y) {}
glm::vec2 toGlm() const { return {x, y}; }
static Vec2 fromGlm(const glm::vec2 &v) { return {v.x, v.y}; }
// 基础运算
Vec2 operator+(const Vec2 &v) const { return {x + v.x, y + v.y}; }
Vec2 operator-(const Vec2 &v) const { return {x - v.x, y - v.y}; }
Vec2 operator*(float s) const { return {x * s, y * s}; }
Vec2 operator/(float s) const { return {x / s, y / s}; }
Vec2 operator-() const { return {-x, -y}; }
Vec2 &operator+=(const Vec2 &v) {
x += v.x;
y += v.y;
return *this;
}
Vec2 &operator-=(const Vec2 &v) {
x -= v.x;
y -= v.y;
return *this;
}
Vec2 &operator*=(float s) {
x *= s;
y *= s;
return *this;
}
Vec2 &operator/=(float s) {
x /= s;
y /= s;
return *this;
}
bool operator==(const Vec2 &v) const { return x == v.x && y == v.y; }
bool operator!=(const Vec2 &v) const { return !(*this == v); }
// 向量运算
float length() const { return std::sqrt(x * x + y * y); }
float lengthSquared() const { return x * x + y * y; }
Vec2 normalized() const {
float len = length();
if (len > 0.0f)
return {x / len, y / len};
return {0.0f, 0.0f};
}
float dot(const Vec2 &v) const { return x * v.x + y * v.y; }
float cross(const Vec2 &v) const { return x * v.y - y * v.x; }
float distance(const Vec2 &v) const { return (*this - v).length(); }
float angle() const { return std::atan2(y, x) * RAD_TO_DEG; }
static Vec2 lerp(const Vec2 &a, const Vec2 &b, float t) {
return a + (b - a) * t;
}
static constexpr Vec2 Zero() { return {0.0f, 0.0f}; }
static constexpr Vec2 One() { return {1.0f, 1.0f}; }
static constexpr Vec2 UnitX() { return {1.0f, 0.0f}; }
static constexpr Vec2 UnitY() { return {0.0f, 1.0f}; }
};
inline Vec2 operator*(float s, const Vec2 &v) { return v * s; }
using Point = Vec2;
// ---------------------------------------------------------------------------
// 3D 向量 (用于3D动作)
// ---------------------------------------------------------------------------
struct Vec3 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
constexpr Vec3() = default;
constexpr Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
explicit Vec3(const glm::vec3 &v) : x(v.x), y(v.y), z(v.z) {}
glm::vec3 toGlm() const { return {x, y, z}; }
static Vec3 fromGlm(const glm::vec3 &v) { return {v.x, v.y, v.z}; }
Vec3 operator+(const Vec3 &v) const { return {x + v.x, y + v.y, z + v.z}; }
Vec3 operator-(const Vec3 &v) const { return {x - v.x, y - v.y, z - v.z}; }
Vec3 operator*(float s) const { return {x * s, y * s, z * s}; }
Vec3 operator/(float s) const { return {x / s, y / s, z / s}; }
Vec3 operator-() const { return {-x, -y, -z}; }
Vec3 &operator+=(const Vec3 &v) {
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vec3 &operator-=(const Vec3 &v) {
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vec3 &operator*=(float s) {
x *= s;
y *= s;
z *= s;
return *this;
}
Vec3 &operator/=(float s) {
x /= s;
y /= s;
z /= s;
return *this;
}
bool operator==(const Vec3 &v) const {
return x == v.x && y == v.y && z == v.z;
}
bool operator!=(const Vec3 &v) const { return !(*this == v); }
float length() const { return std::sqrt(x * x + y * y + z * z); }
float lengthSquared() const { return x * x + y * y + z * z; }
Vec3 normalized() const {
float len = length();
if (len > 0.0f)
return {x / len, y / len, z / len};
return {0.0f, 0.0f, 0.0f};
}
float dot(const Vec3 &v) const { return x * v.x + y * v.y + z * v.z; }
static Vec3 lerp(const Vec3 &a, const Vec3 &b, float t) {
return a + (b - a) * t;
}
static constexpr Vec3 Zero() { return {0.0f, 0.0f, 0.0f}; }
static constexpr Vec3 One() { return {1.0f, 1.0f, 1.0f}; }
};
inline Vec3 operator*(float s, const Vec3 &v) { return v * s; }
// ---------------------------------------------------------------------------
// 2D 尺寸
// ---------------------------------------------------------------------------
struct Size {
float width = 0.0f;
float height = 0.0f;
constexpr Size() = default;
constexpr Size(float w, float h) : width(w), height(h) {}
bool operator==(const Size &s) const {
return width == s.width && height == s.height;
}
bool operator!=(const Size &s) const { return !(*this == s); }
float area() const { return width * height; }
bool empty() const { return width <= 0.0f || height <= 0.0f; }
static constexpr Size Zero() { return {0.0f, 0.0f}; }
};
// ---------------------------------------------------------------------------
// 2D 矩形
// ---------------------------------------------------------------------------
struct Rect {
Point origin;
Size size;
constexpr Rect() = default;
constexpr Rect(float x, float y, float w, float h)
: origin(x, y), size(w, h) {}
constexpr Rect(const Point &o, const Size &s) : origin(o), size(s) {}
float left() const { return origin.x; }
float top() const { return origin.y; }
float right() const { return origin.x + size.width; }
float bottom() const { return origin.y + size.height; }
float width() const { return size.width; }
float height() const { return size.height; }
Point center() const {
return {origin.x + size.width * 0.5f, origin.y + size.height * 0.5f};
}
bool empty() const { return size.empty(); }
bool containsPoint(const Point &p) const {
return p.x >= left() && p.x <= right() && p.y >= top() && p.y <= bottom();
}
bool contains(const Rect &r) const {
return r.left() >= left() && r.right() <= right() && r.top() >= top() &&
r.bottom() <= bottom();
}
bool intersects(const Rect &r) const {
return !(left() > r.right() || right() < r.left() || top() > r.bottom() ||
bottom() < r.top());
}
Rect intersection(const Rect &r) const {
float l = std::max(left(), r.left());
float t = std::max(top(), r.top());
float ri = std::min(right(), r.right());
float b = std::min(bottom(), r.bottom());
if (l < ri && t < b)
return {l, t, ri - l, b - t};
return {};
}
Rect unionWith(const Rect &r) const {
if (empty())
return r;
if (r.empty())
return *this;
float l = std::min(left(), r.left());
float t = std::min(top(), r.top());
float ri = std::max(right(), r.right());
float b = std::max(bottom(), r.bottom());
return {l, t, ri - l, b - t};
}
bool operator==(const Rect &r) const {
return origin == r.origin && size == r.size;
}
bool operator!=(const Rect &r) const { return !(*this == r); }
static constexpr Rect Zero() { return {0, 0, 0, 0}; }
};
// ---------------------------------------------------------------------------
// 2D 变换矩阵(基于 glm::mat4兼容 OpenGL
// ---------------------------------------------------------------------------
struct Transform2D {
glm::mat4 matrix{1.0f}; // 单位矩阵
Transform2D() = default;
explicit Transform2D(const glm::mat4 &m) : matrix(m) {}
static Transform2D identity() { return Transform2D{}; }
static Transform2D translation(float x, float y) {
Transform2D t;
t.matrix = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, 0.0f));
return t;
}
static Transform2D translation(const Vec2 &v) {
return translation(v.x, v.y);
}
static Transform2D rotation(float degrees) {
Transform2D t;
t.matrix = glm::rotate(glm::mat4(1.0f), degrees * DEG_TO_RAD,
glm::vec3(0.0f, 0.0f, 1.0f));
return t;
}
static Transform2D scaling(float sx, float sy) {
Transform2D t;
t.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(sx, sy, 1.0f));
return t;
}
static Transform2D scaling(float s) { return scaling(s, s); }
static Transform2D skewing(float skewX, float skewY) {
Transform2D t;
t.matrix = glm::mat4(1.0f);
t.matrix[1][0] = std::tan(skewX * DEG_TO_RAD);
t.matrix[0][1] = std::tan(skewY * DEG_TO_RAD);
return t;
}
Transform2D operator*(const Transform2D &other) const {
return Transform2D(matrix * other.matrix);
}
Transform2D &operator*=(const Transform2D &other) {
matrix *= other.matrix;
return *this;
}
Vec2 transformPoint(const Vec2 &p) const {
glm::vec4 result = matrix * glm::vec4(p.x, p.y, 0.0f, 1.0f);
return {result.x, result.y};
}
Transform2D inverse() const { return Transform2D(glm::inverse(matrix)); }
};
// ---------------------------------------------------------------------------
// 数学工具函数
// ---------------------------------------------------------------------------
namespace math {
inline float clamp(float value, float minVal, float maxVal) {
return std::clamp(value, minVal, maxVal);
}
inline float lerp(float a, float b, float t) { return a + (b - a) * t; }
inline float degrees(float radians) { return radians * RAD_TO_DEG; }
inline float radians(float degrees) { return degrees * DEG_TO_RAD; }
// ---------------------------------------------------------------------------
// 角度工具函数
// ---------------------------------------------------------------------------
/**
* @brief 规范化角度到 [0, 360) 范围
* @param degrees 输入角度(度数)
* @return 规范化后的角度,范围 [0, 360)
*/
inline float normalizeAngle360(float degrees) {
degrees = std::fmod(degrees, 360.0f);
if (degrees < 0.0f) {
degrees += 360.0f;
}
return degrees;
}
/**
* @brief 规范化角度到 [-180, 180) 范围
* @param degrees 输入角度(度数)
* @return 规范化后的角度,范围 [-180, 180)
*/
inline float normalizeAngle180(float degrees) {
degrees = std::fmod(degrees + 180.0f, 360.0f);
if (degrees < 0.0f) {
degrees += 360.0f;
}
return degrees - 180.0f;
}
/**
* @brief 计算两个角度之间的最短差值
* @param from 起始角度(度数)
* @param to 目标角度(度数)
* @return 从 from 到 to 的最短角度差,范围 [-180, 180]
*/
inline float angleDifference(float from, float to) {
float diff = normalizeAngle360(to - from);
if (diff > 180.0f) {
diff -= 360.0f;
}
return diff;
}
/**
* @brief 线性插值角度
* @param from 起始角度(度数)
* @param to 目标角度(度数)
* @param t 插值因子 [0, 1]
* @return 插值后的角度
*/
inline float lerpAngle(float from, float to, float t) {
return from + angleDifference(from, to) * t;
}
// ---------------------------------------------------------------------------
// 向量工具函数
// ---------------------------------------------------------------------------
/**
* @brief 计算方向向量(从 from 指向 to 的单位向量)
* @param from 起始点
* @param to 目标点
* @return 归一化的方向向量
*/
inline Vec2 direction(const Vec2 &from, const Vec2 &to) {
return (to - from).normalized();
}
/**
* @brief 计算两点之间的角度
* @param from 起始点
* @param to 目标点
* @return 角度(度数),范围 [-180, 180]
*/
inline float angleBetween(const Vec2 &from, const Vec2 &to) {
Vec2 dir = to - from;
return std::atan2(dir.y, dir.x) * RAD_TO_DEG;
}
/**
* @brief 根据角度创建方向向量
* @param degrees 角度度数0度指向右方逆时针为正
* @return 单位方向向量
*/
inline Vec2 angleToVector(float degrees) {
float rad = degrees * DEG_TO_RAD;
return {std::cos(rad), std::sin(rad)};
}
/**
* @brief 将向量旋转指定角度
* @param v 原始向量
* @param degrees 旋转角度(度数),正值为逆时针旋转
* @return 旋转后的向量
*/
inline Vec2 rotateVector(const Vec2 &v, float degrees) {
float rad = degrees * DEG_TO_RAD;
float cosA = std::cos(rad);
float sinA = std::sin(rad);
return {v.x * cosA - v.y * sinA, v.x * sinA + v.y * cosA};
}
// ---------------------------------------------------------------------------
// 坐标系转换工具
// ---------------------------------------------------------------------------
/**
* @brief Y轴向上坐标转Y轴向下坐标
* @param pos Y轴向上坐标系中的位置
* @param height 画布/屏幕高度
* @return Y轴向下坐标系中的位置
*/
inline Vec2 flipY(const Vec2 &pos, float height) {
return {pos.x, height - pos.y};
}
/**
* @brief Y轴向下坐标转Y轴向上坐标
* @param pos Y轴向下坐标系中的位置
* @param height 画布/屏幕高度
* @return Y轴向上坐标系中的位置
*/
inline Vec2 unflipY(const Vec2 &pos, float height) {
return {pos.x, height - pos.y};
}
// ---------------------------------------------------------------------------
// 矩阵工具函数
// ---------------------------------------------------------------------------
/**
* @brief 从变换矩阵提取位置
* @param matrix 4x4变换矩阵
* @return 提取的位置向量
*/
inline Vec2 extractPosition(const glm::mat4 &matrix) {
return {matrix[3][0], matrix[3][1]};
}
/**
* @brief 从变换矩阵提取缩放
* @param matrix 4x4变换矩阵
* @return 提取的缩放向量
*/
inline Vec2 extractScale(const glm::mat4 &matrix) {
float scaleX =
std::sqrt(matrix[0][0] * matrix[0][0] + matrix[0][1] * matrix[0][1]);
float scaleY =
std::sqrt(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1]);
return {scaleX, scaleY};
}
/**
* @brief 从变换矩阵提取旋转角度
* @param matrix 4x4变换矩阵
* @return 提取的旋转角度(度数)
*/
inline float extractRotation(const glm::mat4 &matrix) {
return std::atan2(matrix[0][1], matrix[0][0]) * RAD_TO_DEG;
}
// ---------------------------------------------------------------------------
// 碰撞检测工具
// ---------------------------------------------------------------------------
/**
* @brief 判断点是否在矩形内
* @param point 要检测的点
* @param rect 矩形区域
* @return 如果点在矩形内返回 true否则返回 false
*/
inline bool pointInRect(const Vec2 &point, const Rect &rect) {
return point.x >= rect.left() && point.x <= rect.right() &&
point.y >= rect.top() && point.y <= rect.bottom();
}
/**
* @brief 判断点是否在圆内
* @param point 要检测的点
* @param center 圆心
* @param radius 圆的半径
* @return 如果点在圆内返回 true否则返回 false
*/
inline bool pointInCircle(const Vec2 &point, const Vec2 &center, float radius) {
float dx = point.x - center.x;
float dy = point.y - center.y;
return (dx * dx + dy * dy) <= (radius * radius);
}
/**
* @brief 判断两个矩形是否相交
* @param a 第一个矩形
* @param b 第二个矩形
* @return 如果矩形相交返回 true否则返回 false
*/
inline bool rectsIntersect(const Rect &a, const Rect &b) {
return a.intersects(b);
}
/**
* @brief 判断两个圆是否相交
* @param center1 第一个圆的圆心
* @param radius1 第一个圆的半径
* @param center2 第二个圆的圆心
* @param radius2 第二个圆的半径
* @return 如果圆相交返回 true否则返回 false
*/
inline bool circlesIntersect(const Vec2 &center1, float radius1,
const Vec2 &center2, float radius2) {
float dx = center2.x - center1.x;
float dy = center2.y - center1.y;
float distSq = dx * dx + dy * dy;
float radiusSum = radius1 + radius2;
return distSq <= (radiusSum * radiusSum);
}
} // namespace math
} // namespace frostbite2D

View File

@@ -0,0 +1,58 @@
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
namespace frostbite2D {
// ---------------------------------------------------------------------------
// 宏定义
// ---------------------------------------------------------------------------
#define E2D_CONCAT_IMPL(a, b) a##b
#define E2D_CONCAT(a, b) E2D_CONCAT_IMPL(a, b)
// ---------------------------------------------------------------------------
// 智能指针别名
// ---------------------------------------------------------------------------
template <typename T> using Ptr = std::shared_ptr<T>;
template <typename T> using SharedPtr = std::shared_ptr<T>;
template <typename T> using UniquePtr = std::unique_ptr<T>;
template <typename T> using WeakPtr = std::weak_ptr<T>;
/// 创建 shared_ptr 的便捷函数
template <typename T, typename... Args> inline Ptr<T> makePtr(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
template <typename T, typename... Args>
inline SharedPtr<T> makeShared(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
/// 创建 unique_ptr 的便捷函数
template <typename T, typename... Args>
inline UniquePtr<T> makeUnique(Args &&...args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
// ---------------------------------------------------------------------------
// 函数别名
// ---------------------------------------------------------------------------
template <typename Sig> using Function = std::function<Sig>;
// ---------------------------------------------------------------------------
// 基础类型别名
// ---------------------------------------------------------------------------
using int8 = std::int8_t;
using int16 = std::int16_t;
using int32 = std::int32_t;
using int64 = std::int64_t;
using uint8 = std::uint8_t;
using uint16 = std::uint16_t;
using uint32 = std::uint32_t;
using uint64 = std::uint64_t;
} // namespace frostbite2D

View File

@@ -0,0 +1,93 @@
#pragma once
namespace frostbite2D {
/**
* @brief 模块基类
* 所有模块只需继承此类,实现需要的生命周期方法
*/
class Module {
public:
/**
* @brief 虚析构函数
*/
virtual ~Module() = default;
/**
* @brief 设置模块(初始化)
* 在 Application::run() 开始前调用
*/
virtual void setupModule() {}
/**
* @brief 销毁模块
* 在 Application 关闭时调用
*/
virtual void destroyModule() {}
/**
* @brief 更新时
* 每帧调用
* @param ctx 更新上下文
*/
virtual void onUpdate() { }
/**
* @brief 渲染前
* 在渲染开始前调用
* @param ctx 渲染上下文
*/
virtual void beforeRender() { }
/**
* @brief 渲染时
* 在渲染阶段调用
* @param ctx 渲染上下文
*/
virtual void onRender() {}
/**
* @brief 渲染后
* 在渲染完成后调用
* @param ctx 渲染上下文
*/
virtual void afterRender() { }
/**
* @brief 事件处理
* 处理系统事件
* @param ctx 事件上下文
*/
virtual void handleEvent() { }
/**
* @brief 获取模块名称
* @return 模块名称字符串
*/
virtual const char *getName() const = 0;
/**
* @brief 获取模块优先级
* 数值越小越先执行
* @return 优先级值
*/
virtual int getPriority() const { return 0; }
/**
* @brief 检查模块是否已初始化
* @return 已初始化返回 true
*/
bool isInitialized() const { return initialized_; }
protected:
friend class Application;
/**
* @brief 设置初始化状态
* @param initialized 初始化状态
*/
void setInitialized(bool initialized) { initialized_ = initialized; }
bool initialized_ = false;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,272 @@
#pragma once
#include <SDL2/SDL.h>
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
#include <functional>
#include <string>
namespace frostbite2D {
/**
* \~chinese
* @brief 鼠标指针类型
*/
enum class CursorType {
Arrow, ///< 指针
TextInput, ///< 文本
Hand, ///< 手
SizeAll, ///< 指向四个方向的箭头
SizeWE, ///< 指向左右方向的箭头
SizeNS, ///< 指向上下方向的箭头
SizeNESW, ///< 指向左下到右上方向的箭头
SizeNWSE, ///< 指向左上到右下方向的箭头
No, ///< 禁止
};
/**
* \~chinese
* @brief 分辨率
*/
struct Resolution {
uint32_t width = 0; ///< 分辨率宽度
uint32_t height = 0; ///< 分辨率高度
uint32_t refresh_rate = 0; ///< 刷新率
Resolution() = default;
Resolution(uint32_t width, uint32_t height, uint32_t refresh_rate)
: width(width), height(height), refresh_rate(refresh_rate) {}
};
/**
* \~chinese
* @brief 图标
*/
struct Icon {
Icon() = default;
Icon(std::string file_path) : file_path(file_path) {}
std::string file_path; ///< 文件路径
#if defined(_WIN32)
uint32_t resource_id = 0; ///< 资源ID仅在windows上生效
Icon(uint32_t resource_id) : resource_id(resource_id) {}
#endif
};
/**
* \~chinese
* @brief 窗口设置
*/
struct WindowConfig {
uint32_t width = 640; ///< 窗口宽度
uint32_t height = 480; ///< 窗口高度
std::string title = "fostbite2D Game"; ///< 窗口标题
Icon icon; ///< 窗口图标
bool resizable = false; ///< 窗口大小可调整
bool fullscreen = false; ///< 窗口全屏
bool borderless = false; ///< 无边框窗口
bool decorated = true; ///< 窗口装饰
int multisamples = 0; ///< 多重采样数
bool centered = true; ///< 窗口是否居中
bool vsync = true; ///< 是否启用垂直同步
bool showCursor = true; ///< 是否显示光标
};
class Window {
public:
Window() = default;
virtual ~Window() = default;
/**
* @brief 创建窗口
* @param cfg 窗口配置
* @return 创建是否成功
*/
virtual bool create(const WindowConfig &cfg);
/**
* @brief 销毁窗口
*/
virtual void destroy();
/**
* @brief 轮询事件
*/
virtual void poll();
/**
* @brief 交换缓冲区
*/
virtual void swap();
/**
* @brief 设置窗口关闭标志
*/
virtual void close();
/**
* @brief 设置窗口标题
*/
virtual void setTitle(const std::string &title);
/**
* @brief 设置窗口大小
*/
virtual void setSize(int w, int h);
/**
* @brief 设置窗口位置
*/
virtual void setPos(int x, int y);
/**
* @brief 设置全屏模式
*/
virtual void setFullscreen(bool fs);
/**
* @brief 设置垂直同步
*/
virtual void setVSync(bool vsync);
/**
* @brief 设置窗口可见性
*/
virtual void setVisible(bool visible);
/**
* @brief 获取窗口宽度
*/
virtual int width() const;
/**
* @brief 获取窗口高度
*/
virtual int height() const;
/**
* @brief 获取窗口大小
*/
virtual Size size() const;
/**
* @brief 获取窗口位置
*/
virtual Vec2 pos() const;
/**
* @brief 是否全屏
*/
virtual bool fullscreen() const;
/**
* @brief 是否启用垂直同步
*/
virtual bool vsync() const;
/**
* @brief 窗口是否获得焦点
*/
virtual bool focused() const;
/**
* @brief 窗口是否最小化
*/
virtual bool minimized() const;
/**
* @brief 获取内容缩放X
*/
virtual float scaleX() const;
/**
* @brief 获取内容缩放Y
*/
virtual float scaleY() const;
/**
* @brief 设置光标形状
*/
virtual void setCursor(CursorType cursor);
/**
* @brief 显示/隐藏光标
*/
virtual void showCursor(bool show);
/**
* @brief 锁定/解锁光标
*/
virtual void lockCursor(bool lock);
/**
* @brief 窗口大小改变回调
*/
using ResizeCb = std::function<void(int, int)>;
/**
* @brief 窗口关闭回调
*/
using CloseCb = std::function<void()>;
/**
* @brief 窗口焦点改变回调
*/
using FocusCb = std::function<void(bool)>;
/**
* @brief 设置大小改变回调
*/
virtual void onResize(ResizeCb cb);
/**
* @brief 设置关闭回调
*/
virtual void onClose(CloseCb cb);
/**
* @brief 设置焦点改变回调
*/
virtual void onFocus(FocusCb cb);
/**
* @brief 获取原生窗口句柄
*/
virtual void *native() const;
/**
* @brief 获取 SDL 窗口句柄
*/
SDL_Window *sdlWindow() const { return sdlWindow_; }
/**
* @brief 获取 OpenGL 上下文
*/
SDL_GLContext glContext() const { return glContext_; }
private:
SDL_Window *sdlWindow_ = nullptr;
SDL_GLContext glContext_ = nullptr;
int width_ = 1280;
int height_ = 720;
bool fullscreen_ = false;
bool vsync_ = true;
bool focused_ = true;
bool minimized_ = false;
bool shouldClose_ = false;
float scaleX_ = 1.0f;
float scaleY_ = 1.0f;
bool cursorVisible_ = true;
bool cursorLocked_ = false;
ResizeCb resizeCb_;
CloseCb closeCb_;
FocusCb focusCb_;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,92 @@
#pragma once
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
#include <glm/mat4x4.hpp>
namespace frostbite2D {
// ============================================================================
// 2D 正交相机 - 简化版本,无服务和模块依赖
// ============================================================================
class Camera {
public:
Camera();
Camera(float left, float right, float bottom, float top);
Camera(const Size &viewport);
~Camera() = default;
// ------------------------------------------------------------------------
// 位置和变换
// ------------------------------------------------------------------------
void setPosition(const Vec2 &position);
void setPosition(float x, float y);
Vec2 getPosition() const { return position_; }
void setRotation(float degrees);
float getRotation() const { return rotation_; }
void setZoom(float zoom);
float getZoom() const { return zoom_; }
// ------------------------------------------------------------------------
// 视口设置
// ------------------------------------------------------------------------
void setViewport(float left, float right, float bottom, float top);
void setViewport(const Rect &rect);
Rect getViewport() const;
// ------------------------------------------------------------------------
// 矩阵获取
// ------------------------------------------------------------------------
glm::mat4 getViewMatrix() const;
glm::mat4 getProjectionMatrix() const;
glm::mat4 getViewProjectionMatrix() const;
// ------------------------------------------------------------------------
// 坐标转换
// ------------------------------------------------------------------------
Vec2 screenToWorld(const Vec2 &screenPos) const;
Vec2 worldToScreen(const Vec2 &worldPos) const;
Vec2 screenToWorld(float x, float y) const;
Vec2 worldToScreen(float x, float y) const;
// ------------------------------------------------------------------------
// 移动相机
// ------------------------------------------------------------------------
void move(const Vec2 &offset);
void move(float x, float y);
// ------------------------------------------------------------------------
// 边界限制
// ------------------------------------------------------------------------
void setBounds(const Rect &bounds);
void clearBounds();
void clampToBounds();
// ------------------------------------------------------------------------
// 快捷方法:看向某点
// ------------------------------------------------------------------------
void lookAt(const Vec2 &target);
private:
Vec2 position_ = Vec2::Zero();
float rotation_ = 0.0f;
float zoom_ = 1.0f;
float left_ = -1.0f;
float right_ = 1.0f;
float bottom_ = -1.0f;
float top_ = 1.0f;
Rect bounds_;
bool hasBounds_ = false;
mutable glm::mat4 viewMatrix_;
mutable glm::mat4 projMatrix_;
mutable glm::mat4 vpMatrix_;
mutable bool viewDirty_ = true;
mutable bool projDirty_ = true;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,87 @@
#pragma once
#include <fostbite2D/core/color.h>
#include <fostbite2D/core/types.h>
#include <fostbite2D/core/math_types.h>
#include <string>
namespace frostbite2D {
// ============================================================================
// 字形信息
// ============================================================================
struct Glyph {
float u0, v0; // 纹理坐标左下角
float u1, v1; // 纹理坐标右上角
float width; // 字形宽度(像素)
float height; // 字形高度(像素)
float bearingX; // 水平偏移
float bearingY; // 垂直偏移
float advance; // 前进距离
};
// ============================================================================
// 字体图集接口
// ============================================================================
class FontAtlas {
public:
virtual ~FontAtlas() = default;
/**
* @brief 获取字形信息
* @param codepoint Unicode码点
* @return 字形信息指针
*/
virtual const Glyph *getGlyph(char32_t codepoint) const = 0;
/**
* @brief 获取纹理
* @return 纹理指针
*/
virtual class Texture *getTexture() const = 0;
/**
* @brief 获取字体大小
* @return 字体大小(像素)
*/
virtual int getFontSize() const = 0;
/**
* @brief 获取字体上升高度
* @return 上升高度
*/
virtual float getAscent() const = 0;
/**
* @brief 获取字体下降高度
* @return 下降高度
*/
virtual float getDescent() const = 0;
/**
* @brief 获取行间距
* @return 行间距
*/
virtual float getLineGap() const = 0;
/**
* @brief 获取行高
* @return 行高
*/
virtual float getLineHeight() const = 0;
/**
* @brief 计算文字尺寸
* @param text 要测量的文本
* @return 文本的宽度和高度
*/
virtual Vec2 measureText(const std::string &text) = 0;
/**
* @brief 是否支持 SDF 渲染
* @return 支持SDF返回true
*/
virtual bool isSDF() const = 0;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,85 @@
#pragma once
#include <fostbite2D/core/color.h>
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
#include <fostbite2D/render/font.h>
#include <fostbite2D/render/opengl/gl_texture.h>
#include <fostbite2D/render/texture.h>
#include <memory>
#include <stb/stb_rect_pack.h>
#include <stb/stb_truetype.h>
#include <unordered_map>
#include <vector>
namespace frostbite2D {
// ============================================================================
// OpenGL 字体图集实现 - 使用 stb_rect_pack 进行矩形打包
// ============================================================================
class GLFontAtlas : public FontAtlas {
public:
/**
* @brief 构造函数,从字体文件初始化字体图集
* @param filepath 字体文件路径
* @param fontSize 字体大小(像素)
* @param useSDF 是否使用有符号距离场渲染
*/
GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF = false);
/**
* @brief 析构函数
*/
~GLFontAtlas();
// FontAtlas 接口实现
const Glyph *getGlyph(char32_t codepoint) const override;
Texture *getTexture() const override { return texture_.get(); }
int getFontSize() const override { return fontSize_; }
float getAscent() const override { return ascent_; }
float getDescent() const override { return descent_; }
float getLineGap() const override { return lineGap_; }
float getLineHeight() const override { return ascent_ - descent_ + lineGap_; }
Vec2 measureText(const std::string &text) override;
bool isSDF() const override { return useSDF_; }
private:
// 图集配置 - 增大尺寸以支持更多字符
static constexpr int ATLAS_WIDTH = 1024;
static constexpr int ATLAS_HEIGHT = 1024;
static constexpr int PADDING = 2; // 字形之间的间距
int fontSize_;
bool useSDF_;
mutable std::unique_ptr<GLTexture> texture_;
mutable std::unordered_map<char32_t, Glyph> glyphs_;
// stb_rect_pack 上下文
mutable stbrp_context packContext_;
mutable std::vector<stbrp_node> packNodes_;
mutable int currentY_;
std::vector<unsigned char> fontData_;
stbtt_fontinfo fontInfo_;
float scale_;
float ascent_;
float descent_;
float lineGap_;
// 预分配字形位图缓冲区,避免每次动态分配
mutable std::vector<uint8_t> glyphBitmapCache_;
mutable std::vector<uint8_t> glyphRgbaCache_;
/**
* @brief 创建字体图集纹理
*/
void createAtlas();
/**
* @brief 缓存字形到图集
* @param codepoint Unicode码点
*/
void cacheGlyph(char32_t codepoint) const;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,316 @@
#pragma once
#include <fostbite2D/core/color.h>
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
#include <fostbite2D/render/font.h>
#include <fostbite2D/render/opengl/gl_sprite_batch.h>
#include <fostbite2D/render/shader/shader_interface.h>
#include <fostbite2D/render/texture.h>
#include <array>
#include <glad/glad.h>
#include <vector>
struct SDL_Window;
namespace frostbite2D {
// 混合模式枚举
enum class BlendMode { None, Alpha, Additive, Multiply };
// 渲染统计信息
struct RenderStats {
uint32_t drawCalls = 0;
uint32_t triangleCount = 0;
};
// ============================================================================
// OpenGL 渲染器实现
// ============================================================================
class GLRenderer {
public:
GLRenderer();
~GLRenderer();
/**
* @brief 初始化OpenGL渲染器
* @param window SDL窗口指针
* @return 初始化成功返回true失败返回false
*/
bool init(SDL_Window *window);
/**
* @brief 关闭渲染器释放所有GPU资源
*/
void shutdown();
/**
* @brief 开始新帧,清除颜色缓冲区并重置统计信息
* @param clearColor 清屏颜色
*/
void beginFrame(const Color &clearColor);
/**
* @brief 结束当前帧,刷新所有待处理的渲染批次
*/
void endFrame();
/**
* @brief 设置视口区域
* @param x 视口左下角X坐标
* @param y 视口左下角Y坐标
* @param width 视口宽度
* @param height 视口高度
*/
void setViewport(int x, int y, int width, int height);
/**
* @brief 设置垂直同步
* @param enabled true启用垂直同步false禁用
*/
void setVSync(bool enabled);
/**
* @brief 设置混合模式
* @param mode 混合模式枚举值
*/
void setBlendMode(BlendMode mode);
/**
* @brief 设置视图投影矩阵
* @param matrix 4x4视图投影矩阵
*/
void setViewProjection(const glm::mat4 &matrix);
/**
* @brief 压入变换矩阵到变换栈
* @param transform 变换矩阵
*/
void pushTransform(const glm::mat4 &transform);
/**
* @brief 从变换栈弹出顶部变换矩阵
*/
void popTransform();
/**
* @brief 获取当前累积的变换矩阵
* @return 当前变换矩阵,如果栈为空则返回单位矩阵
*/
glm::mat4 getCurrentTransform() const;
/**
* @brief 创建纹理对象
* @param width 纹理宽度
* @param height 纹理高度
* @param pixels 像素数据指针
* @param channels 颜色通道数
* @return 创建的纹理智能指针
*/
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels);
/**
* @brief 从文件加载纹理
* @param filepath 纹理文件路径
* @return 加载的纹理智能指针
*/
Ptr<Texture> loadTexture(const std::string &filepath);
/**
* @brief 开始精灵批处理
*/
void beginSpriteBatch();
/**
* @brief 绘制精灵(带完整参数)
* @param texture 纹理引用
* @param destRect 目标矩形(屏幕坐标)
* @param srcRect 源矩形(纹理坐标)
* @param tint 着色颜色
* @param rotation 旋转角度(度)
* @param anchor 锚点位置0-1范围
*/
void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, float rotation,
const Vec2 &anchor);
/**
* @brief 绘制精灵(简化版本)
* @param texture 纹理引用
* @param position 绘制位置
* @param tint 着色颜色
*/
void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint);
/**
* @brief 结束精灵批处理并提交绘制
*/
void endSpriteBatch();
/**
* @brief 绘制线段
* @param start 起点坐标
* @param end 终点坐标
* @param color 线条颜色
* @param width 线条宽度
*/
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width);
/**
* @brief 绘制矩形边框
* @param rect 矩形区域
* @param color 边框颜色
* @param width 线条宽度
*/
void drawRect(const Rect &rect, const Color &color, float width);
/**
* @brief 填充矩形
* @param rect 矩形区域
* @param color 填充颜色
*/
void fillRect(const Rect &rect, const Color &color);
/**
* @brief 绘制圆形边框
* @param center 圆心坐标
* @param radius 半径
* @param color 边框颜色
* @param segments 分段数
* @param width 线条宽度
*/
void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments, float width);
/**
* @brief 填充圆形
* @param center 圆心坐标
* @param radius 半径
* @param color 填充颜色
* @param segments 分段数
*/
void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments);
/**
* @brief 绘制三角形边框
* @param p1 第一个顶点
* @param p2 第二个顶点
* @param p3 第三个顶点
* @param color 边框颜色
* @param width 线条宽度
*/
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width);
/**
* @brief 填充三角形
* @param p1 第一个顶点
* @param p2 第二个顶点
* @param p3 第三个顶点
* @param color 填充颜色
*/
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color);
/**
* @brief 绘制多边形边框
* @param points 顶点数组
* @param color 边框颜色
* @param width 线条宽度
*/
void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width);
/**
* @brief 填充多边形
* @param points 顶点数组
* @param color 填充颜色
*/
void fillPolygon(const std::vector<Vec2> &points, const Color &color);
/**
* @brief 绘制文本
* @param font 字体图集引用
* @param text 文本内容
* @param position 绘制位置
* @param color 文本颜色
*/
void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color);
/**
* @brief 绘制文本(使用浮点坐标)
* @param font 字体图集引用
* @param text 文本内容
* @param x X坐标
* @param y Y坐标
* @param color 文本颜色
*/
void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color);
/**
* @brief 获取渲染统计信息
* @return 渲染统计信息
*/
RenderStats getStats() const { return stats_; }
/**
* @brief 重置渲染统计信息
*/
void resetStats();
private:
// 形状批处理常量
static constexpr size_t MAX_CIRCLE_SEGMENTS = 128;
static constexpr size_t MAX_SHAPE_VERTICES = 8192; // 最大形状顶点数
static constexpr size_t MAX_LINE_VERTICES = 16384; // 最大线条顶点数
// 形状顶点结构(包含颜色)
struct ShapeVertex {
float x, y;
float r, g, b, a;
};
SDL_Window *window_;
GLSpriteBatch spriteBatch_;
Ptr<IShader> shapeShader_;
GLuint shapeVao_;
GLuint shapeVbo_;
GLuint lineVao_; // 线条专用 VAO
GLuint lineVbo_; // 线条专用 VBO
glm::mat4 viewProjection_;
std::vector<glm::mat4> transformStack_;
RenderStats stats_;
bool vsync_;
// 形状批处理缓冲区(预分配,避免每帧内存分配)
std::array<ShapeVertex, MAX_SHAPE_VERTICES> shapeVertexCache_;
size_t shapeVertexCount_ = 0;
GLenum currentShapeMode_ = GL_TRIANGLES;
// 线条批处理缓冲区
std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_;
size_t lineVertexCount_ = 0;
float currentLineWidth_ = 1.0f;
// OpenGL 状态缓存
BlendMode cachedBlendMode_ = BlendMode::None;
bool blendEnabled_ = false;
void initShapeRendering();
void flushShapeBatch();
void flushLineBatch();
void addShapeVertex(float x, float y, const Color &color);
void addLineVertex(float x, float y, const Color &color);
void submitShapeBatch(GLenum mode);
};
} // namespace frostbite2D

View File

@@ -0,0 +1,194 @@
#pragma once
#include <fostbite2D/core/color.h>
#include <fostbite2D/render/shader/shader_interface.h>
#include <glad/glad.h>
#include <unordered_map>
#include <vector>
namespace frostbite2D {
class GLShader : public IShader {
public:
/**
* @brief 构造函数
*/
GLShader();
/**
* @brief 析构函数
*/
~GLShader() override;
/**
* @brief 绑定Shader程序
*/
void bind() const override;
/**
* @brief 解绑Shader程序
*/
void unbind() const override;
/**
* @brief 设置布尔类型uniform变量
* @param name uniform变量名
* @param value 布尔值
*/
void setBool(const std::string &name, bool value) override;
/**
* @brief 设置整数类型uniform变量
* @param name uniform变量名
* @param value 整数值
*/
void setInt(const std::string &name, int value) override;
/**
* @brief 设置浮点类型uniform变量
* @param name uniform变量名
* @param value 浮点值
*/
void setFloat(const std::string &name, float value) override;
/**
* @brief 设置二维向量类型uniform变量
* @param name uniform变量名
* @param value 二维向量值
*/
void setVec2(const std::string &name, const glm::vec2 &value) override;
/**
* @brief 设置三维向量类型uniform变量
* @param name uniform变量名
* @param value 三维向量值
*/
void setVec3(const std::string &name, const glm::vec3 &value) override;
/**
* @brief 设置四维向量类型uniform变量
* @param name uniform变量名
* @param value 四维向量值
*/
void setVec4(const std::string &name, const glm::vec4 &value) override;
/**
* @brief 设置4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
void setMat4(const std::string &name, const glm::mat4 &value) override;
/**
* @brief 设置颜色类型uniform变量
* @param name uniform变量名
* @param color 颜色值
*/
void setColor(const std::string &name, const Color &color) override;
/**
* @brief 检查Shader是否有效
* @return 有效返回true否则返回false
*/
bool isValid() const override { return programID_ != 0; }
/**
* @brief 获取原生句柄OpenGL程序ID
* @return OpenGL程序ID
*/
uint32_t getNativeHandle() const override { return programID_; }
/**
* @brief 获取Shader名称
* @return Shader名称
*/
const std::string &getName() const override { return name_; }
/**
* @brief 设置Shader名称
* @param name Shader名称
*/
void setName(const std::string &name) override { name_ = name; }
/**
* @brief 从源码编译Shader
* @param vertexSource 顶点着色器源码
* @param fragmentSource 片段着色器源码
* @return 编译成功返回true失败返回false
*/
bool compileFromSource(const char *vertexSource, const char *fragmentSource);
/**
* @brief 从二进制数据创建Shader
* @param binary 二进制数据
* @return 创建成功返回true失败返回false
*/
bool compileFromBinary(const std::vector<uint8_t> &binary);
/**
* @brief 获取Shader二进制数据
* @param outBinary 输出的二进制数据
* @return 成功返回true失败返回false
*/
bool getBinary(std::vector<uint8_t> &outBinary);
/**
* @brief 获取OpenGL程序ID
* @return OpenGL程序ID
*/
GLuint getProgramID() const { return programID_; }
private:
GLuint programID_ = 0;
std::string name_;
std::unordered_map<std::string, GLint> uniformCache_;
/**
* @brief 编译单个着色器
* @param type 着色器类型
* @param source 着色器源码
* @return 着色器ID失败返回0
*/
GLuint compileShader(GLenum type, const char *source);
/**
* @brief 获取uniform位置
* @param name uniform变量名
* @return uniform位置
*/
GLint getUniformLocation(const std::string &name);
};
class GLShaderFactory : public IShaderFactory {
public:
/**
* @brief 从源码创建Shader
* @param name Shader名称
* @param vertSource 顶点着色器源码
* @param fragSource 片段着色器源码
* @return 创建的Shader实例
*/
Ptr<IShader> createFromSource(const std::string &name,
const std::string &vertSource,
const std::string &fragSource) override;
/**
* @brief 从缓存二进制创建Shader
* @param name Shader名称
* @param binary 编译后的二进制数据
* @return 创建的Shader实例
*/
Ptr<IShader> createFromBinary(const std::string &name,
const std::vector<uint8_t> &binary) override;
/**
* @brief 获取Shader的二进制数据
* @param shader Shader实例
* @param outBinary 输出的二进制数据
* @return 成功返回true失败返回false
*/
bool getShaderBinary(const IShader &shader,
std::vector<uint8_t> &outBinary) override;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,98 @@
#pragma once
#include <array>
#include <fostbite2D/core/color.h>
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
#include <fostbite2D/render/shader/shader_interface.h>
#include <fostbite2D/render/texture.h>
#include <glm/mat4x4.hpp>
#include <vector>
#include <glad/glad.h>
namespace frostbite2D {
// ============================================================================
// OpenGL 精灵批渲染器 - 优化版本
// ============================================================================
class GLSpriteBatch {
public:
static constexpr size_t MAX_SPRITES = 10000;
static constexpr size_t VERTICES_PER_SPRITE = 4;
static constexpr size_t INDICES_PER_SPRITE = 6;
static constexpr size_t MAX_VERTICES = MAX_SPRITES * VERTICES_PER_SPRITE;
static constexpr size_t MAX_INDICES = MAX_SPRITES * INDICES_PER_SPRITE;
struct Vertex {
glm::vec2 position;
glm::vec2 texCoord;
glm::vec4 color;
};
struct SpriteData {
glm::vec2 position;
glm::vec2 size;
glm::vec2 texCoordMin;
glm::vec2 texCoordMax;
glm::vec4 color;
float rotation;
glm::vec2 anchor;
bool isSDF = false;
};
GLSpriteBatch();
~GLSpriteBatch();
bool init();
void shutdown();
void begin(const glm::mat4 &viewProjection);
void draw(const Texture &texture, const SpriteData &data);
void end();
// 批量绘制接口 - 用于自动批处理
void drawBatch(const Texture &texture,
const std::vector<SpriteData> &sprites);
// 立即绘制(不缓存)
void drawImmediate(const Texture &texture, const SpriteData &data);
// 统计
uint32_t getDrawCallCount() const { return drawCallCount_; }
uint32_t getSpriteCount() const { return spriteCount_; }
uint32_t getBatchCount() const { return batchCount_; }
// 检查是否需要刷新
bool needsFlush(const Texture &texture, bool isSDF) const;
private:
GLuint vao_;
GLuint vbo_;
GLuint ibo_;
Ptr<IShader> shader_;
// 使用固定大小数组减少内存分配
std::array<Vertex, MAX_VERTICES> vertexBuffer_;
size_t vertexCount_;
const Texture *currentTexture_;
bool currentIsSDF_;
glm::mat4 viewProjection_;
// 缓存上一帧的 viewProjection避免重复设置
glm::mat4 cachedViewProjection_;
bool viewProjectionDirty_ = true;
uint32_t drawCallCount_;
uint32_t spriteCount_;
uint32_t batchCount_;
void flush();
void setupShader();
// 添加顶点到缓冲区
void addVertices(const SpriteData &data);
};
} // namespace frostbite2D

View File

@@ -0,0 +1,79 @@
#pragma once
#include <fostbite2D/core/color.h>
#include <fostbite2D/core/types.h>
#include <fostbite2D/render/texture.h>
#include <glad/glad.h>
#include <memory>
#include <string>
namespace frostbite2D {
// ============================================================================
// OpenGL 纹理实现
// ============================================================================
class GLTexture : public Texture {
public:
GLTexture(int width, int height, const uint8_t *pixels, int channels);
GLTexture(const std::string &filepath);
~GLTexture();
// Texture 接口实现
int getWidth() const override { return width_; }
int getHeight() const override { return height_; }
Size getSize() const override {
return Size(static_cast<float>(width_), static_cast<float>(height_));
}
int getChannels() const override { return channels_; }
PixelFormat getFormat() const override;
void *getNativeHandle() const override {
return reinterpret_cast<void *>(static_cast<uintptr_t>(textureID_));
}
bool isValid() const override { return textureID_ != 0; }
void setFilter(bool linear) override;
void setWrap(bool repeat) override;
// 从参数创建纹理的工厂方法
static Ptr<Texture> create(int width, int height, PixelFormat format);
// 加载压缩纹理KTX/DDS 格式)
bool loadCompressed(const std::string &filepath);
// OpenGL 特定
GLuint getTextureID() const { return textureID_; }
void bind(unsigned int slot = 0) const;
void unbind() const;
// 获取纹理数据大小(字节),用于 VRAM 跟踪
size_t getDataSize() const { return dataSize_; }
// Alpha 遮罩
bool hasAlphaMask() const {
return alphaMask_ != nullptr && alphaMask_->isValid();
}
const AlphaMask *getAlphaMask() const { return alphaMask_.get(); }
void generateAlphaMask(); // 从当前纹理数据生成遮罩
private:
GLuint textureID_;
int width_;
int height_;
int channels_;
PixelFormat format_;
size_t dataSize_;
// 原始像素数据(用于生成遮罩)
std::vector<uint8_t> pixelData_;
std::unique_ptr<AlphaMask> alphaMask_;
void createTexture(const uint8_t *pixels);
// KTX 文件加载
bool loadKTX(const std::string &filepath);
// DDS 文件加载
bool loadDDS(const std::string &filepath);
};
} // namespace frostbite2D

View File

@@ -0,0 +1,151 @@
#pragma once
#include <fostbite2D/core/types.h>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <string>
#include <vector>
namespace frostbite2D {
// 前向声明
struct Color;
// ============================================================================
// Shader抽象接口 - 渲染后端无关
// ============================================================================
class IShader {
public:
virtual ~IShader() = default;
/**
* @brief 绑定Shader程序
*/
virtual void bind() const = 0;
/**
* @brief 解绑Shader程序
*/
virtual void unbind() const = 0;
/**
* @brief 设置布尔类型uniform变量
* @param name uniform变量名
* @param value 布尔值
*/
virtual void setBool(const std::string &name, bool value) = 0;
/**
* @brief 设置整数类型uniform变量
* @param name uniform变量名
* @param value 整数值
*/
virtual void setInt(const std::string &name, int value) = 0;
/**
* @brief 设置浮点类型uniform变量
* @param name uniform变量名
* @param value 浮点值
*/
virtual void setFloat(const std::string &name, float value) = 0;
/**
* @brief 设置二维向量类型uniform变量
* @param name uniform变量名
* @param value 二维向量值
*/
virtual void setVec2(const std::string &name, const glm::vec2 &value) = 0;
/**
* @brief 设置三维向量类型uniform变量
* @param name uniform变量名
* @param value 三维向量值
*/
virtual void setVec3(const std::string &name, const glm::vec3 &value) = 0;
/**
* @brief 设置四维向量类型uniform变量
* @param name uniform变量名
* @param value 四维向量值
*/
virtual void setVec4(const std::string &name, const glm::vec4 &value) = 0;
/**
* @brief 设置4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
virtual void setMat4(const std::string &name, const glm::mat4 &value) = 0;
/**
* @brief 设置颜色类型uniform变量
* @param name uniform变量名
* @param color 颜色值
*/
virtual void setColor(const std::string &name, const Color &color) = 0;
/**
* @brief 检查Shader是否有效
* @return 有效返回true否则返回false
*/
virtual bool isValid() const = 0;
/**
* @brief 获取原生句柄如OpenGL程序ID
* @return 原生句柄值
*/
virtual uint32_t getNativeHandle() const = 0;
/**
* @brief 获取Shader名称
* @return Shader名称
*/
virtual const std::string &getName() const = 0;
/**
* @brief 设置Shader名称
* @param name Shader名称
*/
virtual void setName(const std::string &name) = 0;
};
// ============================================================================
// Shader工厂接口 - 用于创建渲染后端特定的Shader实例
// ============================================================================
class IShaderFactory {
public:
virtual ~IShaderFactory() = default;
/**
* @brief 从源码创建Shader
* @param name Shader名称
* @param vertSource 顶点着色器源码
* @param fragSource 片段着色器源码
* @return 创建的Shader实例
*/
virtual Ptr<IShader> createFromSource(const std::string &name,
const std::string &vertSource,
const std::string &fragSource) = 0;
/**
* @brief 从缓存二进制创建Shader
* @param name Shader名称
* @param binary 编译后的二进制数据
* @return 创建的Shader实例
*/
virtual Ptr<IShader> createFromBinary(const std::string &name,
const std::vector<uint8_t> &binary) = 0;
/**
* @brief 获取Shader的二进制数据用于缓存
* @param shader Shader实例
* @param outBinary 输出的二进制数据
* @return 成功返回true失败返回false
*/
virtual bool getShaderBinary(const IShader &shader,
std::vector<uint8_t> &outBinary) = 0;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,129 @@
#pragma once
#include <fostbite2D/core/types.h>
#include <fostbite2D/render/shader/shader_interface.h>
#include <filesystem>
#include <functional>
#include <unordered_map>
namespace frostbite2D {
// ============================================================================
// Shader重载回调
// ============================================================================
using ShaderReloadCallback = std::function<void(Ptr<IShader> newShader)>;
// ============================================================================
// Shader管理器 - 统一入口
// ============================================================================
class ShaderManager {
public:
/**
* @brief 获取单例实例
* @return Shader管理器实例引用
*/
static ShaderManager &getInstance();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
/**
* @brief 初始化Shader系统
* @param factory 渲染后端Shader工厂
* @return 初始化成功返回true失败返回false
*/
bool init(Ptr<IShaderFactory> factory);
/**
* @brief 关闭Shader系统
*/
void shutdown();
/**
* @brief 检查是否已初始化
* @return 已初始化返回true否则返回false
*/
bool isInitialized() const { return initialized_; }
// ------------------------------------------------------------------------
// Shader加载
// ------------------------------------------------------------------------
/**
* @brief 从源码加载Shader
* @param name Shader名称
* @param vertSource 顶点着色器源码
* @param fragSource 片段着色器源码
* @return 加载的Shader实例
*/
Ptr<IShader> loadFromSource(const std::string &name,
const std::string &vertSource,
const std::string &fragSource);
/**
* @brief 从文件加载Shader
* @param name Shader名称
* @param vertPath 顶点着色器文件路径
* @param fragPath 片段着色器文件路径
* @return 加载的Shader实例失败返回nullptr
*/
Ptr<IShader> loadFromFile(const std::string &name,
const std::filesystem::path &vertPath,
const std::filesystem::path &fragPath);
/**
* @brief 获取已加载的Shader
* @param name Shader名称
* @return Shader实例不存在返回nullptr
*/
Ptr<IShader> get(const std::string &name) const;
/**
* @brief 检查Shader是否存在
* @param name Shader名称
* @return 存在返回true否则返回false
*/
bool has(const std::string &name) const;
/**
* @brief 移除Shader
* @param name Shader名称
*/
void remove(const std::string &name);
/**
* @brief 清除所有Shader
*/
void clear();
/**
* @brief 注册重载回调
* @param name Shader名称
* @param callback 重载回调函数
*/
void setReloadCallback(const std::string &name,
ShaderReloadCallback callback);
private:
ShaderManager() = default;
~ShaderManager() = default;
ShaderManager(const ShaderManager &) = delete;
ShaderManager &operator=(const ShaderManager &) = delete;
Ptr<IShaderFactory> factory_;
struct ShaderInfo {
Ptr<IShader> shader;
ShaderReloadCallback reloadCallback;
std::string vertSource;
std::string fragSource;
std::filesystem::path vertPath;
std::filesystem::path fragPath;
};
std::unordered_map<std::string, ShaderInfo> shaders_;
bool initialized_ = false;
};
} // namespace frostbite2D

View File

@@ -0,0 +1,154 @@
#pragma once
#include <fostbite2D/core/math_types.h>
#include <fostbite2D/core/types.h>
namespace frostbite2D {
// ============================================================================
// 像素格式枚举
// ============================================================================
enum class PixelFormat {
R8, // 单通道灰度
RG8, // 双通道
RGB8, // RGB
RGBA8, // RGBA
R16F, // 半精度浮点单通道
RG16F, // 半精度浮点双通道
RGB16F, // 半精度浮点RGB
RGBA16F, // 半精度浮点RGBA
R32F, // 单精度浮点单通道
RG32F, // 单精度浮点双通道
RGB32F, // 单精度浮点RGB
RGBA32F, // 单精度浮点RGBA
// 压缩格式
ETC2_RGB8,
ETC2_RGBA8,
ASTC_4x4,
ASTC_6x6,
ASTC_8x8,
};
// ============================================================================
// 纹理抽象基类
// ============================================================================
class Texture {
public:
virtual ~Texture() = default;
/**
* @brief 获取纹理宽度
* @return 纹理宽度(像素)
*/
virtual int getWidth() const = 0;
/**
* @brief 获取纹理高度
* @return 纹理高度(像素)
*/
virtual int getHeight() const = 0;
/**
* @brief 获取纹理尺寸
* @return 纹理尺寸
*/
virtual Size getSize() const = 0;
/**
* @brief 获取颜色通道数
* @return 颜色通道数
*/
virtual int getChannels() const = 0;
/**
* @brief 获取像素格式
* @return 像素格式
*/
virtual PixelFormat getFormat() const = 0;
/**
* @brief 获取原生句柄
* @return 原生句柄如OpenGL纹理ID
*/
virtual void *getNativeHandle() const = 0;
/**
* @brief 检查纹理是否有效
* @return 有效返回true否则返回false
*/
virtual bool isValid() const = 0;
/**
* @brief 设置纹理过滤模式
* @param linear true使用线性过滤false使用最近邻过滤
*/
virtual void setFilter(bool linear) = 0;
/**
* @brief 设置纹理环绕模式
* @param repeat true使用重复模式false使用边缘拉伸模式
*/
virtual void setWrap(bool repeat) = 0;
};
// ============================================================================
// Alpha遮罩 - 用于像素级碰撞检测
// ============================================================================
class AlphaMask {
public:
AlphaMask() = default;
AlphaMask(AlphaMask &&) = default;
AlphaMask &operator=(AlphaMask &&) = default;
/**
* @brief 从像素数据创建Alpha遮罩
* @param pixels 像素数据指针
* @param width 宽度
* @param height 高度
* @param channels 通道数
* @return 创建的AlphaMask
*/
static AlphaMask createFromPixels(const uint8_t *pixels, int width,
int height, int channels);
/**
* @brief 检查遮罩是否有效
* @return 有效返回true
*/
bool isValid() const { return !data_.empty() && width_ > 0 && height_ > 0; }
/**
* @brief 获取指定位置的透明度
* @param x X坐标
* @param y Y坐标
* @return 透明度值0-255
*/
uint8_t getAlpha(int x, int y) const;
/**
* @brief 检查指定位置是否不透明
* @param x X坐标
* @param y Y坐标
* @return 不透明返回true
*/
bool isOpaque(int x, int y) const;
/**
* @brief 获取宽度
* @return 宽度
*/
int getWidth() const { return width_; }
/**
* @brief 获取高度
* @return 高度
*/
int getHeight() const { return height_; }
private:
std::vector<uint8_t> data_;
int width_ = 0;
int height_ = 0;
};
} // namespace frostbite2D