Compare commits
58 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e011cea090 | |
|
|
d5cb194552 | |
|
|
44e0d65f10 | |
|
|
e0b0a7883d | |
|
|
97be1b746a | |
|
|
717112c437 | |
|
|
ec6ced9db2 | |
|
|
8cd883ede7 | |
|
|
91e3e8fe57 | |
|
|
9041833430 | |
|
|
b4a3d6b14b | |
|
|
d387532738 | |
|
|
f7e4f89cca | |
|
|
46ec1c665f | |
|
|
3b827149ba | |
|
|
92be7d9d18 | |
|
|
b4be0d84f8 | |
|
|
46393fd027 | |
|
|
bbdc1435ce | |
|
|
bdf78f5eca | |
|
|
6717015e28 | |
|
|
fb11f2a71e | |
|
|
f9be301dae | |
|
|
ebf73a4492 | |
|
|
418d2c8f92 | |
|
|
e68ce87638 | |
|
|
5a3d0cd9de | |
|
|
0761b55864 | |
|
|
8abf58e3d5 | |
|
|
5ef1873a44 | |
|
|
71eeeac033 | |
|
|
3b031666ae | |
|
|
24b86b4916 | |
|
|
ea081b9dd3 | |
|
|
d81f0c1e45 | |
|
|
b4a55239aa | |
|
|
4afd52cc82 | |
|
|
60ef7ab63f | |
|
|
c84aab70ed | |
|
|
00d709fcc8 | |
|
|
aec444f2b5 | |
|
|
e52c117830 | |
|
|
f41600306e | |
|
|
98bca638d0 | |
|
|
353a222c62 | |
|
|
7b1e1299e0 | |
|
|
bd3cebf0b5 | |
|
|
ea5ecd383f | |
|
|
377ec373b0 | |
|
|
0f520c8e37 | |
|
|
fa9ee0e2a7 | |
|
|
a6c1f66fff | |
|
|
5039b1d9fc | |
|
|
f9c8f080eb | |
|
|
f08a0bf583 | |
|
|
97220e9417 | |
|
|
a2b142eb99 | |
|
|
7c7d9cca92 |
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git diff:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -71,7 +71,6 @@ cmake-build-*/
|
|||
# --------------------------------------------
|
||||
/packages/
|
||||
/deps/
|
||||
/third_party/
|
||||
/vendor/
|
||||
|
||||
# --------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "third_party/tbb"]
|
||||
path = third_party/tbb
|
||||
url = https://github.com/oneapi-src/oneTBB.git
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
class IInput;
|
||||
class RenderBackend;
|
||||
class WindowModule;
|
||||
class RenderModule;
|
||||
class InputModule;
|
||||
|
||||
/**
|
||||
* @brief 应用程序类
|
||||
*/
|
||||
class Application {
|
||||
public:
|
||||
static Application &get();
|
||||
|
||||
Application(const Application &) = delete;
|
||||
Application &operator=(const Application &) = delete;
|
||||
|
||||
/**
|
||||
* @brief 应用信息
|
||||
*/
|
||||
std::string appName = "Extra2D App";
|
||||
std::string appVersion = "1.0.0";
|
||||
std::string organization = "";
|
||||
|
||||
/**
|
||||
* @brief 注册模块
|
||||
* @tparam T 模块类型
|
||||
* @tparam Args 构造函数参数
|
||||
* @return 模块指针
|
||||
*/
|
||||
template <typename T, typename... Args> T *use(Args &&...args) {
|
||||
return Registry::instance().use<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取模块
|
||||
* @tparam T 模块类型
|
||||
* @return 模块指针
|
||||
*/
|
||||
template <typename T> T *get() const { return Registry::instance().get<T>(); }
|
||||
|
||||
/**
|
||||
* @brief 初始化
|
||||
* @return 初始化成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 运行主循环
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* @brief 请求退出
|
||||
*/
|
||||
void quit();
|
||||
|
||||
/**
|
||||
* @brief 暂停
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* @brief 恢复
|
||||
*/
|
||||
void resume();
|
||||
|
||||
bool isPaused() const { return paused_; }
|
||||
bool isRunning() const { return running_; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口
|
||||
* @return 窗口指针
|
||||
*/
|
||||
IWindow *window();
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器
|
||||
* @return 渲染器指针
|
||||
*/
|
||||
RenderBackend *renderer();
|
||||
|
||||
/**
|
||||
* @brief 获取输入
|
||||
* @return 输入指针
|
||||
*/
|
||||
IInput *input();
|
||||
|
||||
/**
|
||||
* @brief 进入场景
|
||||
* @param scene 场景指针
|
||||
*/
|
||||
void enterScene(Ptr<class Scene> scene);
|
||||
|
||||
float deltaTime() const { return deltaTime_; }
|
||||
float totalTime() const { return totalTime_; }
|
||||
int fps() const { return currentFps_; }
|
||||
|
||||
private:
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
void mainLoop();
|
||||
void update();
|
||||
void render();
|
||||
void configureCameraService();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/// 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 extra2d
|
||||
|
|
@ -1,550 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 常量
|
||||
// ---------------------------------------------------------------------------
|
||||
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 ¢er, 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 ¢er1, float radius1,
|
||||
const Vec2 ¢er2, 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 extra2d
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <typeindex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class Application;
|
||||
|
||||
/**
|
||||
* @brief 模块基类
|
||||
* 所有模块必须继承此类
|
||||
*/
|
||||
class Module {
|
||||
public:
|
||||
virtual ~Module() = default;
|
||||
|
||||
/**
|
||||
* @brief 初始化模块
|
||||
* @return 初始化成功返回 true
|
||||
*/
|
||||
virtual bool init() = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭模块
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查模块是否已初始化
|
||||
* @return 已初始化返回 true
|
||||
*/
|
||||
virtual bool ok() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取模块名称
|
||||
* @return 模块名称
|
||||
*/
|
||||
virtual const char* name() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取模块优先级(数值越小越优先)
|
||||
* @return 优先级值
|
||||
*/
|
||||
virtual int priority() const { return 100; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块依赖列表
|
||||
* @return 依赖模块类型列表
|
||||
*/
|
||||
virtual std::vector<std::type_index> deps() const { return {}; }
|
||||
|
||||
/**
|
||||
* @brief 设置所属Application
|
||||
* @param app Application指针
|
||||
*/
|
||||
void setApp(class Application* app) { app_ = app; }
|
||||
|
||||
/**
|
||||
* @brief 获取Application
|
||||
* @return Application指针
|
||||
*/
|
||||
class Application* app() const { return app_; }
|
||||
|
||||
protected:
|
||||
class Application* app_ = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 模块工厂函数类型
|
||||
*/
|
||||
using ModuleFactory = std::function<UniquePtr<Module>()>;
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <unordered_map>
|
||||
#include <typeindex>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class Application;
|
||||
|
||||
/**
|
||||
* @brief 模块注册表
|
||||
* 管理模块的注册、拓扑排序和生命周期
|
||||
*/
|
||||
class Registry {
|
||||
public:
|
||||
static Registry& instance();
|
||||
|
||||
Registry(const Registry&) = delete;
|
||||
Registry& operator=(const Registry&) = delete;
|
||||
|
||||
/**
|
||||
* @brief 注册模块
|
||||
* @tparam T 模块类型
|
||||
* @tparam Args 构造函数参数类型
|
||||
* @param args 构造函数参数
|
||||
* @return 模块指针
|
||||
*/
|
||||
template<typename T, typename... Args>
|
||||
T* use(Args&&... args) {
|
||||
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
|
||||
|
||||
auto typeIdx = std::type_index(typeid(T));
|
||||
if (modules_.count(typeIdx)) {
|
||||
return static_cast<T*>(modules_[typeIdx].get());
|
||||
}
|
||||
|
||||
auto module = makeUnique<T>(std::forward<Args>(args)...);
|
||||
T* ptr = module.get();
|
||||
module->setApp(app_);
|
||||
modules_[typeIdx] = std::move(module);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取模块
|
||||
* @tparam T 模块类型
|
||||
* @return 模块指针,不存在返回 nullptr
|
||||
*/
|
||||
template<typename T>
|
||||
T* get() const {
|
||||
auto typeIdx = std::type_index(typeid(T));
|
||||
auto it = modules_.find(typeIdx);
|
||||
if (it != modules_.end()) {
|
||||
return static_cast<T*>(it->second.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取模块(基类版本)
|
||||
* @param typeIdx 类型索引
|
||||
* @return 模块指针
|
||||
*/
|
||||
Module* get(std::type_index typeIdx) const {
|
||||
auto it = modules_.find(typeIdx);
|
||||
if (it != modules_.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置Application
|
||||
*/
|
||||
void setApp(Application* app) { app_ = app; }
|
||||
|
||||
/**
|
||||
* @brief 初始化所有模块(按优先级拓扑排序)
|
||||
* @return 初始化成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭所有模块
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 清空所有模块
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @brief 获取模块数量
|
||||
*/
|
||||
size_t size() const { return modules_.size(); }
|
||||
|
||||
private:
|
||||
Registry() = default;
|
||||
~Registry() = default;
|
||||
|
||||
/**
|
||||
* @brief 拓扑排序模块
|
||||
* @return 排序后的模块列表
|
||||
*/
|
||||
std::vector<Module*> topologicalSort();
|
||||
|
||||
std::unordered_map<std::type_index, UniquePtr<Module>> modules_;
|
||||
Application* app_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 服务优先级枚举
|
||||
* 定义服务的初始化顺序,数值越小越先初始化
|
||||
*/
|
||||
enum class ServicePriority : int {
|
||||
Core = 0,
|
||||
Event = 100,
|
||||
Timer = 200,
|
||||
Scene = 300,
|
||||
Camera = 400,
|
||||
Resource = 500,
|
||||
Audio = 600,
|
||||
User = 1000
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务状态枚举
|
||||
*/
|
||||
enum class ServiceState {
|
||||
Uninitialized,
|
||||
Initializing,
|
||||
Running,
|
||||
Paused,
|
||||
Stopping,
|
||||
Stopped
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务信息结构体
|
||||
*/
|
||||
struct ServiceInfo {
|
||||
std::string name;
|
||||
ServicePriority priority = ServicePriority::User;
|
||||
ServiceState state = ServiceState::Uninitialized;
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务接口基类
|
||||
* 所有服务必须实现此接口,支持依赖注入和生命周期管理
|
||||
*/
|
||||
class IService {
|
||||
friend class ServiceLocator;
|
||||
|
||||
public:
|
||||
virtual ~IService() = default;
|
||||
|
||||
/**
|
||||
* @brief 获取服务信息
|
||||
* @return 服务信息结构体
|
||||
*/
|
||||
virtual ServiceInfo getServiceInfo() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 初始化服务
|
||||
* @return 初始化成功返回 true
|
||||
*/
|
||||
virtual bool initialize() = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭服务
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 暂停服务
|
||||
*/
|
||||
virtual void pause() {
|
||||
info_.state = ServiceState::Paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 恢复服务
|
||||
*/
|
||||
virtual void resume() {
|
||||
if (info_.state == ServiceState::Paused) {
|
||||
info_.state = ServiceState::Running;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 更新服务
|
||||
* @param deltaTime 帧间隔时间
|
||||
*/
|
||||
virtual void update(float deltaTime) { }
|
||||
|
||||
/**
|
||||
* @brief 检查服务是否已初始化
|
||||
* @return 已初始化返回 true
|
||||
*/
|
||||
virtual bool isInitialized() const {
|
||||
return info_.state == ServiceState::Running ||
|
||||
info_.state == ServiceState::Paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取服务状态
|
||||
* @return 当前服务状态
|
||||
*/
|
||||
ServiceState getState() const { return info_.state; }
|
||||
|
||||
/**
|
||||
* @brief 获取服务名称
|
||||
* @return 服务名称
|
||||
*/
|
||||
const std::string& getName() const { return info_.name; }
|
||||
|
||||
protected:
|
||||
ServiceInfo info_;
|
||||
|
||||
/**
|
||||
* @brief 设置服务状态
|
||||
* @param state 新状态
|
||||
*/
|
||||
void setState(ServiceState state) { info_.state = state; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 类型ID生成器
|
||||
* 用于为每种服务类型生成唯一ID
|
||||
*/
|
||||
using ServiceTypeId = size_t;
|
||||
|
||||
namespace detail {
|
||||
inline ServiceTypeId nextServiceTypeId() {
|
||||
static ServiceTypeId id = 0;
|
||||
return ++id;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ServiceTypeId getServiceTypeId() {
|
||||
static ServiceTypeId id = nextServiceTypeId();
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,302 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 服务工厂函数类型
|
||||
*/
|
||||
template <typename T> using ServiceFactory = std::function<SharedPtr<T>()>;
|
||||
|
||||
/**
|
||||
* @brief 服务定位器
|
||||
* 实现依赖注入和服务发现模式,解耦模块间依赖
|
||||
*
|
||||
* 特性:
|
||||
* - 类型安全的服务注册和获取
|
||||
* - 支持服务工厂延迟创建
|
||||
* - 支持服务依赖声明
|
||||
* - 线程安全
|
||||
* - 支持 Mock 测试
|
||||
*/
|
||||
class ServiceLocator {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return 服务定位器实例引用
|
||||
*/
|
||||
static ServiceLocator &instance();
|
||||
|
||||
ServiceLocator(const ServiceLocator &) = delete;
|
||||
ServiceLocator &operator=(const ServiceLocator &) = delete;
|
||||
|
||||
/**
|
||||
* @brief 注册服务实例
|
||||
* @tparam T 服务接口类型
|
||||
* @param service 服务实例
|
||||
*/
|
||||
template <typename T> void registerService(SharedPtr<T> service) {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
services_[typeId] = std::static_pointer_cast<IService>(service);
|
||||
orderedServices_.push_back(service);
|
||||
sortServices();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册服务工厂
|
||||
* @tparam T 服务接口类型
|
||||
* @param factory 服务工厂函数
|
||||
*/
|
||||
template <typename T> void registerFactory(ServiceFactory<T> factory) {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
factories_[typeId] = [factory]() -> SharedPtr<IService> {
|
||||
return std::static_pointer_cast<IService>(factory());
|
||||
};
|
||||
|
||||
// 立即创建服务实例并添加到有序列表
|
||||
auto service = factories_[typeId]();
|
||||
services_[typeId] = service;
|
||||
orderedServices_.push_back(service);
|
||||
sortServices();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取服务实例
|
||||
* @tparam T 服务接口类型
|
||||
* @return 服务实例,不存在返回 nullptr
|
||||
*/
|
||||
template <typename T> SharedPtr<T> getService() const {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
|
||||
auto it = services_.find(typeId);
|
||||
if (it != services_.end()) {
|
||||
return std::static_pointer_cast<T>(it->second);
|
||||
}
|
||||
|
||||
auto factoryIt = factories_.find(typeId);
|
||||
if (factoryIt != factories_.end()) {
|
||||
auto service = factoryIt->second();
|
||||
services_[typeId] = service;
|
||||
return std::static_pointer_cast<T>(service);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试获取服务实例(不创建)
|
||||
* @tparam T 服务接口类型
|
||||
* @return 服务实例,不存在返回 nullptr
|
||||
*/
|
||||
template <typename T> SharedPtr<T> tryGetService() const {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
auto it = services_.find(typeId);
|
||||
if (it != services_.end()) {
|
||||
return std::static_pointer_cast<T>(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查服务是否已注册
|
||||
* @tparam T 服务接口类型
|
||||
* @return 已注册返回 true
|
||||
*/
|
||||
template <typename T> bool hasService() const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
return services_.find(typeId) != services_.end() ||
|
||||
factories_.find(typeId) != factories_.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注销服务
|
||||
* @tparam T 服务接口类型
|
||||
*/
|
||||
template <typename T> void unregisterService() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto typeId = std::type_index(typeid(T));
|
||||
|
||||
auto it = services_.find(typeId);
|
||||
if (it != services_.end()) {
|
||||
auto service = it->second;
|
||||
services_.erase(it);
|
||||
|
||||
auto orderIt =
|
||||
std::find(orderedServices_.begin(), orderedServices_.end(), service);
|
||||
if (orderIt != orderedServices_.end()) {
|
||||
orderedServices_.erase(orderIt);
|
||||
}
|
||||
}
|
||||
|
||||
factories_.erase(typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化所有已注册的服务
|
||||
* @return 所有服务初始化成功返回 true
|
||||
*/
|
||||
bool initializeAll();
|
||||
|
||||
/**
|
||||
* @brief 关闭所有服务
|
||||
*/
|
||||
void shutdownAll();
|
||||
|
||||
/**
|
||||
* @brief 更新所有服务
|
||||
* @param deltaTime 帧间隔时间
|
||||
*/
|
||||
void updateAll(float deltaTime);
|
||||
|
||||
/**
|
||||
* @brief 暂停所有服务
|
||||
*/
|
||||
void pauseAll();
|
||||
|
||||
/**
|
||||
* @brief 恢复所有服务
|
||||
*/
|
||||
void resumeAll();
|
||||
|
||||
/**
|
||||
* @brief 获取所有服务(按优先级排序)
|
||||
* @return 服务列表
|
||||
*/
|
||||
std::vector<SharedPtr<IService>> getAllServices() const;
|
||||
|
||||
/**
|
||||
* @brief 清空所有服务和工厂
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @brief 获取已注册服务数量
|
||||
* @return 服务数量
|
||||
*/
|
||||
size_t size() const { return services_.size(); }
|
||||
|
||||
private:
|
||||
ServiceLocator() = default;
|
||||
~ServiceLocator() = default;
|
||||
|
||||
/**
|
||||
* @brief 按优先级排序服务
|
||||
*/
|
||||
void sortServices();
|
||||
|
||||
mutable std::unordered_map<std::type_index, SharedPtr<IService>> services_;
|
||||
std::unordered_map<std::type_index, std::function<SharedPtr<IService>()>>
|
||||
factories_;
|
||||
std::vector<SharedPtr<IService>> orderedServices_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务注册器
|
||||
* 用于静态注册服务
|
||||
*/
|
||||
template <typename Interface, typename Implementation> class ServiceRegistrar {
|
||||
public:
|
||||
explicit ServiceRegistrar(ServiceFactory<Interface> factory = nullptr) {
|
||||
if (factory) {
|
||||
ServiceLocator::instance().registerFactory<Interface>(factory);
|
||||
} else {
|
||||
ServiceLocator::instance().registerFactory<Interface>(
|
||||
[]() -> SharedPtr<Interface> {
|
||||
return makeShared<Implementation>();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务注册元数据模板
|
||||
* 使用模板元编程实现编译期服务注册
|
||||
* 通过静态成员变量的初始化触发注册
|
||||
*/
|
||||
template <typename Interface, typename Implementation> struct ServiceAutoReg {
|
||||
/**
|
||||
* @brief 注册标记,访问此变量时触发服务注册
|
||||
*/
|
||||
static const bool registered;
|
||||
|
||||
/**
|
||||
* @brief 执行实际的服务注册
|
||||
* @return true 表示注册成功
|
||||
*/
|
||||
static bool doRegister() {
|
||||
::extra2d::ServiceLocator::instance().registerFactory<Interface>(
|
||||
[]() -> ::extra2d::SharedPtr<Interface> {
|
||||
return ::extra2d::makeShared<Implementation>();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// 静态成员定义,在此处触发注册
|
||||
template <typename Interface, typename Implementation>
|
||||
const bool ServiceAutoReg<Interface, Implementation>::registered =
|
||||
ServiceAutoReg<Interface, Implementation>::doRegister();
|
||||
|
||||
/**
|
||||
* @brief 服务注册元数据(带自定义工厂)
|
||||
*/
|
||||
template <typename Interface> struct ServiceAutoRegFactory {
|
||||
template <typename Factory> struct Impl {
|
||||
static const bool registered;
|
||||
|
||||
static bool doRegister(Factory factory) {
|
||||
::extra2d::ServiceLocator::instance().registerFactory<Interface>(factory);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Interface>
|
||||
template <typename Factory>
|
||||
const bool ServiceAutoRegFactory<Interface>::Impl<Factory>::registered =
|
||||
ServiceAutoRegFactory<Interface>::Impl<Factory>::doRegister(Factory{});
|
||||
|
||||
/**
|
||||
* @brief 自动注册服务宏(元数据驱动)
|
||||
* 在服务实现类中使用,通过模板元编程实现自动注册
|
||||
* 比静态对象更可靠,不易被编译器优化
|
||||
*/
|
||||
#define E2D_AUTO_REGISTER_SERVICE(Interface, Implementation) \
|
||||
static inline const bool E2D_CONCAT(_service_reg_, __LINE__) = \
|
||||
ServiceAutoReg<Interface, Implementation>::registered
|
||||
|
||||
/**
|
||||
* @brief 带自定义工厂的自动注册服务宏(元数据驱动)
|
||||
*/
|
||||
#define E2D_AUTO_REGISTER_SERVICE_FACTORY(Interface, Factory) \
|
||||
static inline const bool E2D_CONCAT(_service_factory_reg_, __LINE__) = \
|
||||
ServiceAutoRegFactory<Interface>::Impl<Factory>::registered
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 服务注册信息
|
||||
*/
|
||||
struct ServiceRegistration {
|
||||
std::string name;
|
||||
ServicePriority priority;
|
||||
std::function<SharedPtr<IService>()> factory;
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 服务注册表
|
||||
* 管理服务的注册信息,支持延迟创建和配置
|
||||
*/
|
||||
class ServiceRegistry {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return 服务注册表实例引用
|
||||
*/
|
||||
static ServiceRegistry& instance();
|
||||
|
||||
ServiceRegistry(const ServiceRegistry&) = delete;
|
||||
ServiceRegistry& operator=(const ServiceRegistry&) = delete;
|
||||
|
||||
/**
|
||||
* @brief 注册服务
|
||||
* @tparam T 服务接口类型
|
||||
* @tparam Impl 服务实现类型
|
||||
* @param name 服务名称
|
||||
* @param priority 服务优先级
|
||||
*/
|
||||
template<typename T, typename Impl>
|
||||
void registerService(const std::string& name, ServicePriority priority) {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
static_assert(std::is_base_of_v<T, Impl>,
|
||||
"Impl must derive from T");
|
||||
|
||||
ServiceRegistration reg;
|
||||
reg.name = name;
|
||||
reg.priority = priority;
|
||||
reg.factory = []() -> SharedPtr<IService> {
|
||||
return std::static_pointer_cast<IService>(makeShared<Impl>());
|
||||
};
|
||||
registrations_.push_back(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册服务(带工厂函数)
|
||||
* @tparam T 服务接口类型
|
||||
* @param name 服务名称
|
||||
* @param priority 服务优先级
|
||||
* @param factory 工厂函数
|
||||
*/
|
||||
template<typename T>
|
||||
void registerServiceWithFactory(
|
||||
const std::string& name,
|
||||
ServicePriority priority,
|
||||
std::function<SharedPtr<T>()> factory) {
|
||||
static_assert(std::is_base_of_v<IService, T>,
|
||||
"T must derive from IService");
|
||||
|
||||
ServiceRegistration reg;
|
||||
reg.name = name;
|
||||
reg.priority = priority;
|
||||
reg.factory = [factory]() -> SharedPtr<IService> {
|
||||
return std::static_pointer_cast<IService>(factory());
|
||||
};
|
||||
registrations_.push_back(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用服务
|
||||
* @param name 服务名称
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
void setServiceEnabled(const std::string& name, bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 创建所有已注册的服务
|
||||
* 并注册到 ServiceLocator
|
||||
*/
|
||||
void createAllServices();
|
||||
|
||||
/**
|
||||
* @brief 获取所有注册信息
|
||||
* @return 注册信息列表
|
||||
*/
|
||||
const std::vector<ServiceRegistration>& getRegistrations() const {
|
||||
return registrations_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清空所有注册
|
||||
*/
|
||||
void clear() {
|
||||
registrations_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
ServiceRegistry() = default;
|
||||
~ServiceRegistry() = default;
|
||||
|
||||
std::vector<ServiceRegistration> registrations_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 自动服务注册器
|
||||
* 在全局作用域使用,自动注册服务
|
||||
*/
|
||||
template<typename Interface, typename Implementation>
|
||||
class AutoServiceRegistrar {
|
||||
public:
|
||||
AutoServiceRegistrar(const std::string& name, ServicePriority priority) {
|
||||
ServiceRegistry::instance().registerService<Interface, Implementation>(
|
||||
name, priority);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \
|
||||
namespace { \
|
||||
static ::extra2d::AutoServiceRegistrar<Interface, Implementation> \
|
||||
E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 宏定义
|
||||
// ---------------------------------------------------------------------------
|
||||
#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 extra2d
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <variant>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 事件类型枚举
|
||||
// ============================================================================
|
||||
enum class EventType {
|
||||
None = 0,
|
||||
|
||||
// 窗口事件
|
||||
WindowClose,
|
||||
WindowResize,
|
||||
WindowFocus,
|
||||
WindowLostFocus,
|
||||
WindowMoved,
|
||||
|
||||
// 键盘事件
|
||||
KeyPressed,
|
||||
KeyReleased,
|
||||
KeyRepeat,
|
||||
|
||||
// 鼠标事件
|
||||
MouseButtonPressed,
|
||||
MouseButtonReleased,
|
||||
MouseMoved,
|
||||
MouseScrolled,
|
||||
|
||||
// UI 事件
|
||||
UIHoverEnter,
|
||||
UIHoverExit,
|
||||
UIPressed,
|
||||
UIReleased,
|
||||
UIClicked,
|
||||
|
||||
// 游戏手柄事件
|
||||
GamepadConnected,
|
||||
GamepadDisconnected,
|
||||
GamepadButtonPressed,
|
||||
GamepadButtonReleased,
|
||||
GamepadAxisMoved,
|
||||
|
||||
// 触摸事件 (移动端)
|
||||
TouchBegan,
|
||||
TouchMoved,
|
||||
TouchEnded,
|
||||
TouchCancelled,
|
||||
|
||||
// 自定义事件
|
||||
Custom
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 键盘事件数据
|
||||
// ============================================================================
|
||||
struct KeyEvent {
|
||||
int keyCode;
|
||||
int scancode;
|
||||
int mods; // 修饰键 (Shift, Ctrl, Alt, etc.)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 鼠标事件数据
|
||||
// ============================================================================
|
||||
struct MouseButtonEvent {
|
||||
int button;
|
||||
int mods;
|
||||
Vec2 position;
|
||||
};
|
||||
|
||||
struct MouseMoveEvent {
|
||||
Vec2 position;
|
||||
Vec2 delta;
|
||||
};
|
||||
|
||||
struct MouseScrollEvent {
|
||||
Vec2 offset;
|
||||
Vec2 position;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 窗口事件数据
|
||||
// ============================================================================
|
||||
struct WindowResizeEvent {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct WindowMoveEvent {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 游戏手柄事件数据
|
||||
// ============================================================================
|
||||
struct GamepadButtonEvent {
|
||||
int gamepadId;
|
||||
int button;
|
||||
};
|
||||
|
||||
struct GamepadAxisEvent {
|
||||
int gamepadId;
|
||||
int axis;
|
||||
float value;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 触摸事件数据
|
||||
// ============================================================================
|
||||
struct TouchEvent {
|
||||
int touchId;
|
||||
Vec2 position;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 自定义事件数据
|
||||
// ============================================================================
|
||||
struct CustomEvent {
|
||||
uint32_t id;
|
||||
void *data;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 事件结构
|
||||
// ============================================================================
|
||||
struct Event {
|
||||
EventType type = EventType::None;
|
||||
double timestamp = 0.0;
|
||||
bool handled = false;
|
||||
|
||||
// 事件数据联合体
|
||||
std::variant<std::monostate, KeyEvent, MouseButtonEvent, MouseMoveEvent,
|
||||
MouseScrollEvent, WindowResizeEvent, WindowMoveEvent,
|
||||
GamepadButtonEvent, GamepadAxisEvent, TouchEvent, CustomEvent>
|
||||
data;
|
||||
|
||||
// 便捷访问方法
|
||||
bool isWindowEvent() const {
|
||||
return type == EventType::WindowClose || type == EventType::WindowResize ||
|
||||
type == EventType::WindowFocus ||
|
||||
type == EventType::WindowLostFocus || type == EventType::WindowMoved;
|
||||
}
|
||||
|
||||
bool isKeyboardEvent() const {
|
||||
return type == EventType::KeyPressed || type == EventType::KeyReleased ||
|
||||
type == EventType::KeyRepeat;
|
||||
}
|
||||
|
||||
bool isMouseEvent() const {
|
||||
return type == EventType::MouseButtonPressed ||
|
||||
type == EventType::MouseButtonReleased ||
|
||||
type == EventType::MouseMoved || type == EventType::MouseScrolled;
|
||||
}
|
||||
|
||||
// 静态工厂方法
|
||||
static Event createWindowResize(int width, int height);
|
||||
static Event createWindowClose();
|
||||
static Event createKeyPress(int keyCode, int scancode, int mods);
|
||||
static Event createKeyRelease(int keyCode, int scancode, int mods);
|
||||
static Event createMouseButtonPress(int button, int mods, const Vec2 &pos);
|
||||
static Event createMouseButtonRelease(int button, int mods, const Vec2 &pos);
|
||||
static Event createMouseMove(const Vec2 &pos, const Vec2 &delta);
|
||||
static Event createMouseScroll(const Vec2 &offset, const Vec2 &pos);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/event/event.h>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 事件监听器 ID
|
||||
// ============================================================================
|
||||
using ListenerId = uint64_t;
|
||||
|
||||
// ============================================================================
|
||||
// 事件分发器
|
||||
// ============================================================================
|
||||
class EventDispatcher {
|
||||
public:
|
||||
using EventCallback = std::function<void(Event &)>;
|
||||
|
||||
EventDispatcher();
|
||||
~EventDispatcher() = default;
|
||||
|
||||
// 添加监听器
|
||||
ListenerId addListener(EventType type, EventCallback callback);
|
||||
|
||||
// 移除监听器
|
||||
void removeListener(ListenerId id);
|
||||
void removeAllListeners(EventType type);
|
||||
void removeAllListeners();
|
||||
|
||||
// 分发事件
|
||||
void dispatch(Event &event);
|
||||
void dispatch(const Event &event);
|
||||
|
||||
// 处理事件队列
|
||||
void processQueue(class EventQueue &queue);
|
||||
|
||||
// 统计
|
||||
size_t getListenerCount(EventType type) const;
|
||||
size_t getTotalListenerCount() const;
|
||||
|
||||
private:
|
||||
struct Listener {
|
||||
ListenerId id;
|
||||
EventType type;
|
||||
EventCallback callback;
|
||||
};
|
||||
|
||||
std::unordered_map<EventType, std::vector<Listener>> listeners_;
|
||||
ListenerId nextId_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/event/event.h>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 事件队列 - 线程安全的事件队列
|
||||
// ============================================================================
|
||||
class EventQueue {
|
||||
public:
|
||||
EventQueue();
|
||||
~EventQueue() = default;
|
||||
|
||||
// 添加事件到队列
|
||||
void push(const Event &event);
|
||||
void push(Event &&event);
|
||||
|
||||
// 从队列取出事件
|
||||
bool poll(Event &event);
|
||||
|
||||
// 查看队列头部事件(不移除)
|
||||
bool peek(Event &event) const;
|
||||
|
||||
// 清空队列
|
||||
void clear();
|
||||
|
||||
// 队列状态
|
||||
bool empty() const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
std::queue<Event> queue_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// Extra2D - 统一入口头文件
|
||||
// 包含所有公共 API
|
||||
|
||||
// Core
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/core/registry.h>
|
||||
|
||||
// Config removed - app info now in Application class
|
||||
|
||||
// Platform
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/keys.h>
|
||||
#include <extra2d/platform/input_module.h>
|
||||
#include <extra2d/platform/backend_factory.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
|
||||
// Graphics
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/texture/font.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/graphics/core/render_target.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/graphics/texture/texture_pool.h>
|
||||
|
||||
// Scene
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
#include <extra2d/scene/scene_manager.h>
|
||||
#include <extra2d/scene/shape_node.h>
|
||||
#include <extra2d/scene/sprite.h>
|
||||
|
||||
// Event
|
||||
#include <extra2d/event/event.h>
|
||||
#include <extra2d/event/event_dispatcher.h>
|
||||
#include <extra2d/event/event_queue.h>
|
||||
|
||||
// Utils
|
||||
#include <extra2d/utils/random.h>
|
||||
#include <extra2d/utils/timer.h>
|
||||
|
||||
// Services
|
||||
#include <extra2d/services/event_service.h>
|
||||
#include <extra2d/services/scene_service.h>
|
||||
#include <extra2d/services/timer_service.h>
|
||||
#include <extra2d/services/camera_service.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
// Application
|
||||
#include <extra2d/app/application.h>
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/core/smart_ptr.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 渲染后端类型枚举
|
||||
*/
|
||||
enum class BackendType {
|
||||
OpenGL, // OpenGL 4.x
|
||||
Vulkan, // Vulkan 1.x
|
||||
Metal, // Metal (macOS/iOS)
|
||||
D3D11, // Direct3D 11
|
||||
D3D12, // Direct3D 12
|
||||
OpenGLES, // OpenGL ES (移动平台)
|
||||
Count
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 后端工厂类,用于创建渲染后端实例
|
||||
*/
|
||||
class BackendFactory {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取后端工厂单例
|
||||
* @return 后端工厂实例引用
|
||||
*/
|
||||
static BackendFactory& getInstance();
|
||||
|
||||
/**
|
||||
* @brief 创建渲染后端
|
||||
* @param type 后端类型
|
||||
* @return 渲染后端实例
|
||||
*/
|
||||
UniquePtr<RenderBackend> createBackend(BackendType type);
|
||||
|
||||
/**
|
||||
* @brief 创建默认渲染后端
|
||||
* @return 默认渲染后端实例
|
||||
*/
|
||||
UniquePtr<RenderBackend> createDefaultBackend();
|
||||
|
||||
/**
|
||||
* @brief 检查后端是否可用
|
||||
* @param type 后端类型
|
||||
* @return 可用返回true,否则返回false
|
||||
*/
|
||||
bool isBackendAvailable(BackendType type) const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前平台推荐的后端类型
|
||||
* @return 推荐的后端类型
|
||||
*/
|
||||
BackendType getRecommendedBackend() const;
|
||||
|
||||
/**
|
||||
* @brief 获取后端类型名称
|
||||
* @param type 后端类型
|
||||
* @return 后端类型名称字符串
|
||||
*/
|
||||
const char* getBackendName(BackendType type) const;
|
||||
|
||||
/**
|
||||
* @brief 从名称解析后端类型
|
||||
* @param name 后端类型名称
|
||||
* @return 后端类型,如果未知则返回OpenGL
|
||||
*/
|
||||
BackendType parseBackendType(const char* name) const;
|
||||
|
||||
private:
|
||||
BackendFactory() = default;
|
||||
~BackendFactory() = default;
|
||||
BackendFactory(const BackendFactory&) = delete;
|
||||
BackendFactory& operator=(const BackendFactory&) = delete;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/resources/buffer.h>
|
||||
#include <glad/glad.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 缓冲区实现
|
||||
// ============================================================================
|
||||
class GLBuffer : public Buffer {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLBuffer();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLBuffer() override;
|
||||
|
||||
/**
|
||||
* @brief 初始化缓冲区
|
||||
* @param desc 缓冲区描述
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init(const BufferDesc& desc);
|
||||
|
||||
/**
|
||||
* @brief 关闭缓冲区,释放资源
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
// Buffer 接口实现
|
||||
void bind() override;
|
||||
void unbind() override;
|
||||
void setData(const void* data, size_t size) override;
|
||||
void updateData(const void* data, size_t offset, size_t size) override;
|
||||
void* map() override;
|
||||
void unmap() override;
|
||||
size_t getSize() const override { return size_; }
|
||||
BufferType getType() const override { return type_; }
|
||||
BufferUsage getUsage() const override { return usage_; }
|
||||
bool isValid() const override { return bufferID_ != 0; }
|
||||
uintptr_t getNativeHandle() const override { return static_cast<uintptr_t>(bufferID_); }
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 缓冲区 ID
|
||||
* @return 缓冲区 ID
|
||||
*/
|
||||
GLuint getBufferID() const { return bufferID_; }
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 缓冲区目标类型
|
||||
* @return 缓冲区目标类型
|
||||
*/
|
||||
GLenum getTarget() const { return target_; }
|
||||
|
||||
private:
|
||||
GLuint bufferID_ = 0;
|
||||
GLenum target_ = GL_ARRAY_BUFFER;
|
||||
size_t size_ = 0;
|
||||
BufferType type_ = BufferType::Vertex;
|
||||
BufferUsage usage_ = BufferUsage::Static;
|
||||
GLenum glUsage_ = GL_STATIC_DRAW;
|
||||
bool mapped_ = false;
|
||||
void* mappedPtr_ = nullptr;
|
||||
|
||||
/**
|
||||
* @brief 转换使用模式到 OpenGL 枚举
|
||||
*/
|
||||
static GLenum convertUsage(BufferUsage usage);
|
||||
|
||||
/**
|
||||
* @brief 转换缓冲区类型到 OpenGL 目标
|
||||
*/
|
||||
static GLenum convertType(BufferType type);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 版本信息
|
||||
// ============================================================================
|
||||
struct GLVersion {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
bool es = false; // 是否为 ES 版本
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 上下文管理类
|
||||
// ============================================================================
|
||||
class GLContext {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取全局 GLContext 实例
|
||||
*/
|
||||
static GLContext& get();
|
||||
|
||||
/**
|
||||
* @brief 初始化 OpenGL 上下文
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭 OpenGL 上下文
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查上下文是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
bool isValid() const { return initialized_; }
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 版本信息
|
||||
*/
|
||||
const GLVersion& getVersion() const { return version_; }
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 版本字符串
|
||||
*/
|
||||
std::string getVersionString() const;
|
||||
|
||||
/**
|
||||
* @brief 获取 GPU 厂商信息
|
||||
*/
|
||||
std::string getVendor() const;
|
||||
|
||||
/**
|
||||
* @brief 获取 GPU 渲染器信息
|
||||
*/
|
||||
std::string getRenderer() const;
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持指定扩展
|
||||
* @param extension 扩展名称
|
||||
* @return 支持返回 true
|
||||
*/
|
||||
bool hasExtension(const std::string& extension) const;
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理尺寸
|
||||
*/
|
||||
int getMaxTextureSize() const;
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理单元数
|
||||
*/
|
||||
int getMaxTextureUnits() const;
|
||||
|
||||
/**
|
||||
* @brief 获取最大顶点属性数
|
||||
*/
|
||||
int getMaxVertexAttribs() const;
|
||||
|
||||
/**
|
||||
* @brief 获取最大 uniform 缓冲区绑定点数
|
||||
*/
|
||||
int getMaxUniformBufferBindings() const;
|
||||
|
||||
/**
|
||||
* @brief 检查是否为 OpenGL ES
|
||||
*/
|
||||
bool isGLES() const { return version_.es; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 VAO
|
||||
*/
|
||||
bool hasVAO() const;
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 FBO
|
||||
*/
|
||||
bool hasFBO() const;
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Shader
|
||||
*/
|
||||
bool hasShader() const;
|
||||
|
||||
private:
|
||||
GLContext() = default;
|
||||
~GLContext() = default;
|
||||
|
||||
GLContext(const GLContext&) = delete;
|
||||
GLContext& operator=(const GLContext&) = delete;
|
||||
|
||||
bool initialized_ = false;
|
||||
GLVersion version_;
|
||||
|
||||
// 缓存的限制值
|
||||
mutable int maxTextureSize_ = -1;
|
||||
mutable int maxTextureUnits_ = -1;
|
||||
mutable int maxVertexAttribs_ = -1;
|
||||
mutable int maxUniformBufferBindings_ = -1;
|
||||
|
||||
/**
|
||||
* @brief 解析 OpenGL 版本
|
||||
*/
|
||||
void parseVersion();
|
||||
|
||||
/**
|
||||
* @brief 加载 OpenGL 扩展
|
||||
*/
|
||||
bool loadExtensions();
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/backends/opengl/gl_texture.h>
|
||||
#include <extra2d/graphics/texture/font.h>
|
||||
|
||||
#include <stb/stb_truetype.h>
|
||||
#include <stb/stb_rect_pack.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 字体图集实现 (使用 STB 库)
|
||||
// 使用 stb_rect_pack 进行动态矩形打包,支持动态缓存字形
|
||||
// ============================================================================
|
||||
class GLFontAtlas : public FontAtlas {
|
||||
public:
|
||||
GLFontAtlas(const std::string& filepath, int fontSize, bool useSDF = false);
|
||||
~GLFontAtlas() override;
|
||||
|
||||
// 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 lineHeight_; }
|
||||
bool isSDF() const override { return useSDF_; }
|
||||
Vec2 measureText(const std::string& text) override;
|
||||
|
||||
private:
|
||||
// 字形数据内部结构
|
||||
struct GlyphData {
|
||||
float width;
|
||||
float height;
|
||||
float bearingX;
|
||||
float bearingY;
|
||||
float advance;
|
||||
float u0, v0, u1, v1;
|
||||
};
|
||||
|
||||
// 图集配置 - 增大尺寸以支持更多字符
|
||||
static constexpr int ATLAS_WIDTH = 1024;
|
||||
static constexpr int ATLAS_HEIGHT = 1024;
|
||||
static constexpr int PADDING = 2; // 字形之间的间距
|
||||
|
||||
bool useSDF_;
|
||||
int fontSize_;
|
||||
|
||||
Ptr<GLTexture> texture_;
|
||||
std::unordered_map<char32_t, GlyphData> glyphs_;
|
||||
float lineHeight_;
|
||||
float ascent_;
|
||||
float descent_;
|
||||
float lineGap_;
|
||||
|
||||
// 字体数据
|
||||
std::vector<unsigned char> fontData_;
|
||||
stbtt_fontinfo fontInfo_;
|
||||
float scale_;
|
||||
|
||||
// stb_rect_pack 上下文 - 持久化以支持增量打包
|
||||
mutable stbrp_context packContext_;
|
||||
mutable std::vector<stbrp_node> packNodes_;
|
||||
|
||||
// 预分配缓冲区,避免每次动态分配
|
||||
mutable std::vector<uint8_t> glyphBitmapCache_;
|
||||
mutable std::vector<uint8_t> glyphRgbaCache_;
|
||||
|
||||
// 初始化字体
|
||||
bool initFont(const std::string& filepath);
|
||||
// 创建空白图集纹理
|
||||
void createAtlas();
|
||||
// 缓存字形到图集
|
||||
void cacheGlyph(char32_t codepoint);
|
||||
// 更新图集纹理区域
|
||||
void updateAtlas(int x, int y, int width, int height,
|
||||
const std::vector<uint8_t>& data);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/resources/framebuffer.h>
|
||||
#include <glad/glad.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 帧缓冲实现
|
||||
// ============================================================================
|
||||
class GLFramebuffer : public Framebuffer {
|
||||
public:
|
||||
// 最大颜色附件数
|
||||
static constexpr int MAX_COLOR_ATTACHMENTS = 8;
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLFramebuffer();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLFramebuffer() override;
|
||||
|
||||
/**
|
||||
* @brief 初始化帧缓冲
|
||||
* @param desc 帧缓冲描述
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init(const FramebufferDesc& desc);
|
||||
|
||||
/**
|
||||
* @brief 关闭帧缓冲,释放资源
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
// Framebuffer 接口实现
|
||||
void bind() override;
|
||||
void unbind() override;
|
||||
void attachColorTexture(Ptr<Texture> texture, int attachment = 0) override;
|
||||
void attachDepthTexture(Ptr<Texture> texture) override;
|
||||
void attachDepthStencilTexture(Ptr<Texture> texture) override;
|
||||
bool isComplete() override;
|
||||
Ptr<Texture> getColorTexture(int attachment = 0) const override;
|
||||
Ptr<Texture> getDepthTexture() const override;
|
||||
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_)); }
|
||||
bool isValid() const override { return fboID_ != 0; }
|
||||
uintptr_t getNativeHandle() const override { return static_cast<uintptr_t>(fboID_); }
|
||||
void clear(const Color& color, bool clearColor = true,
|
||||
bool clearDepth = true, bool clearStencil = false) override;
|
||||
void setViewport(int x, int y, int width, int height) override;
|
||||
bool readPixels(int x, int y, int width, int height,
|
||||
std::vector<uint8_t>& outData) override;
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL FBO ID
|
||||
* @return FBO ID
|
||||
*/
|
||||
GLuint getFboID() const { return fboID_; }
|
||||
|
||||
/**
|
||||
* @brief 创建带内置纹理的帧缓冲(便捷方法)
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param colorFormat 颜色格式
|
||||
* @param depthFormat 深度格式(可选)
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool createWithTextures(int width, int height,
|
||||
PixelFormat colorFormat = PixelFormat::RGBA8,
|
||||
PixelFormat depthFormat = PixelFormat::Depth24);
|
||||
|
||||
private:
|
||||
GLuint fboID_ = 0;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
int numColorAttachments_ = 1;
|
||||
bool hasDepth_ = false;
|
||||
bool hasStencil_ = false;
|
||||
|
||||
// 附件纹理
|
||||
std::array<Ptr<Texture>, MAX_COLOR_ATTACHMENTS> colorTextures_;
|
||||
Ptr<Texture> depthTexture_;
|
||||
Ptr<Texture> depthStencilTexture_;
|
||||
|
||||
// 是否为内置纹理(需要自动清理)
|
||||
bool hasInternalTextures_ = false;
|
||||
|
||||
/**
|
||||
* @brief 检查并更新完整状态
|
||||
*/
|
||||
bool checkStatus();
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 附件枚举
|
||||
*/
|
||||
static GLenum getColorAttachment(int index);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/resources/pipeline.h>
|
||||
#include <glad/glad.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 管线状态实现
|
||||
// ============================================================================
|
||||
class GLPipeline : public Pipeline {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLPipeline();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLPipeline() override;
|
||||
|
||||
/**
|
||||
* @brief 初始化管线
|
||||
* @param desc 管线描述
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init(const PipelineDesc& desc);
|
||||
|
||||
/**
|
||||
* @brief 关闭管线,释放资源
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
// Pipeline 接口实现
|
||||
void bind() override;
|
||||
void unbind() override;
|
||||
void setBlendMode(BlendMode mode) override;
|
||||
BlendMode getBlendMode() const override { return blendMode_; }
|
||||
void setDepthTest(bool enabled) override;
|
||||
void setDepthWrite(bool enabled) override;
|
||||
void setDepthFunc(DepthFunc func) override;
|
||||
void setCullMode(CullMode mode) override;
|
||||
bool isValid() const override { return initialized_; }
|
||||
uintptr_t getNativeHandle() const override { return 0; } // OpenGL 管线没有单一句柄
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
* @param x 视口左下角X坐标
|
||||
* @param y 视口左下角Y坐标
|
||||
* @param width 视口宽度
|
||||
* @param height 视口高度
|
||||
*/
|
||||
void setViewport(int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 获取当前视口
|
||||
* @param x 输出X坐标
|
||||
* @param y 输出Y坐标
|
||||
* @param width 输出宽度
|
||||
* @param height 输出高度
|
||||
*/
|
||||
void getViewport(int& x, int& y, int& width, int& height) const;
|
||||
|
||||
/**
|
||||
* @brief 应用所有状态(用于初始化或重置)
|
||||
*/
|
||||
void applyAllStates();
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
|
||||
// 当前状态
|
||||
BlendMode blendMode_ = BlendMode::Alpha;
|
||||
bool blendEnabled_ = true;
|
||||
bool depthTest_ = false;
|
||||
bool depthWrite_ = false;
|
||||
DepthFunc depthFunc_ = DepthFunc::Less;
|
||||
CullMode cullMode_ = CullMode::None;
|
||||
|
||||
// 视口
|
||||
int viewportX_ = 0;
|
||||
int viewportY_ = 0;
|
||||
int viewportWidth_ = 0;
|
||||
int viewportHeight_ = 0;
|
||||
|
||||
// 状态缓存(避免冗余 GL 调用)
|
||||
BlendMode cachedBlendMode_ = BlendMode::None;
|
||||
bool cachedBlendEnabled_ = false;
|
||||
bool cachedDepthTest_ = false;
|
||||
bool cachedDepthWrite_ = false;
|
||||
DepthFunc cachedDepthFunc_ = DepthFunc::Less;
|
||||
CullMode cachedCullMode_ = CullMode::None;
|
||||
int cachedViewportX_ = -1;
|
||||
int cachedViewportY_ = -1;
|
||||
int cachedViewportWidth_ = -1;
|
||||
int cachedViewportHeight_ = -1;
|
||||
|
||||
/**
|
||||
* @brief 应用混合状态
|
||||
*/
|
||||
void applyBlendState();
|
||||
|
||||
/**
|
||||
* @brief 应用深度状态
|
||||
*/
|
||||
void applyDepthState();
|
||||
|
||||
/**
|
||||
* @brief 应用裁剪状态
|
||||
*/
|
||||
void applyCullState();
|
||||
|
||||
/**
|
||||
* @brief 转换混合模式到 OpenGL 枚举
|
||||
*/
|
||||
static void getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstFactor);
|
||||
|
||||
/**
|
||||
* @brief 转换深度函数到 OpenGL 枚举
|
||||
*/
|
||||
static GLenum convertDepthFunc(DepthFunc func);
|
||||
|
||||
/**
|
||||
* @brief 转换裁剪模式到 OpenGL 枚举
|
||||
*/
|
||||
static GLenum convertCullMode(CullMode mode);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_pipeline.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_sprite_batch.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/shader/shader_interface.h>
|
||||
|
||||
#include <array>
|
||||
#include <glad/glad.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
class IWindow;
|
||||
class GLContext;
|
||||
class GLFramebuffer;
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 渲染器实现
|
||||
// ============================================================================
|
||||
class GLRenderer : public RenderBackend {
|
||||
public:
|
||||
GLRenderer();
|
||||
~GLRenderer() override;
|
||||
|
||||
// RenderBackend 接口实现
|
||||
bool init(IWindow* window) override;
|
||||
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;
|
||||
void flush() override;
|
||||
|
||||
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;
|
||||
|
||||
// GLFramebuffer 相关方法
|
||||
|
||||
/**
|
||||
* @brief 创建帧缓冲对象
|
||||
* @param desc 帧缓冲描述
|
||||
* @return 创建的帧缓冲智能指针
|
||||
*/
|
||||
Ptr<GLFramebuffer> createFramebuffer(const FramebufferDesc& desc);
|
||||
|
||||
/**
|
||||
* @brief 绑定帧缓冲(作为渲染目标)
|
||||
* @param framebuffer 帧缓冲对象指针,传入 nullptr 则绑定默认帧缓冲
|
||||
*/
|
||||
void bindFramebuffer(GLFramebuffer* framebuffer);
|
||||
|
||||
/**
|
||||
* @brief 解绑帧缓冲(恢复到默认帧缓冲)
|
||||
*/
|
||||
void unbindFramebuffer();
|
||||
|
||||
/**
|
||||
* @brief 获取默认帧缓冲
|
||||
* @return 默认帧缓冲智能指针
|
||||
*/
|
||||
Ptr<GLFramebuffer> getDefaultFramebuffer() const;
|
||||
|
||||
/**
|
||||
* @brief 清除当前绑定的帧缓冲
|
||||
* @param color 清除颜色
|
||||
* @param clearColor 是否清除颜色缓冲
|
||||
* @param clearDepth 是否清除深度缓冲
|
||||
* @param clearStencil 是否清除模板缓冲
|
||||
*/
|
||||
void clearFramebuffer(const Color& color, bool clearColor = true,
|
||||
bool clearDepth = true, bool clearStencil = false);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
IWindow* window_;
|
||||
GLSpriteBatch spriteBatch_;
|
||||
Ptr<IShader> shapeShader_;
|
||||
|
||||
GLuint shapeVao_; // 形状 VAO(手动管理,用于顶点属性配置)
|
||||
GLBuffer shapeBuffer_; // 形状 VBO(使用 GLBuffer 管理)
|
||||
GLuint lineVao_; // 线条 VAO(手动管理,用于顶点属性配置)
|
||||
GLBuffer lineBuffer_; // 线条 VBO(使用 GLBuffer 管理)
|
||||
|
||||
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;
|
||||
|
||||
// 线条批处理缓冲区
|
||||
std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_;
|
||||
size_t lineVertexCount_ = 0;
|
||||
float currentLineWidth_ = 1.0f;
|
||||
|
||||
// OpenGL 管线状态管理
|
||||
GLPipeline pipeline_;
|
||||
|
||||
// 自动批处理状态
|
||||
bool batchActive_ = false; // 批处理是否激活
|
||||
bool autoBatchEnabled_ = true; // 是否启用自动批处理
|
||||
const Texture* currentBatchTexture_ = nullptr; // 当前批处理的纹理
|
||||
std::vector<SpriteData> pendingSprites_; // 待提交的精灵
|
||||
static constexpr size_t MAX_BATCH_SPRITES = 1000; // 最大批处理精灵数
|
||||
|
||||
// 帧缓冲管理
|
||||
mutable Ptr<GLFramebuffer> defaultFramebuffer_; // 默认帧缓冲(延迟创建)
|
||||
GLFramebuffer* currentFramebuffer_ = nullptr; // 当前绑定的帧缓冲
|
||||
|
||||
void initShapeRendering();
|
||||
void ensureBatchActive(); // 确保批处理已激活
|
||||
void submitPendingSprites(); // 提交待处理的精灵
|
||||
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 extra2d
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/shader/shader_interface.h>
|
||||
#include <glad/glad.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
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 extra2d
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_texture.h>
|
||||
#include <extra2d/graphics/batch/sprite_batch.h>
|
||||
#include <extra2d/graphics/shader/shader_interface.h>
|
||||
|
||||
#include <array>
|
||||
#include <glad/glad.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// OpenGL 精灵批处理渲染器
|
||||
// 使用 batch/sprite_batch 作为后端无关的批处理层
|
||||
// ============================================================================
|
||||
class GLSpriteBatch {
|
||||
public:
|
||||
GLSpriteBatch();
|
||||
~GLSpriteBatch();
|
||||
|
||||
// 初始化/关闭
|
||||
bool init();
|
||||
void shutdown();
|
||||
|
||||
// 批处理生命周期
|
||||
void begin(const glm::mat4& viewProjection);
|
||||
void end();
|
||||
|
||||
// 绘制单个精灵
|
||||
void draw(const Texture& texture, const SpriteData& data);
|
||||
|
||||
// 批量绘制(用于文本渲染优化)
|
||||
void drawBatch(const Texture& texture, const std::vector<SpriteData>& sprites);
|
||||
|
||||
// 获取绘制调用次数
|
||||
uint32_t getDrawCallCount() const { return drawCallCount_; }
|
||||
|
||||
private:
|
||||
// OpenGL 对象
|
||||
GLuint vao_;
|
||||
GLBuffer vbo_; // 顶点缓冲区(动态)
|
||||
GLBuffer ebo_; // 索引缓冲区(静态)
|
||||
|
||||
// 后端无关的批处理层
|
||||
SpriteBatch batch_;
|
||||
|
||||
// 批次管理
|
||||
struct Batch {
|
||||
const GLTexture* texture;
|
||||
size_t startVertex;
|
||||
size_t vertexCount;
|
||||
};
|
||||
std::vector<Batch> batches_;
|
||||
const GLTexture* currentTexture_;
|
||||
|
||||
// 着色器和矩阵
|
||||
Ptr<IShader> shader_;
|
||||
uint32_t drawCallCount_;
|
||||
glm::mat4 viewProjection_;
|
||||
|
||||
// 内部方法
|
||||
void flush();
|
||||
void submitBatch();
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/graphics/texture/alpha_mask.h>
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 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 extra2d
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief Vulkan 渲染器实现(占位)
|
||||
*
|
||||
* 这是一个占位实现,用于展示Vulkan后端应该包含的内容。
|
||||
* 完整的实现需要包含Vulkan上下文、设备、交换链、管线等。
|
||||
*/
|
||||
class VulkanRenderer : public RenderBackend {
|
||||
public:
|
||||
VulkanRenderer();
|
||||
~VulkanRenderer() override;
|
||||
|
||||
// RenderBackend 接口实现
|
||||
bool init(IWindow* window) override;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
Stats stats_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 形状顶点结构
|
||||
// ============================================================================
|
||||
struct ShapeVertex {
|
||||
float x, y; // 位置
|
||||
float r, g, b, a; // 颜色
|
||||
|
||||
ShapeVertex() = default;
|
||||
ShapeVertex(float px, float py, const Color& c)
|
||||
: x(px), y(py), r(c.r), g(c.g), b(c.b), a(c.a) {}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 形状批处理抽象接口 - 后端无关
|
||||
// ============================================================================
|
||||
class ShapeBatch {
|
||||
public:
|
||||
virtual ~ShapeBatch() = default;
|
||||
|
||||
/**
|
||||
* @brief 初始化形状批处理
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
virtual bool init() = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭形状批处理,释放资源
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 开始批处理
|
||||
* @param viewProjection 视图投影矩阵
|
||||
*/
|
||||
virtual void begin(const glm::mat4& viewProjection) = 0;
|
||||
|
||||
/**
|
||||
* @brief 结束批处理并提交绘制
|
||||
*/
|
||||
virtual void end() = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
* @param start 起点
|
||||
* @param end 终点
|
||||
* @param color 颜色
|
||||
* @param width 线宽
|
||||
*/
|
||||
virtual void drawLine(const Vec2& start, const Vec2& end,
|
||||
const Color& color, float width = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形边框
|
||||
* @param rect 矩形区域
|
||||
* @param color 颜色
|
||||
* @param width 边框宽度
|
||||
*/
|
||||
virtual void drawRect(const Rect& rect, const Color& color,
|
||||
float width = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 填充矩形
|
||||
* @param rect 矩形区域
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void fillRect(const Rect& rect, const Color& color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形边框
|
||||
* @param center 圆心
|
||||
* @param radius 半径
|
||||
* @param color 颜色
|
||||
* @param segments 分段数
|
||||
* @param width 边框宽度
|
||||
*/
|
||||
virtual void drawCircle(const Vec2& center, float radius,
|
||||
const Color& color, int segments = 32,
|
||||
float width = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 填充圆形
|
||||
* @param center 圆心
|
||||
* @param radius 半径
|
||||
* @param color 颜色
|
||||
* @param segments 分段数
|
||||
*/
|
||||
virtual void fillCircle(const Vec2& center, float radius,
|
||||
const Color& color, int segments = 32) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制三角形边框
|
||||
* @param p1 顶点1
|
||||
* @param p2 顶点2
|
||||
* @param p3 顶点3
|
||||
* @param color 颜色
|
||||
* @param width 边框宽度
|
||||
*/
|
||||
virtual void drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
||||
const Color& color, float width = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 填充三角形
|
||||
* @param p1 顶点1
|
||||
* @param p2 顶点2
|
||||
* @param p3 顶点3
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void fillTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
||||
const Color& color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形边框
|
||||
* @param points 顶点数组
|
||||
* @param color 颜色
|
||||
* @param width 边框宽度
|
||||
*/
|
||||
virtual void drawPolygon(const std::vector<Vec2>& points,
|
||||
const Color& color, float width = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 填充多边形
|
||||
* @param points 顶点数组
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void fillPolygon(const std::vector<Vec2>& points,
|
||||
const Color& color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取绘制调用次数
|
||||
* @return 绘制调用次数
|
||||
*/
|
||||
virtual uint32_t getDrawCallCount() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 重置绘制调用计数
|
||||
*/
|
||||
virtual void resetDrawCallCount() = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 三角函数查表 - 避免每帧计算 sin/cos
|
||||
// ============================================================================
|
||||
class TrigLookup {
|
||||
public:
|
||||
TrigLookup();
|
||||
|
||||
// 通过角度(0-360)获取 sin/cos
|
||||
float sin(int angle) const;
|
||||
float cos(int angle) const;
|
||||
|
||||
// 通过弧度获取 sin/cos
|
||||
float sinRad(float rad) const;
|
||||
float cosRad(float rad) const;
|
||||
|
||||
private:
|
||||
static constexpr int TABLE_SIZE = 360 * 4; // 0.25度精度
|
||||
std::array<float, TABLE_SIZE> sinTable_;
|
||||
std::array<float, TABLE_SIZE> cosTable_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 精灵批次数据 - 后端无关
|
||||
// ============================================================================
|
||||
struct SpriteVertex {
|
||||
Vec2 position;
|
||||
Vec2 texCoord;
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct SpriteData {
|
||||
Vec2 position;
|
||||
Vec2 size;
|
||||
float rotation;
|
||||
Vec2 pivot;
|
||||
Color color;
|
||||
const Texture* texture;
|
||||
Rect uvRect;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 通用精灵批处理 - 后端无关
|
||||
// 负责:顶点生成、批次管理、三角函数查表
|
||||
// ============================================================================
|
||||
class SpriteBatch {
|
||||
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;
|
||||
|
||||
SpriteBatch();
|
||||
~SpriteBatch() = default;
|
||||
|
||||
// 开始批次
|
||||
void begin(const glm::mat4& viewProjection);
|
||||
|
||||
// 结束批次 - 返回需要绘制的批次列表
|
||||
void end();
|
||||
|
||||
// 绘制单个精灵
|
||||
void draw(const SpriteData& sprite);
|
||||
|
||||
// 批量绘制 - 一次性处理多个精灵
|
||||
void drawBatch(const std::vector<SpriteData>& sprites);
|
||||
|
||||
// 立即绘制 - 不缓存,直接提交
|
||||
void drawImmediate(const SpriteData& sprite);
|
||||
|
||||
// 获取当前批次数据
|
||||
const std::vector<SpriteVertex>& getVertices() const { return vertices_; }
|
||||
const std::vector<uint16_t>& getIndices() const { return indices_; }
|
||||
size_t getSpriteCount() const { return spriteCount_; }
|
||||
|
||||
// 检查是否需要刷新
|
||||
bool needsFlush() const { return spriteCount_ >= MAX_SPRITES; }
|
||||
|
||||
// 清空批次
|
||||
void clear();
|
||||
|
||||
private:
|
||||
// 三角函数查表
|
||||
TrigLookup trigLookup_;
|
||||
|
||||
// 顶点数据 - 使用固定大小数组避免动态分配
|
||||
std::vector<SpriteVertex> vertices_;
|
||||
std::vector<uint16_t> indices_;
|
||||
size_t spriteCount_;
|
||||
|
||||
// 变换矩阵
|
||||
glm::mat4 viewProjection_;
|
||||
glm::mat4 cachedVP_;
|
||||
bool vpDirty_;
|
||||
|
||||
// 生成索引
|
||||
void generateIndices();
|
||||
|
||||
// 生成顶点
|
||||
void generateVertices(const SpriteData& sprite, size_t vertexOffset);
|
||||
|
||||
// 刷新批次
|
||||
void flush();
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class ViewportAdapter;
|
||||
|
||||
// ============================================================================
|
||||
// 2D 正交相机
|
||||
// ============================================================================
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
Camera(float left, float right, float bottom, float top);
|
||||
Camera(const Size &viewport);
|
||||
~Camera() = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 位置和变换
|
||||
// ------------------------------------------------------------------------
|
||||
void setPos(const Vec2 &position);
|
||||
void setPos(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();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 视口适配器
|
||||
// ------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 设置视口适配器
|
||||
* @param adapter 视口适配器指针
|
||||
*/
|
||||
void setViewportAdapter(ViewportAdapter *adapter);
|
||||
|
||||
/**
|
||||
* @brief 根据视口适配器自动设置视口
|
||||
*/
|
||||
void applyViewportAdapter();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 快捷方法:看向某点
|
||||
// ------------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
ViewportAdapter *viewportAdapter_ = nullptr;
|
||||
|
||||
mutable glm::mat4 viewMatrix_;
|
||||
mutable glm::mat4 projMatrix_;
|
||||
mutable glm::mat4 vpMatrix_;
|
||||
mutable bool viewDirty_ = true;
|
||||
mutable bool projDirty_ = true;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,332 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 视口适配模式枚举
|
||||
// ============================================================================
|
||||
enum class ViewportMode {
|
||||
AspectRatio,
|
||||
Stretch,
|
||||
Center,
|
||||
Custom
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 黑边位置枚举
|
||||
// ============================================================================
|
||||
enum class LetterboxPosition {
|
||||
Center,
|
||||
LeftTop,
|
||||
RightTop,
|
||||
LeftBottom,
|
||||
RightBottom
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 视口配置结构体
|
||||
// ============================================================================
|
||||
struct ViewportConfig {
|
||||
float logicWidth = 1920.0f;
|
||||
float logicHeight = 1080.0f;
|
||||
ViewportMode mode = ViewportMode::AspectRatio;
|
||||
LetterboxPosition letterboxPosition = LetterboxPosition::Center;
|
||||
Color letterboxColor = Colors::Black;
|
||||
bool autoScaleInCenterMode = true;
|
||||
float customScale = 1.0f;
|
||||
Vec2 customOffset = Vec2::Zero();
|
||||
Rect customViewport = Rect::Zero();
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 视口计算结果结构体
|
||||
// ============================================================================
|
||||
struct ViewportResult {
|
||||
Rect viewport;
|
||||
float scaleX = 1.0f;
|
||||
float scaleY = 1.0f;
|
||||
float uniformScale = 1.0f;
|
||||
Vec2 offset;
|
||||
bool hasLetterbox = false;
|
||||
|
||||
struct Letterbox {
|
||||
Rect top;
|
||||
Rect bottom;
|
||||
Rect left;
|
||||
Rect right;
|
||||
} letterbox;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 视口适配器类
|
||||
// ============================================================================
|
||||
class ViewportAdapter {
|
||||
public:
|
||||
ViewportAdapter();
|
||||
ViewportAdapter(float logicWidth, float logicHeight);
|
||||
~ViewportAdapter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 配置设置
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 设置视口配置
|
||||
* @param config 视口配置结构体
|
||||
*/
|
||||
void setConfig(const ViewportConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 获取当前视口配置
|
||||
* @return 当前视口配置
|
||||
*/
|
||||
const ViewportConfig &getConfig() const { return config_; }
|
||||
|
||||
/**
|
||||
* @brief 设置逻辑分辨率
|
||||
* @param width 逻辑宽度
|
||||
* @param height 逻辑高度
|
||||
*/
|
||||
void setLogicSize(float width, float height);
|
||||
|
||||
/**
|
||||
* @brief 设置视口适配模式
|
||||
* @param mode 适配模式
|
||||
*/
|
||||
void setMode(ViewportMode mode);
|
||||
|
||||
/**
|
||||
* @brief 设置黑边位置
|
||||
* @param position 黑边位置
|
||||
*/
|
||||
void setLetterboxPosition(LetterboxPosition position);
|
||||
|
||||
/**
|
||||
* @brief 设置黑边颜色
|
||||
* @param color 黑边颜色
|
||||
*/
|
||||
void setLetterboxColor(const Color &color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 更新和计算
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 更新视口适配计算
|
||||
* @param screenWidth 屏幕宽度
|
||||
* @param screenHeight 屏幕高度
|
||||
*/
|
||||
void update(int screenWidth, int screenHeight);
|
||||
|
||||
/**
|
||||
* @brief 获取计算结果
|
||||
* @return 视口计算结果
|
||||
*/
|
||||
const ViewportResult &getResult() const { return result_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 坐标转换
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 屏幕坐标转逻辑坐标
|
||||
* @param screenPos 屏幕坐标
|
||||
* @return 逻辑坐标
|
||||
*/
|
||||
Vec2 screenToLogic(const Vec2 &screenPos) const;
|
||||
|
||||
/**
|
||||
* @brief 逻辑坐标转屏幕坐标
|
||||
* @param logicPos 逻辑坐标
|
||||
* @return 屏幕坐标
|
||||
*/
|
||||
Vec2 logicToScreen(const Vec2 &logicPos) const;
|
||||
|
||||
/**
|
||||
* @brief 屏幕坐标转逻辑坐标(分量形式)
|
||||
* @param x 屏幕X坐标
|
||||
* @param y 屏幕Y坐标
|
||||
* @return 逻辑坐标
|
||||
*/
|
||||
Vec2 screenToLogic(float x, float y) const;
|
||||
|
||||
/**
|
||||
* @brief 逻辑坐标转屏幕坐标(分量形式)
|
||||
* @param x 逻辑X坐标
|
||||
* @param y 逻辑Y坐标
|
||||
* @return 屏幕坐标
|
||||
*/
|
||||
Vec2 logicToScreen(float x, float y) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 矩阵获取
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取视口变换矩阵
|
||||
* @return 视口变换矩阵(从逻辑坐标到屏幕坐标)
|
||||
*/
|
||||
glm::mat4 getMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 获取反向视口变换矩阵
|
||||
* @return 反向视口变换矩阵(从屏幕坐标到逻辑坐标)
|
||||
*/
|
||||
glm::mat4 getInvMatrix() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 区域检测
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 检查屏幕坐标是否在视口内
|
||||
* @param screenPos 屏幕坐标
|
||||
* @return 如果在视口内返回 true
|
||||
*/
|
||||
bool isInViewport(const Vec2 &screenPos) const;
|
||||
|
||||
/**
|
||||
* @brief 检查屏幕坐标是否在黑边区域
|
||||
* @param screenPos 屏幕坐标
|
||||
* @return 如果在黑边区域返回 true
|
||||
*/
|
||||
bool isInLetterbox(const Vec2 &screenPos) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Getter 方法
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取逻辑宽度
|
||||
* @return 逻辑宽度
|
||||
*/
|
||||
float getLogicWidth() const { return config_.logicWidth; }
|
||||
|
||||
/**
|
||||
* @brief 获取逻辑高度
|
||||
* @return 逻辑高度
|
||||
*/
|
||||
float getLogicHeight() const { return config_.logicHeight; }
|
||||
|
||||
/**
|
||||
* @brief 获取逻辑尺寸
|
||||
* @return 逻辑尺寸
|
||||
*/
|
||||
Size getLogicSize() const {
|
||||
return Size(config_.logicWidth, config_.logicHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕宽度
|
||||
* @return 屏幕宽度
|
||||
*/
|
||||
int getScreenWidth() const { return screenWidth_; }
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕高度
|
||||
* @return 屏幕高度
|
||||
*/
|
||||
int getScreenHeight() const { return screenHeight_; }
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕尺寸
|
||||
* @return 屏幕尺寸
|
||||
*/
|
||||
Size getScreenSize() const {
|
||||
return Size(static_cast<float>(screenWidth_),
|
||||
static_cast<float>(screenHeight_));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取X方向缩放比例
|
||||
* @return X方向缩放比例
|
||||
*/
|
||||
float getScaleX() const { return result_.scaleX; }
|
||||
|
||||
/**
|
||||
* @brief 获取Y方向缩放比例
|
||||
* @return Y方向缩放比例
|
||||
*/
|
||||
float getScaleY() const { return result_.scaleY; }
|
||||
|
||||
/**
|
||||
* @brief 获取统一缩放比例
|
||||
* @return 统一缩放比例
|
||||
*/
|
||||
float getUniformScale() const { return result_.uniformScale; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口偏移
|
||||
* @return 视口偏移
|
||||
*/
|
||||
Vec2 getOffset() const { return result_.offset; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口矩形
|
||||
* @return 视口矩形
|
||||
*/
|
||||
Rect getViewport() const { return result_.viewport; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否有黑边
|
||||
* @return 如果有黑边返回 true
|
||||
*/
|
||||
bool hasLetterbox() const { return result_.hasLetterbox; }
|
||||
|
||||
/**
|
||||
* @brief 获取黑边信息
|
||||
* @return 黑边信息结构体
|
||||
*/
|
||||
const ViewportResult::Letterbox &getLetterbox() const {
|
||||
return result_.letterbox;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 计算宽高比适配模式
|
||||
*/
|
||||
void calculateAspectRatio();
|
||||
|
||||
/**
|
||||
* @brief 计算拉伸适配模式
|
||||
*/
|
||||
void calculateStretch();
|
||||
|
||||
/**
|
||||
* @brief 计算居中适配模式
|
||||
*/
|
||||
void calculateCenter();
|
||||
|
||||
/**
|
||||
* @brief 计算自定义适配模式
|
||||
*/
|
||||
void calculateCustom();
|
||||
|
||||
/**
|
||||
* @brief 计算黑边区域
|
||||
*/
|
||||
void calculateLetterbox();
|
||||
|
||||
/**
|
||||
* @brief 根据黑边位置调整偏移
|
||||
* @param extraWidth 额外宽度
|
||||
* @param extraHeight 额外高度
|
||||
*/
|
||||
void applyLetterboxPosition(float extraWidth, float extraHeight);
|
||||
|
||||
ViewportConfig config_;
|
||||
ViewportResult result_;
|
||||
int screenWidth_ = 0;
|
||||
int screenHeight_ = 0;
|
||||
|
||||
mutable glm::mat4 viewportMatrix_;
|
||||
mutable glm::mat4 inverseViewportMatrix_;
|
||||
mutable bool matrixDirty_ = true;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/resources/pipeline.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
class IWindow;
|
||||
class Texture;
|
||||
class FontAtlas;
|
||||
class Shader;
|
||||
|
||||
// ============================================================================
|
||||
// 渲染后端类型
|
||||
// ============================================================================
|
||||
enum class BackendType {
|
||||
OpenGL,
|
||||
// Vulkan,
|
||||
// Metal,
|
||||
// D3D11,
|
||||
// D3D12
|
||||
};
|
||||
|
||||
// BlendMode 定义在 pipeline.h 中
|
||||
|
||||
// ============================================================================
|
||||
// 渲染后端抽象接口
|
||||
// ============================================================================
|
||||
class RenderBackend {
|
||||
public:
|
||||
virtual ~RenderBackend() = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 生命周期
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool init(IWindow* window) = 0;
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 帧管理
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void beginFrame(const Color &clearColor) = 0;
|
||||
virtual void endFrame() = 0;
|
||||
virtual void setViewport(int x, int y, int width, int height) = 0;
|
||||
virtual void setVSync(bool enabled) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 状态设置
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void setBlendMode(BlendMode mode) = 0;
|
||||
virtual void setViewProjection(const glm::mat4 &matrix) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 变换矩阵栈
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void pushTransform(const glm::mat4 &transform) = 0;
|
||||
virtual void popTransform() = 0;
|
||||
virtual glm::mat4 getCurrentTransform() const = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 纹理
|
||||
// ------------------------------------------------------------------------
|
||||
virtual Ptr<Texture> createTexture(int width, int height,
|
||||
const uint8_t *pixels, int channels) = 0;
|
||||
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 精灵批渲染
|
||||
// ------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 开始手动精灵批处理(高级用法)
|
||||
* @note 一般情况下不需要调用,drawSprite/drawText 会自动管理批处理
|
||||
*/
|
||||
virtual void beginSpriteBatch() = 0;
|
||||
virtual void drawSprite(const Texture &texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Color &tint,
|
||||
float rotation, const Vec2 &anchor) = 0;
|
||||
virtual void drawSprite(const Texture &texture, const Vec2 &position,
|
||||
const Color &tint) = 0;
|
||||
virtual void endSpriteBatch() = 0;
|
||||
|
||||
/**
|
||||
* @brief 立即提交当前批处理
|
||||
* @note 手动控制批处理提交时机,一般情况下不需要调用
|
||||
*/
|
||||
virtual void flush() = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 形状渲染
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float width = 1.0f) = 0;
|
||||
virtual void drawRect(const Rect &rect, const Color &color,
|
||||
float width = 1.0f) = 0;
|
||||
virtual void fillRect(const Rect &rect, const Color &color) = 0;
|
||||
virtual void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
int segments = 32, float width = 1.0f) = 0;
|
||||
virtual void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
int segments = 32) = 0;
|
||||
virtual void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||
const Color &color, float width = 1.0f) = 0;
|
||||
virtual void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||
const Color &color) = 0;
|
||||
virtual void drawPolygon(const std::vector<Vec2> &points, const Color &color,
|
||||
float width = 1.0f) = 0;
|
||||
virtual void fillPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 文字渲染
|
||||
// ------------------------------------------------------------------------
|
||||
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath,
|
||||
int fontSize, bool useSDF = false) = 0;
|
||||
virtual void drawText(const FontAtlas &font, const std::string &text,
|
||||
const Vec2 &position, const Color &color) = 0;
|
||||
virtual void drawText(const FontAtlas &font, const std::string &text, float x,
|
||||
float y, const Color &color) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 统计信息
|
||||
// ------------------------------------------------------------------------
|
||||
struct Stats {
|
||||
uint32_t drawCalls = 0;
|
||||
uint32_t triangleCount = 0;
|
||||
uint32_t textureBinds = 0;
|
||||
uint32_t shaderBinds = 0;
|
||||
};
|
||||
virtual Stats getStats() const = 0;
|
||||
virtual void resetStats() = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 工厂方法
|
||||
// ------------------------------------------------------------------------
|
||||
static UniquePtr<RenderBackend> create(BackendType type);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
class Texture;
|
||||
class FontAtlas;
|
||||
|
||||
/**
|
||||
* @brief 渲染命令类型枚举
|
||||
*/
|
||||
enum class RenderCommandType : uint8_t {
|
||||
None = 0,
|
||||
Sprite, // 精灵绘制
|
||||
Line, // 线条绘制
|
||||
Rect, // 矩形绘制
|
||||
FilledRect, // 填充矩形
|
||||
Circle, // 圆形绘制
|
||||
FilledCircle, // 填充圆形
|
||||
Triangle, // 三角形绘制
|
||||
FilledTriangle, // 填充三角形
|
||||
Polygon, // 多边形绘制
|
||||
FilledPolygon, // 填充多边形
|
||||
Text, // 文本绘制
|
||||
Custom // 自定义绘制
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 精灵渲染命令数据
|
||||
*/
|
||||
struct SpriteCommandData {
|
||||
const Texture* texture;
|
||||
Rect destRect;
|
||||
Rect srcRect;
|
||||
Color tint;
|
||||
float rotation;
|
||||
Vec2 anchor;
|
||||
uint32_t sortKey; // 用于自动排序的键值
|
||||
|
||||
SpriteCommandData()
|
||||
: texture(nullptr), destRect(), srcRect(), tint(Colors::White),
|
||||
rotation(0.0f), anchor(0.0f, 0.0f), sortKey(0) {}
|
||||
SpriteCommandData(const Texture* tex, const Rect& dest, const Rect& src,
|
||||
const Color& t, float rot, const Vec2& anc, uint32_t key)
|
||||
: texture(tex), destRect(dest), srcRect(src), tint(t),
|
||||
rotation(rot), anchor(anc), sortKey(key) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 线条渲染命令数据
|
||||
*/
|
||||
struct LineCommandData {
|
||||
Vec2 start;
|
||||
Vec2 end;
|
||||
Color color;
|
||||
float width;
|
||||
|
||||
LineCommandData() : start(), end(), color(Colors::White), width(1.0f) {}
|
||||
LineCommandData(const Vec2& s, const Vec2& e, const Color& c, float w)
|
||||
: start(s), end(e), color(c), width(w) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 矩形渲染命令数据
|
||||
*/
|
||||
struct RectCommandData {
|
||||
Rect rect;
|
||||
Color color;
|
||||
float width;
|
||||
bool filled;
|
||||
|
||||
RectCommandData() : rect(), color(Colors::White), width(1.0f), filled(false) {}
|
||||
RectCommandData(const Rect& r, const Color& c, float w, bool f)
|
||||
: rect(r), color(c), width(w), filled(f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 圆形渲染命令数据
|
||||
*/
|
||||
struct CircleCommandData {
|
||||
Vec2 center;
|
||||
float radius;
|
||||
Color color;
|
||||
int segments;
|
||||
float width;
|
||||
bool filled;
|
||||
|
||||
CircleCommandData() : center(), radius(0.0f), color(Colors::White),
|
||||
segments(32), width(1.0f), filled(false) {}
|
||||
CircleCommandData(const Vec2& c, float r, const Color& col, int seg, float w, bool f)
|
||||
: center(c), radius(r), color(col), segments(seg), width(w), filled(f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 三角形渲染命令数据
|
||||
*/
|
||||
struct TriangleCommandData {
|
||||
Vec2 p1, p2, p3;
|
||||
Color color;
|
||||
float width;
|
||||
bool filled;
|
||||
|
||||
TriangleCommandData() : p1(), p2(), p3(), color(Colors::White),
|
||||
width(1.0f), filled(false) {}
|
||||
TriangleCommandData(const Vec2& a, const Vec2& b, const Vec2& c, const Color& col, float w, bool f)
|
||||
: p1(a), p2(b), p3(c), color(col), width(w), filled(f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 多边形渲染命令数据
|
||||
*/
|
||||
struct PolygonCommandData {
|
||||
std::vector<Vec2> points;
|
||||
Color color;
|
||||
float width;
|
||||
bool filled;
|
||||
|
||||
PolygonCommandData() : color(Colors::White), width(1.0f), filled(false) {}
|
||||
PolygonCommandData(std::vector<Vec2> pts, const Color& col, float w, bool f)
|
||||
: points(std::move(pts)), color(col), width(w), filled(f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 文本渲染命令数据
|
||||
*/
|
||||
struct TextCommandData {
|
||||
const FontAtlas* font;
|
||||
std::string text;
|
||||
Vec2 position;
|
||||
Color color;
|
||||
|
||||
TextCommandData() : font(nullptr), text(), position(), color(Colors::White) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 统一渲染命令结构
|
||||
* 使用 variant 存储不同类型的命令数据,减少内存分配
|
||||
*/
|
||||
struct RenderCommand {
|
||||
RenderCommandType type;
|
||||
uint32_t layer; // 渲染层级,用于排序
|
||||
uint32_t order; // 提交顺序,保证同层级内稳定排序
|
||||
glm::mat4 transform; // 变换矩阵
|
||||
|
||||
// 使用 variant 存储具体数据
|
||||
std::variant<
|
||||
SpriteCommandData,
|
||||
LineCommandData,
|
||||
RectCommandData,
|
||||
CircleCommandData,
|
||||
TriangleCommandData,
|
||||
PolygonCommandData,
|
||||
TextCommandData
|
||||
> data;
|
||||
|
||||
RenderCommand() : type(RenderCommandType::None), layer(0), order(0),
|
||||
transform(1.0f) {}
|
||||
|
||||
// 便捷构造函数
|
||||
static RenderCommand makeSprite(const Texture* tex, const Rect& dest,
|
||||
const Rect& src, const Color& tint,
|
||||
float rot = 0.0f, const Vec2& anc = Vec2(0, 0),
|
||||
uint32_t lyr = 0);
|
||||
static RenderCommand makeLine(const Vec2& s, const Vec2& e, const Color& c,
|
||||
float w = 1.0f, uint32_t lyr = 0);
|
||||
static RenderCommand makeRect(const Rect& r, const Color& c,
|
||||
float w = 1.0f, bool fill = false, uint32_t lyr = 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染命令缓冲区
|
||||
* 用于收集和批量处理渲染命令
|
||||
*/
|
||||
class RenderCommandBuffer {
|
||||
public:
|
||||
static constexpr size_t INITIAL_CAPACITY = 1024;
|
||||
static constexpr size_t MAX_CAPACITY = 65536;
|
||||
|
||||
RenderCommandBuffer();
|
||||
~RenderCommandBuffer();
|
||||
|
||||
// 添加渲染命令
|
||||
void addCommand(const RenderCommand& cmd);
|
||||
void addCommand(RenderCommand&& cmd);
|
||||
|
||||
// 批量添加(预留空间后使用)
|
||||
RenderCommand& emplaceCommand();
|
||||
|
||||
// 排序命令(按纹理、层级等)
|
||||
void sortCommands();
|
||||
|
||||
// 清空缓冲区
|
||||
void clear();
|
||||
|
||||
// 获取命令列表
|
||||
const std::vector<RenderCommand>& getCommands() const { return commands_; }
|
||||
std::vector<RenderCommand>& getCommands() { return commands_; }
|
||||
|
||||
// 统计
|
||||
size_t size() const { return commands_.size(); }
|
||||
bool empty() const { return commands_.empty(); }
|
||||
size_t capacity() const { return commands_.capacity(); }
|
||||
|
||||
// 预分配空间
|
||||
void reserve(size_t capacity);
|
||||
|
||||
private:
|
||||
std::vector<RenderCommand> commands_;
|
||||
uint32_t nextOrder_;
|
||||
|
||||
// 排序比较函数
|
||||
static bool compareCommands(const RenderCommand& a, const RenderCommand& b);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 渲染模块配置结构
|
||||
*/
|
||||
struct RenderCfg {
|
||||
BackendType backend;
|
||||
int targetFPS;
|
||||
bool vsync;
|
||||
int multisamples;
|
||||
int priority;
|
||||
|
||||
RenderCfg()
|
||||
: backend(BackendType::OpenGL)
|
||||
, targetFPS(60)
|
||||
, vsync(true)
|
||||
, multisamples(0)
|
||||
, priority(10)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染模块
|
||||
* 管理渲染后端
|
||||
*/
|
||||
class RenderModule : public Module {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数(Lambda 配置)
|
||||
* @param configFn 配置函数
|
||||
*/
|
||||
explicit RenderModule(std::function<void(RenderCfg&)> configFn);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~RenderModule() override;
|
||||
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
bool ok() const override { return initialized_; }
|
||||
const char* name() const override { return "render"; }
|
||||
int priority() const override { return cfg_.priority; }
|
||||
|
||||
/**
|
||||
* @brief 获取依赖
|
||||
* @return 依赖模块类型列表
|
||||
*/
|
||||
std::vector<std::type_index> deps() const override {
|
||||
return {std::type_index(typeid(WindowModule))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器
|
||||
* @return 渲染后端指针
|
||||
*/
|
||||
RenderBackend* renderer() const { return renderer_.get(); }
|
||||
|
||||
private:
|
||||
RenderCfg cfg_;
|
||||
UniquePtr<RenderBackend> renderer_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_texture.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <mutex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 渲染目标配置
|
||||
// ============================================================================
|
||||
struct RenderTargetConfig {
|
||||
int width = 800; // 宽度
|
||||
int height = 600; // 高度
|
||||
PixelFormat colorFormat = PixelFormat::RGBA8; // 颜色格式
|
||||
bool hasDepth = true; // 是否包含深度缓冲
|
||||
bool hasStencil = false; // 是否包含模板缓冲
|
||||
int samples = 1; // 多重采样数 (1 = 无MSAA)
|
||||
bool autoResize = true; // 是否自动调整大小
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 渲染目标 - 基于FBO的离屏渲染
|
||||
// ============================================================================
|
||||
class RenderTarget {
|
||||
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 从现有纹理创建渲染目标
|
||||
*/
|
||||
bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false);
|
||||
|
||||
/**
|
||||
* @brief 销毁渲染目标
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
*/
|
||||
bool isValid() const { return fbo_ != 0; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 尺寸和格式
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
Vec2 getSize() const {
|
||||
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 获取颜色纹理
|
||||
*/
|
||||
Ptr<Texture> getColorTexture() const { return colorTexture_; }
|
||||
|
||||
/**
|
||||
* @brief 获取深度纹理(如果有)
|
||||
*/
|
||||
Ptr<Texture> getDepthTexture() const { return depthTexture_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 视口和裁剪
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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 复制到屏幕
|
||||
*/
|
||||
void copyToScreen(int screenWidth, int screenHeight);
|
||||
|
||||
/**
|
||||
* @brief 保存为图像文件
|
||||
*/
|
||||
bool saveToFile(const std::string &filepath);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 静态方法
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 创建渲染目标的静态工厂方法
|
||||
*/
|
||||
static Ptr<RenderTarget> createFromConfig(const RenderTargetConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 获取当前绑定的渲染目标ID
|
||||
*/
|
||||
static GLuint getCurrentFBO();
|
||||
|
||||
/**
|
||||
* @brief 绑定默认渲染目标(屏幕)
|
||||
*/
|
||||
static void bindDefault();
|
||||
|
||||
/**
|
||||
* @brief 获取FBO ID(供内部使用)
|
||||
*/
|
||||
GLuint getFBO() const { return fbo_; }
|
||||
|
||||
protected:
|
||||
GLuint fbo_ = 0; // 帧缓冲对象
|
||||
GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板)
|
||||
|
||||
Ptr<Texture> colorTexture_; // 颜色纹理
|
||||
Ptr<Texture> depthTexture_; // 深度纹理(可选)
|
||||
|
||||
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 &get();
|
||||
|
||||
/**
|
||||
* @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 RenderTargetMgr {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
*/
|
||||
static RenderTargetMgr& get();
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染目标管理器
|
||||
* @param width 默认宽度
|
||||
* @param height 默认高度
|
||||
*/
|
||||
bool init(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染目标管理器
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 创建新的渲染目标
|
||||
*/
|
||||
Ptr<RenderTarget> createRenderTarget(const RenderTargetConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 获取默认渲染目标
|
||||
*/
|
||||
RenderTarget *getDefaultRenderTarget() const {
|
||||
return defaultRenderTarget_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整所有受管渲染目标的大小
|
||||
*/
|
||||
void resize(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
private:
|
||||
RenderTargetMgr() = default;
|
||||
~RenderTargetMgr() = default;
|
||||
RenderTargetMgr(const RenderTargetMgr &) = delete;
|
||||
RenderTargetMgr &operator=(const RenderTargetMgr &) = delete;
|
||||
|
||||
Ptr<RenderTarget> defaultRenderTarget_;
|
||||
std::vector<Ptr<RenderTarget>> renderTargets_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 便捷宏
|
||||
// ============================================================================
|
||||
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::get()
|
||||
#define E2D_RENDER_TARGET_MGR() ::extra2d::RenderTargetMgr::get()
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// GPU 上下文状态管理器
|
||||
// 用于跟踪 OpenGL/Vulkan 等 GPU 上下文的生命周期状态
|
||||
// 确保在 GPU 资源析构时能安全地检查上下文是否有效
|
||||
// ============================================================================
|
||||
|
||||
class GPUContext {
|
||||
public:
|
||||
/// 获取单例实例
|
||||
static GPUContext& get();
|
||||
|
||||
/// 标记 GPU 上下文为有效(在初始化完成后调用)
|
||||
void markValid();
|
||||
|
||||
/// 标记 GPU 上下文为无效(在销毁前调用)
|
||||
void markInvalid();
|
||||
|
||||
/// 检查 GPU 上下文是否有效
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
GPUContext() = default;
|
||||
~GPUContext() = default;
|
||||
GPUContext(const GPUContext&) = delete;
|
||||
GPUContext& operator=(const GPUContext&) = delete;
|
||||
|
||||
std::atomic<bool> valid_{false};
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// VRAM 管理器 - 跟踪显存使用情况
|
||||
// ============================================================================
|
||||
class VRAMMgr {
|
||||
public:
|
||||
static VRAMMgr& get();
|
||||
|
||||
// 纹理显存跟踪
|
||||
void allocTexture(size_t size);
|
||||
void freeTexture(size_t size);
|
||||
|
||||
// VBO/FBO 显存跟踪
|
||||
void allocBuffer(size_t size);
|
||||
void freeBuffer(size_t size);
|
||||
|
||||
// 查询显存使用情况
|
||||
size_t getUsedVRAM() const;
|
||||
size_t getTextureVRAM() const;
|
||||
size_t getBufferVRAM() const;
|
||||
size_t getAvailableVRAM() const;
|
||||
|
||||
// 显存预算管理
|
||||
void setVRAMBudget(size_t budget);
|
||||
size_t getVRAMBudget() const;
|
||||
bool isOverBudget() const;
|
||||
|
||||
// 统计信息
|
||||
void printStats() const;
|
||||
|
||||
// 重置计数器
|
||||
void reset();
|
||||
|
||||
private:
|
||||
VRAMMgr();
|
||||
~VRAMMgr() = default;
|
||||
VRAMMgr(const VRAMMgr&) = delete;
|
||||
VRAMMgr& operator=(const VRAMMgr&) = delete;
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
size_t textureVRAM_;
|
||||
size_t bufferVRAM_;
|
||||
size_t vramBudget_;
|
||||
|
||||
// 统计
|
||||
uint32_t textureAllocCount_;
|
||||
uint32_t textureFreeCount_;
|
||||
uint32_t bufferAllocCount_;
|
||||
uint32_t bufferFreeCount_;
|
||||
size_t peakTextureVRAM_;
|
||||
size_t peakBufferVRAM_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 缓冲区类型枚举
|
||||
// ============================================================================
|
||||
enum class BufferType {
|
||||
Vertex, // 顶点缓冲
|
||||
Index, // 索引缓冲
|
||||
Uniform // 统一缓冲
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 缓冲区使用模式枚举
|
||||
// ============================================================================
|
||||
enum class BufferUsage {
|
||||
Static, // 静态数据,很少更新
|
||||
Dynamic, // 动态数据,频繁更新
|
||||
Stream // 流式数据,每帧更新
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 缓冲区描述结构
|
||||
// ============================================================================
|
||||
struct BufferDesc {
|
||||
BufferType type = BufferType::Vertex;
|
||||
BufferUsage usage = BufferUsage::Static;
|
||||
size_t size = 0; // 缓冲区大小(字节)
|
||||
const void* initialData = nullptr; // 初始数据
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 缓冲区抽象接口 - 渲染后端无关
|
||||
// ============================================================================
|
||||
class Buffer {
|
||||
public:
|
||||
virtual ~Buffer() = default;
|
||||
|
||||
/**
|
||||
* @brief 绑定缓冲区
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 解绑缓冲区
|
||||
*/
|
||||
virtual void unbind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置缓冲区数据(完全替换)
|
||||
* @param data 数据指针
|
||||
* @param size 数据大小(字节)
|
||||
*/
|
||||
virtual void setData(const void* data, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* @brief 更新缓冲区部分数据
|
||||
* @param data 数据指针
|
||||
* @param offset 偏移量(字节)
|
||||
* @param size 数据大小(字节)
|
||||
*/
|
||||
virtual void updateData(const void* data, size_t offset, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* @brief 映射缓冲区到内存(用于直接写入)
|
||||
* @return 映射后的内存指针,失败返回 nullptr
|
||||
*/
|
||||
virtual void* map() = 0;
|
||||
|
||||
/**
|
||||
* @brief 解除缓冲区映射
|
||||
*/
|
||||
virtual void unmap() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取缓冲区大小
|
||||
* @return 缓冲区大小(字节)
|
||||
*/
|
||||
virtual size_t getSize() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取缓冲区类型
|
||||
* @return 缓冲区类型
|
||||
*/
|
||||
virtual BufferType getType() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取缓冲区使用模式
|
||||
* @return 使用模式
|
||||
*/
|
||||
virtual BufferUsage getUsage() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查缓冲区是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取原生句柄(后端特定)
|
||||
* @return 原生句柄值
|
||||
*/
|
||||
virtual uintptr_t getNativeHandle() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 字形信息结构
|
||||
// ============================================================================
|
||||
struct Glyph {
|
||||
float width = 0; // 字形宽度
|
||||
float height = 0; // 字形高度
|
||||
float bearingX = 0; // 水平偏移
|
||||
float bearingY = 0; // 垂直偏移(从基线到字形顶部)
|
||||
float advance = 0; // 水平步进
|
||||
float u0 = 0, v0 = 0; // 纹理坐标左下角
|
||||
float u1 = 0, v1 = 0; // 纹理坐标右上角
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 字体图集描述结构
|
||||
// ============================================================================
|
||||
struct FontAtlasDesc {
|
||||
std::string filepath; // 字体文件路径
|
||||
int fontSize = 16; // 字体大小
|
||||
bool useSDF = false; // 是否使用SDF渲染
|
||||
int atlasSize = 512; // 图集大小
|
||||
int padding = 2; // 字形间距
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 字体图集抽象接口 - 渲染后端无关
|
||||
// ============================================================================
|
||||
class FontAtlas {
|
||||
public:
|
||||
virtual ~FontAtlas() = default;
|
||||
|
||||
/**
|
||||
* @brief 初始化字体图集
|
||||
* @param desc 字体图集描述
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
virtual bool init(const FontAtlasDesc& desc) = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭字体图集,释放资源
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取字形信息
|
||||
* @param codepoint Unicode 码点
|
||||
* @return 字形信息指针,未找到返回 nullptr
|
||||
*/
|
||||
virtual const Glyph* getGlyph(char32_t codepoint) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取纹理
|
||||
* @return 纹理对象
|
||||
*/
|
||||
virtual Ptr<Texture> getTexture() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取字体大小
|
||||
* @return 字体大小
|
||||
*/
|
||||
virtual int getFontSize() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取行高
|
||||
* @return 行高
|
||||
*/
|
||||
virtual float getLineHeight() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取基线到顶部的距离
|
||||
* @return 上升高度
|
||||
*/
|
||||
virtual float getAscent() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取基线到底部的距离
|
||||
* @return 下降高度
|
||||
*/
|
||||
virtual float getDescent() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 计算文本宽度
|
||||
* @param text 文本内容
|
||||
* @return 文本宽度
|
||||
*/
|
||||
virtual float measureText(const std::string& text) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 计算文本尺寸
|
||||
* @param text 文本内容
|
||||
* @return 文本尺寸
|
||||
*/
|
||||
virtual Size measureTextSize(const std::string& text) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 是否使用SDF渲染
|
||||
* @return 使用SDF返回 true
|
||||
*/
|
||||
virtual bool isSDF() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查字体图集是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 预加载字符到图集
|
||||
* @param text 需要预加载的文本
|
||||
* @return 成功加载的字符数
|
||||
*/
|
||||
virtual int preloadGlyphs(const std::string& text) = 0;
|
||||
|
||||
/**
|
||||
* @brief 清空已加载的字形缓存
|
||||
*/
|
||||
virtual void clearCache() = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 帧缓冲描述结构
|
||||
// ============================================================================
|
||||
struct FramebufferDesc {
|
||||
int width = 0; // 帧缓冲宽度
|
||||
int height = 0; // 帧缓冲高度
|
||||
int colorAttachments = 1; // 颜色附件数量
|
||||
bool hasDepth = false; // 是否有深度附件
|
||||
bool hasStencil = false; // 是否有模板附件
|
||||
bool multisample = false; // 是否多重采样
|
||||
int samples = 4; // 采样数(多重采样时有效)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 帧缓冲抽象接口 - 渲染后端无关
|
||||
// ============================================================================
|
||||
class Framebuffer {
|
||||
public:
|
||||
virtual ~Framebuffer() = default;
|
||||
|
||||
/**
|
||||
* @brief 绑定帧缓冲(作为渲染目标)
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 解绑帧缓冲(恢复到默认帧缓冲)
|
||||
*/
|
||||
virtual void unbind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 附加颜色纹理
|
||||
* @param texture 纹理对象
|
||||
* @param attachment 附件索引(0-7)
|
||||
*/
|
||||
virtual void attachColorTexture(Ptr<Texture> texture, int attachment = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief 附加深度纹理
|
||||
* @param texture 纹理对象
|
||||
*/
|
||||
virtual void attachDepthTexture(Ptr<Texture> texture) = 0;
|
||||
|
||||
/**
|
||||
* @brief 附加深度模板纹理
|
||||
* @param texture 纹理对象
|
||||
*/
|
||||
virtual void attachDepthStencilTexture(Ptr<Texture> texture) = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查帧缓冲是否完整
|
||||
* @return 完整返回 true
|
||||
*/
|
||||
virtual bool isComplete() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取颜色附件纹理
|
||||
* @param attachment 附件索引
|
||||
* @return 纹理对象
|
||||
*/
|
||||
virtual Ptr<Texture> getColorTexture(int attachment = 0) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取深度附件纹理
|
||||
* @return 纹理对象
|
||||
*/
|
||||
virtual Ptr<Texture> getDepthTexture() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲宽度
|
||||
* @return 宽度
|
||||
*/
|
||||
virtual int getWidth() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲高度
|
||||
* @return 高度
|
||||
*/
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取尺寸
|
||||
* @return 尺寸
|
||||
*/
|
||||
virtual Size getSize() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查帧缓冲是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取原生句柄(后端特定)
|
||||
* @return 原生句柄值
|
||||
*/
|
||||
virtual uintptr_t getNativeHandle() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 清除帧缓冲
|
||||
* @param color 清除颜色
|
||||
* @param clearColor 是否清除颜色缓冲
|
||||
* @param clearDepth 是否清除深度缓冲
|
||||
* @param clearStencil 是否清除模板缓冲
|
||||
*/
|
||||
virtual void clear(const Color& color, bool clearColor = true,
|
||||
bool clearDepth = true, bool clearStencil = false) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
* @param x 视口左下角X坐标
|
||||
* @param y 视口左下角Y坐标
|
||||
* @param width 视口宽度
|
||||
* @param height 视口高度
|
||||
*/
|
||||
virtual void setViewport(int x, int y, int width, int height) = 0;
|
||||
|
||||
/**
|
||||
* @brief 读取像素数据
|
||||
* @param x 起始X坐标
|
||||
* @param y 起始Y坐标
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param outData 输出数据缓冲区
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
virtual bool readPixels(int x, int y, int width, int height,
|
||||
std::vector<uint8_t>& outData) = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 混合模式枚举
|
||||
// ============================================================================
|
||||
enum class BlendMode {
|
||||
None, // 不混合
|
||||
Alpha, // 标准 Alpha 混合
|
||||
Additive, // 加法混合
|
||||
Multiply // 乘法混合
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 深度测试函数枚举
|
||||
// ============================================================================
|
||||
enum class DepthFunc {
|
||||
Never, // 永不通过
|
||||
Less, // 小于
|
||||
Equal, // 等于
|
||||
LessEqual, // 小于等于
|
||||
Greater, // 大于
|
||||
NotEqual, // 不等于
|
||||
GreaterEqual,// 大于等于
|
||||
Always // 总是通过
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 裁剪模式枚举
|
||||
// ============================================================================
|
||||
enum class CullMode {
|
||||
None, // 不裁剪
|
||||
Front, // 裁剪正面
|
||||
Back, // 裁剪背面
|
||||
Both // 裁剪双面
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 顶点属性格式枚举
|
||||
// ============================================================================
|
||||
enum class VertexFormat {
|
||||
Float1, // 1个float
|
||||
Float2, // 2个float
|
||||
Float3, // 3个float
|
||||
Float4, // 4个float
|
||||
Byte4, // 4个byte
|
||||
UByte4, // 4个ubyte
|
||||
Short2, // 2个short
|
||||
Short4 // 4个short
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 顶点属性描述
|
||||
// ============================================================================
|
||||
struct VertexAttribute {
|
||||
uint32_t location = 0; // 属性位置
|
||||
VertexFormat format = VertexFormat::Float3; // 数据格式
|
||||
uint32_t offset = 0; // 在顶点结构中的偏移
|
||||
uint32_t stride = 0; // 顶点结构大小
|
||||
bool normalized = false; // 是否归一化
|
||||
|
||||
VertexAttribute() = default;
|
||||
VertexAttribute(uint32_t loc, VertexFormat fmt, uint32_t off, uint32_t str, bool norm = false)
|
||||
: location(loc), format(fmt), offset(off), stride(str), normalized(norm) {}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 管线描述结构
|
||||
// ============================================================================
|
||||
struct PipelineDesc {
|
||||
// 混合状态
|
||||
BlendMode blendMode = BlendMode::Alpha;
|
||||
bool blendEnabled = true;
|
||||
|
||||
// 深度状态
|
||||
bool depthTest = false;
|
||||
bool depthWrite = false;
|
||||
DepthFunc depthFunc = DepthFunc::Less;
|
||||
|
||||
// 裁剪状态
|
||||
CullMode cullMode = CullMode::None;
|
||||
|
||||
// 顶点布局
|
||||
std::vector<VertexAttribute> vertexAttributes;
|
||||
|
||||
// 着色器(由后端特定实现设置)
|
||||
void* vertexShader = nullptr;
|
||||
void* fragmentShader = nullptr;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 渲染管线抽象接口 - 渲染后端无关
|
||||
// ============================================================================
|
||||
class Pipeline {
|
||||
public:
|
||||
virtual ~Pipeline() = default;
|
||||
|
||||
/**
|
||||
* @brief 绑定管线
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 解绑管线
|
||||
*/
|
||||
virtual void unbind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
* @param mode 混合模式
|
||||
*/
|
||||
virtual void setBlendMode(BlendMode mode) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取当前混合模式
|
||||
* @return 混合模式
|
||||
*/
|
||||
virtual BlendMode getBlendMode() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置深度测试
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
virtual void setDepthTest(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置深度写入
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
virtual void setDepthWrite(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置深度测试函数
|
||||
* @param func 深度测试函数
|
||||
*/
|
||||
virtual void setDepthFunc(DepthFunc func) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪模式
|
||||
* @param mode 裁剪模式
|
||||
*/
|
||||
virtual void setCullMode(CullMode mode) = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查管线是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取原生句柄(后端特定)
|
||||
* @return 原生句柄值
|
||||
*/
|
||||
virtual uintptr_t getNativeHandle() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 着色器类型枚举
|
||||
// ============================================================================
|
||||
enum class ShaderType {
|
||||
Vertex, // 顶点着色器
|
||||
Fragment, // 片段着色器
|
||||
Geometry, // 几何着色器
|
||||
Compute // 计算着色器
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 着色器描述结构
|
||||
// ============================================================================
|
||||
struct ShaderDesc {
|
||||
std::string name; // 着色器名称
|
||||
std::string vertexSource; // 顶点着色器源码
|
||||
std::string fragmentSource; // 片段着色器源码
|
||||
std::string geometrySource; // 几何着色器源码(可选)
|
||||
std::vector<uint8_t> binaryData; // 预编译二进制数据(可选)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 着色器抽象接口 - 渲染后端无关
|
||||
// ============================================================================
|
||||
class Shader {
|
||||
public:
|
||||
virtual ~Shader() = default;
|
||||
|
||||
/**
|
||||
* @brief 绑定着色器程序
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
|
||||
/**
|
||||
* @brief 解绑着色器程序
|
||||
*/
|
||||
virtual void unbind() = 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 设置纹理采样器
|
||||
* @param name uniform 变量名
|
||||
* @param slot 纹理槽位
|
||||
*/
|
||||
virtual void setTexture(const std::string& name, int slot) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取着色器名称
|
||||
* @return 着色器名称
|
||||
*/
|
||||
virtual const std::string& getName() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查着色器是否有效
|
||||
* @return 有效返回 true
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取原生句柄(后端特定)
|
||||
* @return 原生句柄值
|
||||
*/
|
||||
virtual uintptr_t getNativeHandle() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Shader缓存条目
|
||||
// ============================================================================
|
||||
struct ShaderCacheEntry {
|
||||
std::string name;
|
||||
std::string sourceHash;
|
||||
uint64_t compileTime = 0;
|
||||
std::vector<uint8_t> binary;
|
||||
std::vector<std::string> dependencies;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Shader缓存管理器
|
||||
// ============================================================================
|
||||
class ShaderCache {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return 缓存管理器实例引用
|
||||
*/
|
||||
static ShaderCache& getInstance();
|
||||
|
||||
/**
|
||||
* @brief 初始化缓存系统
|
||||
* @param cacheDir 缓存目录路径
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool init(const std::string& cacheDir);
|
||||
|
||||
/**
|
||||
* @brief 关闭缓存系统
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查缓存是否有效
|
||||
* @param name Shader名称
|
||||
* @param sourceHash 源码哈希值
|
||||
* @return 缓存有效返回true,否则返回false
|
||||
*/
|
||||
bool hasValidCache(const std::string& name, const std::string& sourceHash);
|
||||
|
||||
/**
|
||||
* @brief 加载缓存的二进制数据
|
||||
* @param name Shader名称
|
||||
* @return 缓存条目指针,不存在返回nullptr
|
||||
*/
|
||||
Ptr<ShaderCacheEntry> loadCache(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 保存编译结果到缓存
|
||||
* @param entry 缓存条目
|
||||
* @return 保存成功返回true,失败返回false
|
||||
*/
|
||||
bool saveCache(const ShaderCacheEntry& entry);
|
||||
|
||||
/**
|
||||
* @brief 使缓存失效
|
||||
* @param name Shader名称
|
||||
*/
|
||||
void invalidate(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 清除所有缓存
|
||||
*/
|
||||
void clearAll();
|
||||
|
||||
/**
|
||||
* @brief 计算源码哈希值
|
||||
* @param vertSource 顶点着色器源码
|
||||
* @param fragSource 片段着色器源码
|
||||
* @return 哈希值字符串
|
||||
*/
|
||||
static std::string computeHash(const std::string& vertSource,
|
||||
const std::string& fragSource);
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
* @return 已初始化返回true,否则返回false
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
private:
|
||||
ShaderCache() = default;
|
||||
~ShaderCache() = default;
|
||||
ShaderCache(const ShaderCache&) = delete;
|
||||
ShaderCache& operator=(const ShaderCache&) = delete;
|
||||
|
||||
std::string cacheDir_;
|
||||
std::unordered_map<std::string, ShaderCacheEntry> cacheMap_;
|
||||
bool initialized_ = false;
|
||||
|
||||
/**
|
||||
* @brief 加载缓存索引
|
||||
* @return 加载成功返回true,失败返回false
|
||||
*/
|
||||
bool loadCacheIndex();
|
||||
|
||||
/**
|
||||
* @brief 保存缓存索引
|
||||
* @return 保存成功返回true,失败返回false
|
||||
*/
|
||||
bool saveCacheIndex();
|
||||
|
||||
/**
|
||||
* @brief 获取缓存文件路径
|
||||
* @param name Shader名称
|
||||
* @return 缓存文件完整路径
|
||||
*/
|
||||
std::string getCachePath(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief 确保缓存目录存在
|
||||
* @return 目录存在或创建成功返回true,否则返回false
|
||||
*/
|
||||
bool ensureCacheDirectory();
|
||||
};
|
||||
|
||||
// 便捷宏
|
||||
#define E2D_SHADER_CACHE() ::extra2d::ShaderCache::getInstance()
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 文件变化事件
|
||||
// ============================================================================
|
||||
struct FileChangeEvent {
|
||||
std::string filepath;
|
||||
|
||||
enum class Type { Created, Modified, Deleted, Renamed } type;
|
||||
|
||||
uint64_t timestamp = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 文件变化回调
|
||||
// ============================================================================
|
||||
using FileChangeCallback = std::function<void(const FileChangeEvent &)>;
|
||||
|
||||
// ============================================================================
|
||||
// Shader热重载管理器
|
||||
// ============================================================================
|
||||
class ShaderHotReloader {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return 热重载管理器实例引用
|
||||
*/
|
||||
static ShaderHotReloader &getInstance();
|
||||
|
||||
/**
|
||||
* @brief 初始化热重载系统
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭热重载系统
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 注册Shader文件监视
|
||||
* @param shaderName Shader名称
|
||||
* @param filePaths 要监视的文件列表
|
||||
* @param callback 文件变化时的回调
|
||||
*/
|
||||
void watch(const std::string &shaderName,
|
||||
const std::vector<std::string> &filePaths,
|
||||
FileChangeCallback callback);
|
||||
|
||||
/**
|
||||
* @brief 取消监视
|
||||
* @param shaderName Shader名称
|
||||
*/
|
||||
void unwatch(const std::string &shaderName);
|
||||
|
||||
/**
|
||||
* @brief 更新文件监视(在主循环中调用)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用热重载
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 检查是否启用
|
||||
* @return 启用返回true,否则返回false
|
||||
*/
|
||||
bool isEnabled() const { return enabled_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
* @return 已初始化返回true,否则返回false
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
private:
|
||||
ShaderHotReloader() = default;
|
||||
~ShaderHotReloader() = default;
|
||||
ShaderHotReloader(const ShaderHotReloader &) = delete;
|
||||
ShaderHotReloader &operator=(const ShaderHotReloader &) = delete;
|
||||
|
||||
bool enabled_ = false;
|
||||
bool initialized_ = false;
|
||||
|
||||
struct WatchInfo {
|
||||
std::vector<std::string> filePaths;
|
||||
FileChangeCallback callback;
|
||||
std::unordered_map<std::string, uint64_t> modifiedTimes;
|
||||
};
|
||||
std::unordered_map<std::string, WatchInfo> watchMap_;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE watchHandle_ = nullptr;
|
||||
std::vector<uint8_t> buffer_;
|
||||
std::string watchDir_;
|
||||
bool watching_ = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 轮询检查文件变化
|
||||
*/
|
||||
void pollChanges();
|
||||
|
||||
/**
|
||||
* @brief 获取文件修改时间
|
||||
* @param filepath 文件路径
|
||||
* @return 修改时间戳
|
||||
*/
|
||||
static uint64_t getFileModifiedTime(const std::string &filepath);
|
||||
};
|
||||
|
||||
// 便捷宏
|
||||
#define E2D_SHADER_HOT_RELOADER() ::extra2d::ShaderHotReloader::getInstance()
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class 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 extra2d
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Shader加载结果
|
||||
// ============================================================================
|
||||
struct ShaderLoadResult {
|
||||
bool success = false;
|
||||
std::string errorMessage;
|
||||
std::string vertSource;
|
||||
std::string fragSource;
|
||||
std::vector<std::string> dependencies;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Shader元数据
|
||||
// ============================================================================
|
||||
struct ShaderMetadata {
|
||||
std::string name;
|
||||
std::string vertPath;
|
||||
std::string fragPath;
|
||||
std::string combinedPath;
|
||||
uint64_t lastModified = 0;
|
||||
std::vector<std::string> defines;
|
||||
std::unordered_map<std::string, std::string> uniforms;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// ShaderLoader接口 - 支持多种文件格式加载
|
||||
// ============================================================================
|
||||
class IShaderLoader {
|
||||
public:
|
||||
virtual ~IShaderLoader() = default;
|
||||
|
||||
/**
|
||||
* @brief 从分离文件加载Shader (.vert + .frag)
|
||||
* @param name Shader名称
|
||||
* @param vertPath 顶点着色器文件路径
|
||||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromSeparateFiles(
|
||||
const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) = 0;
|
||||
|
||||
/**
|
||||
* @brief 从组合文件加载Shader (.shader)
|
||||
* @param path 组合Shader文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromCombinedFile(const std::string& path) = 0;
|
||||
|
||||
/**
|
||||
* @brief 从源码字符串加载Shader
|
||||
* @param vertSource 顶点着色器源码
|
||||
* @param fragSource 片段着色器源码
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromSource(
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) = 0;
|
||||
|
||||
/**
|
||||
* @brief 处理Shader源码中的#include指令
|
||||
* @param source 原始源码
|
||||
* @param baseDir 基础目录
|
||||
* @param outDependencies 输出依赖列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
virtual std::string processIncludes(
|
||||
const std::string& source,
|
||||
const std::string& baseDir,
|
||||
std::vector<std::string>& outDependencies) = 0;
|
||||
|
||||
/**
|
||||
* @brief 应用预处理器定义
|
||||
* @param source 原始源码
|
||||
* @param defines 预处理器定义列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
virtual std::string applyDefines(
|
||||
const std::string& source,
|
||||
const std::vector<std::string>& defines) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param path Shader文件路径
|
||||
* @return 元数据
|
||||
*/
|
||||
virtual ShaderMetadata getMetadata(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 默认ShaderLoader实现
|
||||
// ============================================================================
|
||||
class ShaderLoader : public IShaderLoader {
|
||||
public:
|
||||
ShaderLoader();
|
||||
~ShaderLoader() override = default;
|
||||
|
||||
/**
|
||||
* @brief 从分离文件加载Shader (.vert + .frag)
|
||||
* @param name Shader名称
|
||||
* @param vertPath 顶点着色器文件路径
|
||||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromSeparateFiles(
|
||||
const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) override;
|
||||
|
||||
/**
|
||||
* @brief 从组合文件加载Shader (.shader)
|
||||
* @param path 组合Shader文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromCombinedFile(const std::string& path) override;
|
||||
|
||||
/**
|
||||
* @brief 从源码字符串加载Shader
|
||||
* @param vertSource 顶点着色器源码
|
||||
* @param fragSource 片段着色器源码
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromSource(
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) override;
|
||||
|
||||
/**
|
||||
* @brief 处理Shader源码中的#include指令
|
||||
* @param source 原始源码
|
||||
* @param baseDir 基础目录
|
||||
* @param outDependencies 输出依赖列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string processIncludes(
|
||||
const std::string& source,
|
||||
const std::string& baseDir,
|
||||
std::vector<std::string>& outDependencies) override;
|
||||
|
||||
/**
|
||||
* @brief 应用预处理器定义
|
||||
* @param source 原始源码
|
||||
* @param defines 预处理器定义列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string applyDefines(
|
||||
const std::string& source,
|
||||
const std::vector<std::string>& defines) override;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param path Shader文件路径
|
||||
* @return 元数据
|
||||
*/
|
||||
ShaderMetadata getMetadata(const std::string& path) override;
|
||||
|
||||
/**
|
||||
* @brief 添加include搜索路径
|
||||
* @param path 搜索路径
|
||||
*/
|
||||
void addIncludePath(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief 读取文件内容
|
||||
* @param filepath 文件路径
|
||||
* @return 文件内容字符串
|
||||
*/
|
||||
static std::string readFile(const std::string& filepath);
|
||||
|
||||
/**
|
||||
* @brief 获取文件修改时间
|
||||
* @param filepath 文件路径
|
||||
* @return 修改时间戳
|
||||
*/
|
||||
static uint64_t getFileModifiedTime(const std::string& filepath);
|
||||
|
||||
/**
|
||||
* @brief 检查文件是否存在
|
||||
* @param filepath 文件路径
|
||||
* @return 存在返回true,否则返回false
|
||||
*/
|
||||
static bool fileExists(const std::string& filepath);
|
||||
|
||||
private:
|
||||
std::vector<std::string> includePaths_;
|
||||
std::unordered_map<std::string, std::string> includeCache_;
|
||||
|
||||
/**
|
||||
* @brief 解析组合Shader文件
|
||||
* @param content 文件内容
|
||||
* @param outVert 输出顶点着色器源码
|
||||
* @param outFrag 输出片段着色器源码
|
||||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool parseCombinedFile(const std::string& content,
|
||||
std::string& outVert,
|
||||
std::string& outFrag,
|
||||
ShaderMetadata& outMetadata);
|
||||
|
||||
/**
|
||||
* @brief 解析元数据JSON块
|
||||
* @param jsonContent JSON内容
|
||||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata);
|
||||
|
||||
/**
|
||||
* @brief 查找include文件路径
|
||||
* @param includeName include文件名
|
||||
* @param baseDir 基础目录
|
||||
* @return 找到的完整路径,未找到返回空字符串
|
||||
*/
|
||||
std::string findIncludeFile(const std::string& includeName, const std::string& baseDir);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/shader/shader_cache.h>
|
||||
#include <extra2d/graphics/shader/shader_hot_reloader.h>
|
||||
#include <extra2d/graphics/shader/shader_interface.h>
|
||||
#include <extra2d/graphics/shader/shader_loader.h>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Shader重载回调
|
||||
// ============================================================================
|
||||
using ShaderReloadCallback = std::function<void(Ptr<IShader> newShader)>;
|
||||
|
||||
// ============================================================================
|
||||
// Shader管理器 - 统一入口
|
||||
// ============================================================================
|
||||
class ShaderManager {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
* @return Shader管理器实例引用
|
||||
*/
|
||||
static ShaderManager& getInstance();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 初始化和关闭
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 使用平台默认路径初始化Shader系统
|
||||
* 自动检测平台并使用正确的路径(romfs/sdmc/相对路径)
|
||||
* @param factory 渲染后端Shader工厂
|
||||
* @param appName 应用名称(用于缓存目录)
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool init(Ptr<IShaderFactory> factory, const std::string& appName = "extra2d");
|
||||
|
||||
/**
|
||||
* @brief 初始化Shader系统
|
||||
* @param shaderDir Shader文件目录
|
||||
* @param cacheDir 缓存目录
|
||||
* @param factory 渲染后端Shader工厂
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool init(const std::string& shaderDir,
|
||||
const std::string& cacheDir,
|
||||
Ptr<IShaderFactory> factory);
|
||||
|
||||
/**
|
||||
* @brief 关闭Shader系统
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
* @return 已初始化返回true,否则返回false
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
/**
|
||||
* @brief 检查当前平台是否支持热重载
|
||||
* Switch平台使用romfs,不支持热重载
|
||||
* @return 支持热重载返回true
|
||||
*/
|
||||
bool isHotReloadSupported() const { return hotReloadSupported_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Shader加载
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 从分离文件加载Shader
|
||||
* @param name Shader名称
|
||||
* @param vertPath 顶点着色器文件路径
|
||||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> loadFromFiles(const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath);
|
||||
|
||||
/**
|
||||
* @brief 从组合文件加载Shader
|
||||
* @param path 组合Shader文件路径
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> loadFromCombinedFile(const std::string& path);
|
||||
|
||||
/**
|
||||
* @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名称
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用热重载
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
void setHotReloadEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 检查热重载是否启用
|
||||
* @return 启用返回true,否则返回false
|
||||
*/
|
||||
bool isHotReloadEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief 更新热重载系统(主循环调用)
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* @brief 手动重载Shader
|
||||
* @param name Shader名称
|
||||
* @return 重载成功返回true,失败返回false
|
||||
*/
|
||||
bool reload(const std::string& name);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 内置Shader
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取内置Shader
|
||||
* @param name 内置Shader名称
|
||||
* @return Shader实例
|
||||
*/
|
||||
Ptr<IShader> getBuiltin(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 加载所有内置Shader
|
||||
* @return 加载成功返回true,失败返回false
|
||||
*/
|
||||
bool loadBuiltinShaders();
|
||||
|
||||
/**
|
||||
* @brief 从JSON元数据文件加载Shader(多后端支持)
|
||||
* @param jsonPath JSON元数据文件路径
|
||||
* @param name Shader名称
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> loadFromMetadata(const std::string& jsonPath, const std::string& name);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 工具方法
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取Shader目录
|
||||
* @return Shader目录路径
|
||||
*/
|
||||
const std::string& getShaderDir() const { return shaderDir_; }
|
||||
|
||||
/**
|
||||
* @brief 获取ShaderLoader
|
||||
* @return ShaderLoader引用
|
||||
*/
|
||||
ShaderLoader& getLoader() { return loader_; }
|
||||
|
||||
private:
|
||||
ShaderManager() = default;
|
||||
~ShaderManager() = default;
|
||||
ShaderManager(const ShaderManager&) = delete;
|
||||
ShaderManager& operator=(const ShaderManager&) = delete;
|
||||
|
||||
std::string shaderDir_;
|
||||
std::string cacheDir_;
|
||||
Ptr<IShaderFactory> factory_;
|
||||
ShaderLoader loader_;
|
||||
|
||||
struct ShaderInfo {
|
||||
Ptr<IShader> shader;
|
||||
ShaderMetadata metadata;
|
||||
ShaderReloadCallback reloadCallback;
|
||||
std::string vertSource;
|
||||
std::string fragSource;
|
||||
std::vector<std::string> filePaths;
|
||||
};
|
||||
std::unordered_map<std::string, ShaderInfo> shaders_;
|
||||
|
||||
bool initialized_ = false;
|
||||
bool hotReloadEnabled_ = false;
|
||||
bool hotReloadSupported_ = true;
|
||||
|
||||
/**
|
||||
* @brief 从缓存加载Shader
|
||||
* @param name Shader名称
|
||||
* @param sourceHash 源码哈希值
|
||||
* @param vertSource 顶点着色器源码
|
||||
* @param fragSource 片段着色器源码
|
||||
* @return Shader实例
|
||||
*/
|
||||
Ptr<IShader> loadFromCache(const std::string& name,
|
||||
const std::string& sourceHash,
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource);
|
||||
|
||||
/**
|
||||
* @brief 创建内置Shader源码
|
||||
*/
|
||||
void createBuiltinShaderSources();
|
||||
|
||||
/**
|
||||
* @brief 处理文件变化事件
|
||||
* @param shaderName Shader名称
|
||||
* @param event 文件变化事件
|
||||
*/
|
||||
void handleFileChange(const std::string& shaderName, const FileChangeEvent& event);
|
||||
};
|
||||
|
||||
// 便捷宏
|
||||
#define E2D_SHADER_MANAGER() ::extra2d::ShaderManager::getInstance()
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/shader/shader_interface.h>
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
struct WaterParams {
|
||||
float waveSpeed = 1.0f;
|
||||
float waveAmplitude = 0.02f;
|
||||
float waveFrequency = 4.0f;
|
||||
};
|
||||
|
||||
struct OutlineParams {
|
||||
Color color = Colors::Black;
|
||||
float thickness = 2.0f;
|
||||
};
|
||||
|
||||
struct DistortionParams {
|
||||
float distortionAmount = 0.02f;
|
||||
float timeScale = 1.0f;
|
||||
};
|
||||
|
||||
struct PixelateParams {
|
||||
float pixelSize = 8.0f;
|
||||
};
|
||||
|
||||
struct InvertParams {
|
||||
float strength = 1.0f;
|
||||
};
|
||||
|
||||
struct GrayscaleParams {
|
||||
float intensity = 1.0f;
|
||||
};
|
||||
|
||||
struct BlurParams {
|
||||
float radius = 5.0f;
|
||||
};
|
||||
|
||||
class ShaderPreset {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建水波纹效果着色器
|
||||
* @param params 水波纹效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Water(const WaterParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建描边效果着色器
|
||||
* @param params 描边效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Outline(const OutlineParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建扭曲效果着色器
|
||||
* @param params 扭曲效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Distortion(const DistortionParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建像素化效果着色器
|
||||
* @param params 像素化效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Pixelate(const PixelateParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建反相效果着色器
|
||||
* @param params 反相效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Invert(const InvertParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建灰度效果着色器
|
||||
* @param params 灰度效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Grayscale(const GrayscaleParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建模糊效果着色器
|
||||
* @param params 模糊效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> Blur(const BlurParams& params = {});
|
||||
|
||||
/**
|
||||
* @brief 创建灰度+描边组合效果着色器
|
||||
* @param grayParams 灰度效果参数
|
||||
* @param outlineParams 描边效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> GrayscaleOutline(const GrayscaleParams& grayParams,
|
||||
const OutlineParams& outlineParams);
|
||||
|
||||
/**
|
||||
* @brief 创建像素化+反相组合效果着色器
|
||||
* @param pixParams 像素化效果参数
|
||||
* @param invParams 反相效果参数
|
||||
* @return 配置好的着色器
|
||||
*/
|
||||
static Ptr<IShader> PixelateInvert(const PixelateParams& pixParams,
|
||||
const InvertParams& invParams);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Alpha 遮罩 - 存储图片的非透明区域信息
|
||||
// ============================================================================
|
||||
class AlphaMask {
|
||||
public:
|
||||
AlphaMask() = default;
|
||||
AlphaMask(int width, int height);
|
||||
|
||||
/// 从像素数据创建遮罩
|
||||
static AlphaMask createFromPixels(const uint8_t *pixels, int width,
|
||||
int height, int channels);
|
||||
|
||||
/// 获取指定位置的透明度(0-255)
|
||||
uint8_t getAlpha(int x, int y) const;
|
||||
|
||||
/// 检查指定位置是否不透明
|
||||
bool isOpaque(int x, int y, uint8_t threshold = 128) const;
|
||||
|
||||
/// 检查指定位置是否在遮罩范围内
|
||||
bool isValid(int x, int y) const;
|
||||
|
||||
/// 获取遮罩尺寸
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
Size getSize() const {
|
||||
return Size(static_cast<float>(width_), static_cast<float>(height_));
|
||||
}
|
||||
|
||||
/// 获取原始数据
|
||||
const std::vector<uint8_t> &getData() const { return data_; }
|
||||
|
||||
/// 检查遮罩是否有效
|
||||
bool isValid() const { return !data_.empty() && width_ > 0 && height_ > 0; }
|
||||
|
||||
private:
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
std::vector<uint8_t> data_; // Alpha值数组
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 字形信息
|
||||
// ============================================================================
|
||||
struct Glyph {
|
||||
float u0, v0; // 纹理坐标左下角
|
||||
float u1, v1; // 纹理坐标右上角
|
||||
float width; // 字形宽度(像素)
|
||||
float height; // 字形高度(像素)
|
||||
float bearingX; // 水平偏移
|
||||
float bearingY; // 垂直偏移
|
||||
float advance; // 前进距离
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 字体图集接口
|
||||
// ============================================================================
|
||||
class FontAtlas {
|
||||
public:
|
||||
virtual ~FontAtlas() = default;
|
||||
|
||||
// 获取字形信息
|
||||
virtual const Glyph *getGlyph(char32_t codepoint) const = 0;
|
||||
|
||||
// 获取纹理
|
||||
virtual class Texture *getTexture() const = 0;
|
||||
|
||||
// 获取字体大小
|
||||
virtual int getFontSize() const = 0;
|
||||
|
||||
virtual float getAscent() const = 0;
|
||||
virtual float getDescent() const = 0;
|
||||
virtual float getLineGap() const = 0;
|
||||
virtual float getLineHeight() const = 0;
|
||||
|
||||
// 计算文字尺寸
|
||||
virtual Vec2 measureText(const std::string &text) = 0;
|
||||
|
||||
// 是否支持 SDF 渲染
|
||||
virtual bool isSDF() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 像素格式枚举
|
||||
// ============================================================================
|
||||
enum class PixelFormat {
|
||||
R8, // 单通道灰度
|
||||
RG8, // 双通道
|
||||
RGB8, // RGB 24位
|
||||
RGBA8, // RGBA 32位(默认)
|
||||
RGB16F, // RGB 半精度浮点
|
||||
RGBA16F, // RGBA 半精度浮点
|
||||
RGB32F, // RGB 全精度浮点
|
||||
RGBA32F, // RGBA 全精度浮点
|
||||
Depth16, // 16位深度
|
||||
Depth24, // 24位深度
|
||||
Depth32F, // 32位浮点深度
|
||||
Depth24Stencil8, // 24位深度 + 8位模板
|
||||
|
||||
// 压缩纹理格式
|
||||
ETC2_RGB8, // ETC2 RGB 压缩
|
||||
ETC2_RGBA8, // ETC2 RGBA 压缩
|
||||
ASTC_4x4, // ASTC 4x4 压缩
|
||||
ASTC_6x6, // ASTC 6x6 压缩
|
||||
ASTC_8x8 // ASTC 8x8 压缩
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 纹理接口
|
||||
// ============================================================================
|
||||
class Texture {
|
||||
public:
|
||||
virtual ~Texture() = default;
|
||||
|
||||
// 获取尺寸
|
||||
virtual int getWidth() const = 0;
|
||||
virtual int getHeight() const = 0;
|
||||
virtual Size getSize() const = 0;
|
||||
|
||||
// 获取通道数
|
||||
virtual int getChannels() const = 0;
|
||||
|
||||
// 获取像素格式
|
||||
virtual PixelFormat getFormat() const = 0;
|
||||
|
||||
// 获取原始句柄(用于底层渲染)
|
||||
virtual void* getNativeHandle() const = 0;
|
||||
|
||||
// 是否有效
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
// 设置过滤模式
|
||||
virtual void setFilter(bool linear) = 0;
|
||||
|
||||
// 设置环绕模式
|
||||
virtual void setWrap(bool repeat) = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_texture.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 纹理图集 - 自动将小纹理合并到大图集以减少 DrawCall
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 图集中的单个纹理条目
|
||||
*/
|
||||
struct AtlasEntry {
|
||||
std::string name; // 原始纹理名称/路径
|
||||
Rect uvRect; // 在图集中的 UV 坐标范围
|
||||
Vec2 originalSize; // 原始纹理尺寸
|
||||
uint32_t padding; // 边距(用于避免纹理 bleeding)
|
||||
|
||||
AtlasEntry() : uvRect(), originalSize(), padding(2) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 纹理图集页面
|
||||
* 当单个图集放不下时,创建多个页面
|
||||
*/
|
||||
class TextureAtlasPage {
|
||||
public:
|
||||
static constexpr int DEFAULT_SIZE = 2048;
|
||||
static constexpr int MAX_SIZE = 4096;
|
||||
static constexpr int MIN_TEXTURE_SIZE = 32; // 小于此大小的纹理才考虑合并
|
||||
static constexpr int PADDING = 2; // 纹理间边距
|
||||
|
||||
TextureAtlasPage(int width = DEFAULT_SIZE, int height = DEFAULT_SIZE);
|
||||
~TextureAtlasPage();
|
||||
|
||||
// 尝试添加纹理到图集
|
||||
// 返回是否成功,如果成功则输出 uvRect
|
||||
bool tryAddTexture(const std::string& name, int texWidth, int texHeight,
|
||||
const uint8_t* pixels, Rect& outUvRect);
|
||||
|
||||
// 获取图集纹理
|
||||
Ptr<Texture> getTexture() const { return texture_; }
|
||||
|
||||
// 获取条目
|
||||
const AtlasEntry* getEntry(const std::string& name) const;
|
||||
|
||||
// 获取使用率
|
||||
float getUsageRatio() const;
|
||||
|
||||
// 获取尺寸
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
|
||||
// 是否已满
|
||||
bool isFull() const { return isFull_; }
|
||||
|
||||
private:
|
||||
int width_, height_;
|
||||
Ptr<Texture> texture_;
|
||||
std::unordered_map<std::string, AtlasEntry> entries_;
|
||||
|
||||
// 矩形打包数据
|
||||
struct PackNode {
|
||||
int x, y, width, height;
|
||||
bool used;
|
||||
std::unique_ptr<PackNode> left;
|
||||
std::unique_ptr<PackNode> right;
|
||||
|
||||
PackNode(int x_, int y_, int w, int h)
|
||||
: x(x_), y(y_), width(w), height(h), used(false) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<PackNode> root_;
|
||||
bool isFull_;
|
||||
int usedArea_;
|
||||
|
||||
// 递归插入
|
||||
PackNode* insert(PackNode* node, int width, int height);
|
||||
void writePixels(int x, int y, int w, int h, const uint8_t* pixels);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 纹理图集管理器
|
||||
* 自动管理多个图集页面,提供统一的纹理查询接口
|
||||
*/
|
||||
class TextureAtlas {
|
||||
public:
|
||||
TextureAtlas();
|
||||
~TextureAtlas();
|
||||
|
||||
// 初始化
|
||||
void init(int pageSize = TextureAtlasPage::DEFAULT_SIZE);
|
||||
|
||||
// 添加纹理到图集
|
||||
// 如果纹理太大,返回 false,应该作为独立纹理加载
|
||||
bool addTexture(const std::string& name, int width, int height,
|
||||
const uint8_t* pixels);
|
||||
|
||||
// 查询纹理是否在图集中
|
||||
bool contains(const std::string& name) const;
|
||||
|
||||
// 获取纹理在图集中的信息
|
||||
// 返回图集纹理和 UV 坐标
|
||||
const Texture* getAtlasTexture(const std::string& name) const;
|
||||
Rect getUVRect(const std::string& name) const;
|
||||
|
||||
// 获取原始纹理尺寸
|
||||
Vec2 getOriginalSize(const std::string& name) const;
|
||||
|
||||
// 获取所有图集页面
|
||||
const std::vector<std::unique_ptr<TextureAtlasPage>>& getPages() const { return pages_; }
|
||||
|
||||
// 获取总使用率
|
||||
float getTotalUsageRatio() const;
|
||||
|
||||
// 清空所有图集
|
||||
void clear();
|
||||
|
||||
// 设置是否启用自动图集
|
||||
void setEnabled(bool enabled) { enabled_ = enabled; }
|
||||
bool isEnabled() const { return enabled_; }
|
||||
|
||||
// 设置纹理大小阈值(小于此大小的纹理才进入图集)
|
||||
void setSizeThreshold(int threshold) { sizeThreshold_ = threshold; }
|
||||
int getSizeThreshold() const { return sizeThreshold_; }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<TextureAtlasPage>> pages_;
|
||||
std::unordered_map<std::string, TextureAtlasPage*> entryToPage_;
|
||||
|
||||
int pageSize_;
|
||||
int sizeThreshold_;
|
||||
bool enabled_;
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 全局图集管理器(单例)
|
||||
*/
|
||||
class TextureAtlasMgr {
|
||||
public:
|
||||
static TextureAtlasMgr& get();
|
||||
|
||||
// 获取主图集
|
||||
TextureAtlas& getAtlas() { return atlas_; }
|
||||
|
||||
// 快捷方法
|
||||
bool addTexture(const std::string& name, int width, int height,
|
||||
const uint8_t* pixels) {
|
||||
return atlas_.addTexture(name, width, height, pixels);
|
||||
}
|
||||
|
||||
bool contains(const std::string& name) const {
|
||||
return atlas_.contains(name);
|
||||
}
|
||||
|
||||
const Texture* getAtlasTexture(const std::string& name) const {
|
||||
return atlas_.getAtlasTexture(name);
|
||||
}
|
||||
|
||||
Rect getUVRect(const std::string& name) const {
|
||||
return atlas_.getUVRect(name);
|
||||
}
|
||||
|
||||
private:
|
||||
TextureAtlasMgr() = default;
|
||||
~TextureAtlasMgr() = default;
|
||||
|
||||
TextureAtlasMgr(const TextureAtlasMgr&) = delete;
|
||||
TextureAtlasMgr& operator=(const TextureAtlasMgr&) = delete;
|
||||
|
||||
TextureAtlas atlas_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,561 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
class Scene;
|
||||
class RenderBackend;
|
||||
|
||||
// ============================================================================
|
||||
// 纹理加载选项
|
||||
// ============================================================================
|
||||
struct TextureLoadOptions {
|
||||
bool generateMipmaps = true; // 是否生成 mipmaps
|
||||
bool sRGB = true; // 是否使用 sRGB 色彩空间
|
||||
bool premultiplyAlpha = false; // 是否预乘 Alpha
|
||||
PixelFormat preferredFormat = PixelFormat::RGBA8; // 首选像素格式
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 纹理键 - 用于唯一标识纹理缓存条目
|
||||
// ============================================================================
|
||||
struct TextureKey {
|
||||
std::string path; // 纹理文件路径
|
||||
Rect region; // 纹理区域(用于纹理图集)
|
||||
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*/
|
||||
TextureKey() = default;
|
||||
|
||||
/**
|
||||
* @brief 构造函数(仅路径)
|
||||
* @param p 纹理文件路径
|
||||
*/
|
||||
explicit TextureKey(const std::string &p) : path(p), region(Rect::Zero()) {}
|
||||
|
||||
/**
|
||||
* @brief 构造函数(路径 + 区域)
|
||||
* @param p 纹理文件路径
|
||||
* @param r 纹理区域
|
||||
*/
|
||||
TextureKey(const std::string &p, const Rect &r) : path(p), region(r) {}
|
||||
|
||||
/**
|
||||
* @brief 相等比较运算符
|
||||
* @param other 另一个 TextureKey
|
||||
* @return 是否相等
|
||||
*/
|
||||
bool operator==(const TextureKey &other) const {
|
||||
return path == other.path && region == other.region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 不等比较运算符
|
||||
* @param other 另一个 TextureKey
|
||||
* @return 是否不等
|
||||
*/
|
||||
bool operator!=(const TextureKey &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// TextureKey 哈希函子
|
||||
// ============================================================================
|
||||
struct TextureKeyHash {
|
||||
/**
|
||||
* @brief 计算 TextureKey 的哈希值
|
||||
* @param key 纹理键
|
||||
* @return 哈希值
|
||||
*/
|
||||
size_t operator()(const TextureKey &key) const {
|
||||
size_t h1 = std::hash<std::string>{}(key.path);
|
||||
size_t h2 = std::hash<float>{}(key.region.origin.x);
|
||||
size_t h3 = std::hash<float>{}(key.region.origin.y);
|
||||
size_t h4 = std::hash<float>{}(key.region.size.width);
|
||||
size_t h5 = std::hash<float>{}(key.region.size.height);
|
||||
|
||||
// 组合哈希值
|
||||
size_t result = h1;
|
||||
result ^= h2 + 0x9e3779b9 + (result << 6) + (result >> 2);
|
||||
result ^= h3 + 0x9e3779b9 + (result << 6) + (result >> 2);
|
||||
result ^= h4 + 0x9e3779b9 + (result << 6) + (result >> 2);
|
||||
result ^= h5 + 0x9e3779b9 + (result << 6) + (result >> 2);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 纹理池条目
|
||||
// ============================================================================
|
||||
struct TexturePoolEntry {
|
||||
Ptr<Texture> texture; // 纹理对象
|
||||
mutable std::atomic<uint32_t> refCount; // 引用计数
|
||||
TextureKey key; // 纹理键
|
||||
size_t memorySize; // 内存占用(字节)
|
||||
mutable uint64_t lastAccessTime; // 最后访问时间戳
|
||||
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*/
|
||||
TexturePoolEntry()
|
||||
: texture(nullptr), refCount(0), key(), memorySize(0), lastAccessTime(0) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param tex 纹理对象
|
||||
* @param k 纹理键
|
||||
* @param memSize 内存占用
|
||||
*/
|
||||
TexturePoolEntry(Ptr<Texture> tex, const TextureKey &k, size_t memSize)
|
||||
: texture(tex), refCount(1), key(k), memorySize(memSize),
|
||||
lastAccessTime(getCurrentTime()) {}
|
||||
|
||||
/**
|
||||
* @brief 移动构造函数
|
||||
* @param other 另一个条目
|
||||
*/
|
||||
TexturePoolEntry(TexturePoolEntry &&other) noexcept
|
||||
: texture(std::move(other.texture)),
|
||||
refCount(other.refCount.load(std::memory_order_relaxed)),
|
||||
key(std::move(other.key)), memorySize(other.memorySize),
|
||||
lastAccessTime(other.lastAccessTime) {}
|
||||
|
||||
/**
|
||||
* @brief 移动赋值运算符
|
||||
* @param other 另一个条目
|
||||
* @return 引用
|
||||
*/
|
||||
TexturePoolEntry &operator=(TexturePoolEntry &&other) noexcept {
|
||||
if (this != &other) {
|
||||
texture = std::move(other.texture);
|
||||
refCount.store(other.refCount.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
key = std::move(other.key);
|
||||
memorySize = other.memorySize;
|
||||
lastAccessTime = other.lastAccessTime;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 禁止拷贝
|
||||
TexturePoolEntry(const TexturePoolEntry &) = delete;
|
||||
TexturePoolEntry &operator=(const TexturePoolEntry &) = delete;
|
||||
|
||||
/**
|
||||
* @brief 更新最后访问时间
|
||||
*/
|
||||
void touch() const { lastAccessTime = getCurrentTime(); }
|
||||
|
||||
/**
|
||||
* @brief 获取当前时间戳
|
||||
* @return 时间戳(毫秒)
|
||||
*/
|
||||
static uint64_t getCurrentTime() {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch());
|
||||
return static_cast<uint64_t>(duration.count());
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 纹理引用智能指针 - 自动管理纹理池引用计数
|
||||
// ============================================================================
|
||||
class TextureRef {
|
||||
public:
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*/
|
||||
TextureRef() : texture_(nullptr), entry_(nullptr), mutex_(nullptr) {}
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param texture 纹理对象
|
||||
* @param entry 纹理池条目
|
||||
* @param mutex 互斥锁
|
||||
*/
|
||||
TextureRef(Ptr<Texture> texture, TexturePoolEntry *entry, std::mutex *mutex)
|
||||
: texture_(texture), entry_(entry), mutex_(mutex) {}
|
||||
|
||||
/**
|
||||
* @brief 创建独立的纹理引用(不管理引用计数)
|
||||
* @param texture 纹理对象
|
||||
* @return 独立的纹理引用
|
||||
*/
|
||||
static TextureRef fromTexture(Ptr<Texture> texture) {
|
||||
return TextureRef(texture, nullptr, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 拷贝构造函数
|
||||
* @param other 另一个 TextureRef
|
||||
*/
|
||||
TextureRef(const TextureRef &other)
|
||||
: texture_(other.texture_), entry_(other.entry_), mutex_(other.mutex_) {
|
||||
if (entry_ && entry_->refCount.load(std::memory_order_relaxed) > 0) {
|
||||
entry_->refCount.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动构造函数
|
||||
* @param other 另一个 TextureRef
|
||||
*/
|
||||
TextureRef(TextureRef &&other) noexcept
|
||||
: texture_(std::move(other.texture_)), entry_(other.entry_),
|
||||
mutex_(other.mutex_) {
|
||||
other.entry_ = nullptr;
|
||||
other.mutex_ = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~TextureRef() { reset(); }
|
||||
|
||||
/**
|
||||
* @brief 拷贝赋值运算符
|
||||
* @param other 另一个 TextureRef
|
||||
* @return 引用
|
||||
*/
|
||||
TextureRef &operator=(const TextureRef &other) {
|
||||
if (this != &other) {
|
||||
reset();
|
||||
texture_ = other.texture_;
|
||||
entry_ = other.entry_;
|
||||
mutex_ = other.mutex_;
|
||||
if (entry_ && entry_->refCount.load(std::memory_order_relaxed) > 0) {
|
||||
entry_->refCount.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动赋值运算符
|
||||
* @param other 另一个 TextureRef
|
||||
* @return 引用
|
||||
*/
|
||||
TextureRef &operator=(TextureRef &&other) noexcept {
|
||||
if (this != &other) {
|
||||
reset();
|
||||
texture_ = std::move(other.texture_);
|
||||
entry_ = other.entry_;
|
||||
mutex_ = other.mutex_;
|
||||
other.entry_ = nullptr;
|
||||
other.mutex_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重置引用
|
||||
*/
|
||||
void reset() {
|
||||
if (entry_ && mutex_) {
|
||||
std::lock_guard<std::mutex> lock(*mutex_);
|
||||
if (entry_->refCount.load(std::memory_order_relaxed) > 0) {
|
||||
entry_->refCount.fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
texture_.reset();
|
||||
entry_ = nullptr;
|
||||
mutex_ = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取纹理对象
|
||||
* @return 纹理对象指针
|
||||
*/
|
||||
Texture *get() const { return texture_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取纹理对象(智能指针)
|
||||
* @return 纹理对象智能指针
|
||||
*/
|
||||
Ptr<Texture> getPtr() const { return texture_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
* @return 是否有效
|
||||
*/
|
||||
bool valid() const { return texture_ != nullptr; }
|
||||
|
||||
/**
|
||||
* @brief 布尔转换运算符
|
||||
*/
|
||||
explicit operator bool() const { return valid(); }
|
||||
|
||||
/**
|
||||
* @brief 箭头运算符
|
||||
*/
|
||||
Texture *operator->() const { return texture_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 解引用运算符
|
||||
*/
|
||||
Texture &operator*() const { return *texture_; }
|
||||
|
||||
private:
|
||||
Ptr<Texture> texture_;
|
||||
TexturePoolEntry *entry_;
|
||||
std::mutex *mutex_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 纹理池 - 纹理缓存和内存管理系统
|
||||
// 特性:
|
||||
// - 纹理缓存和复用
|
||||
// - 引用计数管理
|
||||
// - 内存使用限制
|
||||
// - LRU 淘汰策略
|
||||
// - 线程安全
|
||||
// ============================================================================
|
||||
class TexturePool {
|
||||
public:
|
||||
// ========================================================================
|
||||
// 统计信息
|
||||
// ========================================================================
|
||||
struct Stats {
|
||||
size_t textureCount = 0; // 纹理数量
|
||||
size_t memoryUsage = 0; // 内存使用量(字节)
|
||||
size_t maxMemoryUsage = 0; // 最大内存使用量
|
||||
size_t cacheHits = 0; // 缓存命中次数
|
||||
size_t cacheMisses = 0; // 缓存未命中次数
|
||||
size_t evictionCount = 0; // 淘汰次数
|
||||
};
|
||||
|
||||
// ========================================================================
|
||||
// 构造和析构
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*/
|
||||
TexturePool();
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param scene 场景指针
|
||||
* @param maxMemoryUsage 最大内存使用量(0 表示无限制)
|
||||
*/
|
||||
explicit TexturePool(Scene *scene, size_t maxMemoryUsage = 0);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~TexturePool();
|
||||
|
||||
// 禁止拷贝
|
||||
TexturePool(const TexturePool &) = delete;
|
||||
TexturePool &operator=(const TexturePool &) = delete;
|
||||
|
||||
/**
|
||||
* @brief 初始化纹理池
|
||||
* @param scene 场景指针
|
||||
* @param maxMemoryUsage 最大内存使用量(0 表示无限制)
|
||||
*/
|
||||
void init(Scene *scene, size_t maxMemoryUsage = 0);
|
||||
|
||||
// ========================================================================
|
||||
// 纹理加载
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 从文件加载纹理
|
||||
* @param path 文件路径
|
||||
* @param options 加载选项
|
||||
* @return 纹理引用
|
||||
*/
|
||||
TextureRef load(const std::string &path,
|
||||
const TextureLoadOptions &options = TextureLoadOptions());
|
||||
|
||||
/**
|
||||
* @brief 从文件加载纹理区域
|
||||
* @param path 文件路径
|
||||
* @param region 纹理区域
|
||||
* @param options 加载选项
|
||||
* @return 纹理引用
|
||||
*/
|
||||
TextureRef load(const std::string &path, const Rect ®ion,
|
||||
const TextureLoadOptions &options = TextureLoadOptions());
|
||||
|
||||
/**
|
||||
* @brief 从内存加载纹理
|
||||
* @param data 像素数据
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param channels 通道数
|
||||
* @param key 缓存键
|
||||
* @return 纹理引用
|
||||
*/
|
||||
TextureRef loadFromMemory(const uint8_t *data, int width, int height,
|
||||
int channels, const std::string &key);
|
||||
|
||||
/**
|
||||
* @brief 获取或加载纹理
|
||||
* @param path 文件路径
|
||||
* @param options 加载选项
|
||||
* @return 纹理引用
|
||||
*/
|
||||
TextureRef
|
||||
getOrLoad(const std::string &path,
|
||||
const TextureLoadOptions &options = TextureLoadOptions());
|
||||
|
||||
/**
|
||||
* @brief 获取或加载纹理区域
|
||||
* @param path 文件路径
|
||||
* @param region 纹理区域
|
||||
* @param options 加载选项
|
||||
* @return 纹理引用
|
||||
*/
|
||||
TextureRef
|
||||
getOrLoad(const std::string &path, const Rect ®ion,
|
||||
const TextureLoadOptions &options = TextureLoadOptions());
|
||||
|
||||
// ========================================================================
|
||||
// 引用计数管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 增加引用计数
|
||||
* @param key 纹理键
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool addRef(const TextureKey &key);
|
||||
|
||||
/**
|
||||
* @brief 减少引用计数
|
||||
* @param key 纹理键
|
||||
* @return 减少后的引用计数
|
||||
*/
|
||||
uint32_t release(const TextureKey &key);
|
||||
|
||||
/**
|
||||
* @brief 获取引用计数
|
||||
* @param key 纹理键
|
||||
* @return 引用计数
|
||||
*/
|
||||
uint32_t getRefCount(const TextureKey &key) const;
|
||||
|
||||
// ========================================================================
|
||||
// 缓存管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 检查纹理是否已缓存
|
||||
* @param key 纹理键
|
||||
* @return 是否已缓存
|
||||
*/
|
||||
bool isCached(const TextureKey &key) const;
|
||||
|
||||
/**
|
||||
* @brief 从缓存中移除纹理
|
||||
* @param key 纹理键
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool removeFromCache(const TextureKey &key);
|
||||
|
||||
/**
|
||||
* @brief 垃圾回收(移除引用计数为 0 的纹理)
|
||||
* @return 移除的纹理数量
|
||||
*/
|
||||
size_t collectGarbage();
|
||||
|
||||
/**
|
||||
* @brief 清空所有缓存
|
||||
*/
|
||||
void clear();
|
||||
|
||||
// ========================================================================
|
||||
// 内存管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取当前内存使用量
|
||||
* @return 内存使用量(字节)
|
||||
*/
|
||||
size_t getMemoryUsage() const;
|
||||
|
||||
/**
|
||||
* @brief 设置最大内存使用量
|
||||
* @param maxMemory 最大内存使用量(0 表示无限制)
|
||||
*/
|
||||
void setMaxMemoryUsage(size_t maxMemory);
|
||||
|
||||
/**
|
||||
* @brief 获取最大内存使用量
|
||||
* @return 最大内存使用量
|
||||
*/
|
||||
size_t getMaxMemoryUsage() const { return maxMemoryUsage_; }
|
||||
|
||||
/**
|
||||
* @brief 执行 LRU 淘汰
|
||||
* @param targetMemory 目标内存使用量
|
||||
* @return 淘汰的纹理数量
|
||||
*/
|
||||
size_t evictLRU(size_t targetMemory = 0);
|
||||
|
||||
// ========================================================================
|
||||
// 统计信息
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取统计信息
|
||||
* @return 统计信息
|
||||
*/
|
||||
Stats getStats() const;
|
||||
|
||||
/**
|
||||
* @brief 重置统计信息
|
||||
*/
|
||||
void resetStats();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 计算纹理内存大小
|
||||
* @param texture 纹理对象
|
||||
* @return 内存大小(字节)
|
||||
*/
|
||||
static size_t calculateTextureMemory(const Texture *texture);
|
||||
|
||||
/**
|
||||
* @brief 检查是否需要淘汰
|
||||
* @return 是否需要淘汰
|
||||
*/
|
||||
bool needsEviction() const;
|
||||
|
||||
/**
|
||||
* @brief 尝试自动淘汰
|
||||
*/
|
||||
void tryAutoEvict();
|
||||
|
||||
Scene *scene_; // 场景指针
|
||||
mutable std::mutex mutex_; // 互斥锁
|
||||
std::unordered_map<TextureKey, TexturePoolEntry, TextureKeyHash>
|
||||
cache_; // 纹理缓存
|
||||
|
||||
size_t maxMemoryUsage_; // 最大内存使用量
|
||||
size_t currentMemoryUsage_; // 当前内存使用量
|
||||
|
||||
// 统计信息
|
||||
mutable std::atomic<size_t> cacheHits_;
|
||||
mutable std::atomic<size_t> cacheMisses_;
|
||||
mutable std::atomic<size_t> evictionCount_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 平台后端工厂
|
||||
* 用于注册和创建平台后端
|
||||
*/
|
||||
class BackendFactory {
|
||||
public:
|
||||
using WindowFn = std::function<UniquePtr<IWindow>()>;
|
||||
using InputFn = std::function<UniquePtr<IInput>()>;
|
||||
|
||||
/**
|
||||
* @brief 注册平台后端
|
||||
* @param name 后端名称
|
||||
* @param win 窗口创建函数
|
||||
* @param in 输入创建函数
|
||||
*/
|
||||
static void reg(const std::string& name, WindowFn win, InputFn in);
|
||||
|
||||
/**
|
||||
* @brief 创建窗口实例
|
||||
* @param name 后端名称
|
||||
* @return 窗口实例,如果后端不存在返回 nullptr
|
||||
*/
|
||||
static UniquePtr<IWindow> createWindow(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 创建输入实例
|
||||
* @param name 后端名称
|
||||
* @return 输入实例,如果后端不存在返回 nullptr
|
||||
*/
|
||||
static UniquePtr<IInput> createInput(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有已注册的后端名称
|
||||
*/
|
||||
static std::vector<std::string> backends();
|
||||
|
||||
/**
|
||||
* @brief 检查后端是否存在
|
||||
*/
|
||||
static bool has(const std::string& name);
|
||||
|
||||
private:
|
||||
struct BackendEntry {
|
||||
WindowFn windowFn;
|
||||
InputFn inputFn;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, BackendEntry>& registry();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 平台后端注册宏
|
||||
* 在全局作用域使用此宏注册平台后端
|
||||
*
|
||||
* @example
|
||||
* E2D_REG_BACKEND(sdl2, SDL2Window, SDL2Input)
|
||||
*/
|
||||
#define E2D_REG_BACKEND(name, WinClass, InClass) \
|
||||
namespace { \
|
||||
__attribute__((used)) \
|
||||
static struct E2D_BACKEND_REG_##name { \
|
||||
E2D_BACKEND_REG_##name() { \
|
||||
::extra2d::BackendFactory::reg( \
|
||||
#name, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \
|
||||
return ::extra2d::makeUnique<WinClass>(); \
|
||||
}, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::IInput> { \
|
||||
return ::extra2d::makeUnique<InClass>(); \
|
||||
} \
|
||||
); \
|
||||
} \
|
||||
} e2d_backend_reg_##name; \
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/platform/keys.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 触摸点信息
|
||||
*/
|
||||
struct TouchPoint {
|
||||
int id = 0;
|
||||
Vec2 position;
|
||||
Vec2 delta;
|
||||
bool pressed = false;
|
||||
bool released = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 输入抽象接口
|
||||
* 所有平台输入后端必须实现此接口
|
||||
*/
|
||||
class IInput {
|
||||
public:
|
||||
virtual ~IInput() = default;
|
||||
|
||||
/**
|
||||
* @brief 初始化输入系统
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭输入系统
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 每帧更新输入状态
|
||||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
// ========== 键盘 ==========
|
||||
|
||||
/**
|
||||
* @brief 检测按键是否按下(持续状态)
|
||||
*/
|
||||
virtual bool down(Key key) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测按键是否刚按下(仅当前帧)
|
||||
*/
|
||||
virtual bool pressed(Key key) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测按键是否刚释放(仅当前帧)
|
||||
*/
|
||||
virtual bool released(Key key) const = 0;
|
||||
|
||||
// ========== 鼠标 ==========
|
||||
|
||||
/**
|
||||
* @brief 检测鼠标按钮是否按下
|
||||
*/
|
||||
virtual bool down(Mouse btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测鼠标按钮是否刚按下
|
||||
*/
|
||||
virtual bool pressed(Mouse btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测鼠标按钮是否刚释放
|
||||
*/
|
||||
virtual bool released(Mouse btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取鼠标位置
|
||||
*/
|
||||
virtual Vec2 mouse() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取鼠标移动增量
|
||||
*/
|
||||
virtual Vec2 mouseDelta() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取滚轮值
|
||||
*/
|
||||
virtual float scroll() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取滚轮增量
|
||||
*/
|
||||
virtual float scrollDelta() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置鼠标位置
|
||||
*/
|
||||
virtual void setMouse(const Vec2& pos) = 0;
|
||||
|
||||
// ========== 手柄 ==========
|
||||
|
||||
/**
|
||||
* @brief 检测手柄是否连接
|
||||
*/
|
||||
virtual bool gamepad() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测手柄按钮是否按下
|
||||
*/
|
||||
virtual bool down(Gamepad btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测手柄按钮是否刚按下
|
||||
*/
|
||||
virtual bool pressed(Gamepad btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检测手柄按钮是否刚释放
|
||||
*/
|
||||
virtual bool released(Gamepad btn) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取左摇杆值
|
||||
*/
|
||||
virtual Vec2 leftStick() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取右摇杆值
|
||||
*/
|
||||
virtual Vec2 rightStick() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取左扳机值
|
||||
*/
|
||||
virtual float leftTrigger() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取右扳机值
|
||||
*/
|
||||
virtual float rightTrigger() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置手柄振动
|
||||
* @param left 左马达强度 [0, 1]
|
||||
* @param right 右马达强度 [0, 1]
|
||||
*/
|
||||
virtual void vibrate(float left, float right) = 0;
|
||||
|
||||
// ========== 触摸 ==========
|
||||
|
||||
/**
|
||||
* @brief 检测是否有触摸
|
||||
*/
|
||||
virtual bool touching() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取触摸点数量
|
||||
*/
|
||||
virtual int touchCount() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取触摸点位置
|
||||
* @param index 触摸点索引
|
||||
*/
|
||||
virtual Vec2 touch(int index) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取触摸点信息
|
||||
* @param index 触摸点索引
|
||||
*/
|
||||
virtual TouchPoint touchPoint(int index) const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <functional>
|
||||
#include <typeindex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 输入模块配置结构
|
||||
*/
|
||||
struct InputCfg {
|
||||
float deadzone;
|
||||
float mouseSensitivity;
|
||||
bool enableVibration;
|
||||
int maxGamepads;
|
||||
int priority;
|
||||
|
||||
InputCfg()
|
||||
: deadzone(0.15f)
|
||||
, mouseSensitivity(1.0f)
|
||||
, enableVibration(true)
|
||||
, maxGamepads(4)
|
||||
, priority(20)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 输入模块
|
||||
* 管理输入设备
|
||||
*/
|
||||
class InputModule : public Module {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数(Lambda 配置)
|
||||
* @param configFn 配置函数
|
||||
*/
|
||||
explicit InputModule(std::function<void(InputCfg&)> configFn);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~InputModule() override;
|
||||
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
bool ok() const override { return initialized_; }
|
||||
const char* name() const override { return "input"; }
|
||||
int priority() const override { return cfg_.priority; }
|
||||
|
||||
/**
|
||||
* @brief 获取依赖
|
||||
* @return 依赖模块类型列表
|
||||
*/
|
||||
std::vector<std::type_index> deps() const override {
|
||||
return {std::type_index(typeid(WindowModule))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取输入接口
|
||||
* @return 输入接口指针
|
||||
*/
|
||||
IInput* input() const { return input_; }
|
||||
|
||||
/**
|
||||
* @brief 更新输入状态
|
||||
*/
|
||||
void update();
|
||||
|
||||
private:
|
||||
InputCfg cfg_;
|
||||
IInput* input_ = nullptr;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/platform/window_config.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IInput;
|
||||
|
||||
/**
|
||||
* @brief 光标形状
|
||||
*/
|
||||
enum class Cursor {
|
||||
Arrow,
|
||||
IBeam,
|
||||
Crosshair,
|
||||
Hand,
|
||||
HResize,
|
||||
VResize,
|
||||
Hidden
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 窗口抽象接口
|
||||
* 所有平台窗口后端必须实现此接口
|
||||
*/
|
||||
class IWindow {
|
||||
public:
|
||||
virtual ~IWindow() = default;
|
||||
|
||||
/**
|
||||
* @brief 创建窗口
|
||||
* @param cfg 窗口配置
|
||||
* @return 创建是否成功
|
||||
*/
|
||||
virtual bool create(const WindowConfigData& cfg) = 0;
|
||||
|
||||
/**
|
||||
* @brief 销毁窗口
|
||||
*/
|
||||
virtual void destroy() = 0;
|
||||
|
||||
/**
|
||||
* @brief 轮询事件
|
||||
*/
|
||||
virtual void poll() = 0;
|
||||
|
||||
/**
|
||||
* @brief 交换缓冲区
|
||||
*/
|
||||
virtual void swap() = 0;
|
||||
|
||||
/**
|
||||
* @brief 窗口是否应该关闭
|
||||
*/
|
||||
virtual bool shouldClose() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置窗口关闭标志
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置窗口标题
|
||||
*/
|
||||
virtual void setTitle(const std::string& title) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置窗口大小
|
||||
*/
|
||||
virtual void setSize(int w, int h) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置窗口位置
|
||||
*/
|
||||
virtual void setPos(int x, int y) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置全屏模式
|
||||
*/
|
||||
virtual void setFullscreen(bool fs) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
virtual void setVSync(bool vsync) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置窗口可见性
|
||||
*/
|
||||
virtual void setVisible(bool visible) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
virtual int width() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
virtual int height() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口大小
|
||||
*/
|
||||
virtual Size size() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口位置
|
||||
*/
|
||||
virtual Vec2 pos() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 是否全屏
|
||||
*/
|
||||
virtual bool fullscreen() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 是否启用垂直同步
|
||||
*/
|
||||
virtual bool vsync() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 窗口是否获得焦点
|
||||
*/
|
||||
virtual bool focused() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 窗口是否最小化
|
||||
*/
|
||||
virtual bool minimized() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取内容缩放X
|
||||
*/
|
||||
virtual float scaleX() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取内容缩放Y
|
||||
*/
|
||||
virtual float scaleY() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置光标形状
|
||||
*/
|
||||
virtual void setCursor(Cursor cursor) = 0;
|
||||
|
||||
/**
|
||||
* @brief 显示/隐藏光标
|
||||
*/
|
||||
virtual void showCursor(bool show) = 0;
|
||||
|
||||
/**
|
||||
* @brief 锁定/解锁光标
|
||||
*/
|
||||
virtual void lockCursor(bool lock) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取输入接口
|
||||
*/
|
||||
virtual IInput* input() const = 0;
|
||||
|
||||
/**
|
||||
* @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) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置关闭回调
|
||||
*/
|
||||
virtual void onClose(CloseCb cb) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置焦点改变回调
|
||||
*/
|
||||
virtual void onFocus(FocusCb cb) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取原生窗口句柄
|
||||
*/
|
||||
virtual void* native() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 键盘按键码
|
||||
*/
|
||||
enum class Key : int {
|
||||
None = 0,
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
Num0, Num1, Num2, Num3, Num4,
|
||||
Num5, Num6, Num7, Num8, Num9,
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
Space, Enter, Escape, Tab, Backspace,
|
||||
Insert, Delete, Home, End, PageUp, PageDown,
|
||||
Up, Down, Left, Right,
|
||||
LShift, RShift, LCtrl, RCtrl, LAlt, RAlt,
|
||||
CapsLock, NumLock, ScrollLock,
|
||||
Count
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 鼠标按钮
|
||||
*/
|
||||
enum class Mouse : int {
|
||||
Left = 0,
|
||||
Right,
|
||||
Middle,
|
||||
X1,
|
||||
X2,
|
||||
Count
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 游戏手柄按钮
|
||||
*/
|
||||
enum class Gamepad : int {
|
||||
A = 0,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
LB,
|
||||
RB,
|
||||
LT,
|
||||
RT,
|
||||
Back,
|
||||
Start,
|
||||
Guide,
|
||||
LStick,
|
||||
RStick,
|
||||
DUp,
|
||||
DDown,
|
||||
DLeft,
|
||||
DRight,
|
||||
Count
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 手柄轴
|
||||
*/
|
||||
enum class GamepadAxis : int {
|
||||
LeftX = 0,
|
||||
LeftY,
|
||||
RightX,
|
||||
RightY,
|
||||
LeftTrigger,
|
||||
RightTrigger,
|
||||
Count
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @file window_config.h
|
||||
* @brief 窗口模块配置
|
||||
*
|
||||
* 定义窗口相关的配置数据结构,由 WindowModule 管理。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 窗口模式枚举
|
||||
*/
|
||||
enum class WindowMode {
|
||||
Windowed,
|
||||
Fullscreen,
|
||||
Borderless
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 窗口配置数据结构
|
||||
*/
|
||||
struct WindowConfigData {
|
||||
std::string title = "Extra2D Application";
|
||||
int width = 1280;
|
||||
int height = 720;
|
||||
int minWidth = 320;
|
||||
int minHeight = 240;
|
||||
int maxWidth = 0;
|
||||
int maxHeight = 0;
|
||||
WindowMode mode = WindowMode::Windowed;
|
||||
bool resizable = true;
|
||||
bool borderless = false;
|
||||
bool alwaysOnTop = false;
|
||||
bool centered = true;
|
||||
int posX = -1;
|
||||
int posY = -1;
|
||||
bool hideOnClose = false;
|
||||
bool minimizeOnClose = true;
|
||||
float opacity = 1.0f;
|
||||
bool transparentFramebuffer = false;
|
||||
bool highDPI = true;
|
||||
float contentScale = 1.0f;
|
||||
bool vsync = true;
|
||||
int multisamples = 0;
|
||||
bool visible = true;
|
||||
bool decorated = true;
|
||||
|
||||
/**
|
||||
* @brief 检查窗口尺寸是否有效
|
||||
* @return 如果宽高都大于0返回 true
|
||||
*/
|
||||
bool isSizeValid() const { return width > 0 && height > 0; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否设置了窗口位置
|
||||
* @return 如果设置了有效位置返回 true
|
||||
*/
|
||||
bool hasPosition() const { return posX >= 0 && posY >= 0; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽高比
|
||||
* @return 宽高比值
|
||||
*/
|
||||
float aspectRatio() const { return static_cast<float>(width) / static_cast<float>(height); }
|
||||
|
||||
/**
|
||||
* @brief 检查是否为全屏模式
|
||||
* @return 如果是全屏模式返回 true
|
||||
*/
|
||||
bool isFullscreen() const { return mode == WindowMode::Fullscreen; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否为无边框模式
|
||||
* @return 如果是无边框模式返回 true
|
||||
*/
|
||||
bool isBorderless() const { return mode == WindowMode::Borderless || borderless; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/window_config.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 窗口模块配置结构
|
||||
*/
|
||||
struct WindowCfg {
|
||||
std::string title;
|
||||
int w;
|
||||
int h;
|
||||
WindowMode mode;
|
||||
bool vsync;
|
||||
int priority;
|
||||
std::string backend;
|
||||
|
||||
WindowCfg()
|
||||
: title("Extra2D"), w(1280), h(720), mode(WindowMode::Windowed),
|
||||
vsync(true), priority(0), backend("sdl2") {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 窗口模块
|
||||
* 管理窗口创建和生命周期
|
||||
*/
|
||||
class WindowModule : public Module {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数(Lambda 配置)
|
||||
* @param configFn 配置函数
|
||||
*/
|
||||
explicit WindowModule(std::function<void(WindowCfg &)> configFn);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~WindowModule() override;
|
||||
|
||||
bool init() override;
|
||||
void shutdown() override;
|
||||
bool ok() const override { return initialized_; }
|
||||
const char *name() const override { return "window"; }
|
||||
int priority() const override { return cfg_.priority; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口
|
||||
* @return 窗口指针
|
||||
*/
|
||||
IWindow *win() const { return win_.get(); }
|
||||
|
||||
private:
|
||||
WindowCfg cfg_;
|
||||
UniquePtr<IWindow> win_;
|
||||
bool initialized_ = false;
|
||||
bool sdlInited_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/event/event_dispatcher.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
class Scene;
|
||||
class RenderBackend;
|
||||
struct RenderCommand;
|
||||
|
||||
// ============================================================================
|
||||
// 节点基类 - 场景图的基础
|
||||
// ============================================================================
|
||||
class Node : public std::enable_shared_from_this<Node> {
|
||||
public:
|
||||
Node();
|
||||
virtual ~Node();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 层级管理
|
||||
// ------------------------------------------------------------------------
|
||||
void addChild(Ptr<Node> child);
|
||||
|
||||
/**
|
||||
* @brief 批量添加子节点
|
||||
* @param children 子节点列表
|
||||
*/
|
||||
void addChildren(std::vector<Ptr<Node>> &&children);
|
||||
|
||||
void removeChild(Ptr<Node> child);
|
||||
void removeChildByName(const std::string &name);
|
||||
void detach();
|
||||
void clearChildren();
|
||||
|
||||
Ptr<Node> getParent() const { return parent_.lock(); }
|
||||
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
|
||||
Ptr<Node> findChild(const std::string &name) const;
|
||||
Ptr<Node> findChildByTag(int tag) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 变换属性
|
||||
// ------------------------------------------------------------------------
|
||||
void setPos(const Vec2 &pos);
|
||||
void setPos(float x, float y);
|
||||
Vec2 getPosition() const { return position_; }
|
||||
|
||||
void setRotation(float degrees);
|
||||
float getRotation() const { return rotation_; }
|
||||
|
||||
void setScale(const Vec2 &scale);
|
||||
void setScale(float scale);
|
||||
void setScale(float x, float y);
|
||||
Vec2 getScale() const { return scale_; }
|
||||
|
||||
void setAnchor(const Vec2 &anchor);
|
||||
void setAnchor(float x, float y);
|
||||
Vec2 getAnchor() const { return anchor_; }
|
||||
|
||||
void setSkew(const Vec2 &skew);
|
||||
void setSkew(float x, float y);
|
||||
Vec2 getSkew() const { return skew_; }
|
||||
|
||||
void setOpacity(float opacity);
|
||||
float getOpacity() const { return opacity_; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
bool isVisible() const { return visible_; }
|
||||
|
||||
/**
|
||||
* @brief 设置颜色
|
||||
* @param color RGB颜色
|
||||
*/
|
||||
void setColor(const Color3B &color);
|
||||
Color3B getColor() const { return color_; }
|
||||
|
||||
/**
|
||||
* @brief 设置X轴翻转
|
||||
*/
|
||||
void setFlipX(bool flipX);
|
||||
bool isFlipX() const { return flipX_; }
|
||||
|
||||
/**
|
||||
* @brief 设置Y轴翻转
|
||||
*/
|
||||
void setFlipY(bool flipY);
|
||||
bool isFlipY() const { return flipY_; }
|
||||
|
||||
void setZOrder(int zOrder);
|
||||
int getZOrder() const { return zOrder_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 世界变换
|
||||
// ------------------------------------------------------------------------
|
||||
Vec2 toWorld(const Vec2 &localPos) const;
|
||||
Vec2 toLocal(const Vec2 &worldPos) const;
|
||||
|
||||
glm::mat4 getLocalTransform() const;
|
||||
glm::mat4 getWorldTransform() const;
|
||||
|
||||
/**
|
||||
* @brief 标记变换矩阵为脏状态,并传播到所有子节点
|
||||
*/
|
||||
void markTransformDirty();
|
||||
|
||||
/**
|
||||
* @brief 批量更新变换矩阵
|
||||
* 在渲染前统一计算所有脏节点的变换矩阵,避免逐节点计算时的重复递归
|
||||
*/
|
||||
void batchTransforms();
|
||||
|
||||
/**
|
||||
* @brief 获取变换脏标记状态
|
||||
*/
|
||||
bool isTransformDirty() const { return transformDirty_; }
|
||||
bool isWorldTransformDirty() const { return worldTransformDirty_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 名称和标签
|
||||
// ------------------------------------------------------------------------
|
||||
void setName(const std::string &name) { name_ = name; }
|
||||
const std::string &getName() const { return name_; }
|
||||
|
||||
void setTag(int tag) { tag_ = tag; }
|
||||
int getTag() const { return tag_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 生命周期回调
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void onEnter();
|
||||
virtual void onExit();
|
||||
virtual void onUpdate(float dt);
|
||||
virtual void onRender(RenderBackend &renderer);
|
||||
virtual void onAttachToScene(Scene *scene);
|
||||
virtual void onDetachFromScene();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 边界框
|
||||
// ------------------------------------------------------------------------
|
||||
virtual Rect getBounds() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 事件系统
|
||||
// ------------------------------------------------------------------------
|
||||
EventDispatcher &getEventDispatcher() { return eventDispatcher_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 内部方法
|
||||
// ------------------------------------------------------------------------
|
||||
void update(float dt);
|
||||
void render(RenderBackend &renderer);
|
||||
void sortChildren();
|
||||
|
||||
bool isRunning() const { return running_; }
|
||||
Scene *getScene() const { return scene_; }
|
||||
|
||||
// 多线程渲染命令收集
|
||||
virtual void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder = 0);
|
||||
|
||||
protected:
|
||||
// 子类重写
|
||||
virtual void onDraw(RenderBackend &renderer) {}
|
||||
virtual void onUpdateNode(float dt) {}
|
||||
virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||
int zOrder) {};
|
||||
|
||||
// 供子类访问的内部状态
|
||||
Vec2 &getPositionRef() { return position_; }
|
||||
Vec2 &getScaleRef() { return scale_; }
|
||||
Vec2 &getAnchorRef() { return anchor_; }
|
||||
float getRotationRef() { return rotation_; }
|
||||
float getOpacityRef() { return opacity_; }
|
||||
|
||||
private:
|
||||
// ==========================================================================
|
||||
// 成员变量按类型大小降序排列,减少内存对齐填充
|
||||
// 64位系统对齐:std::string(32) > glm::mat4(64) > std::vector(24) >
|
||||
// double(8) > float(4) > int(4) > bool(1)
|
||||
// ==========================================================================
|
||||
|
||||
// 1. 大块内存(64字节)
|
||||
mutable glm::mat4 localTransform_; // 64 bytes
|
||||
mutable glm::mat4 worldTransform_; // 64 bytes
|
||||
|
||||
// 2. 字符串和容器(24-32字节)
|
||||
std::string name_; // 32 bytes
|
||||
std::vector<Ptr<Node>> children_; // 24 bytes
|
||||
|
||||
// 3. 子节点索引(加速查找)
|
||||
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_; // 56 bytes
|
||||
std::unordered_map<int, WeakPtr<Node>> tagIndex_; // 56 bytes
|
||||
|
||||
// 4. 事件分发器
|
||||
EventDispatcher eventDispatcher_; // 大小取决于实现
|
||||
|
||||
// 5. 父节点引用
|
||||
WeakPtr<Node> parent_; // 16 bytes
|
||||
|
||||
// 7. 变换属性(按访问频率分组)
|
||||
Vec2 position_ = Vec2::Zero(); // 8 bytes
|
||||
Vec2 scale_ = Vec2(1.0f, 1.0f); // 8 bytes
|
||||
Vec2 anchor_ = Vec2(0.5f, 0.5f); // 8 bytes
|
||||
Vec2 skew_ = Vec2::Zero(); // 8 bytes
|
||||
|
||||
// 8. 浮点属性
|
||||
float rotation_ = 0.0f; // 4 bytes
|
||||
float opacity_ = 1.0f; // 4 bytes
|
||||
|
||||
// 10. 颜色属性
|
||||
Color3B color_ = Color3B(255, 255, 255); // 3 bytes
|
||||
|
||||
// 11. 整数属性
|
||||
int zOrder_ = 0; // 4 bytes
|
||||
int tag_ = -1; // 4 bytes
|
||||
|
||||
// 12. 布尔属性
|
||||
bool flipX_ = false; // 1 byte
|
||||
bool flipY_ = false; // 1 byte
|
||||
|
||||
// 13. 场景指针
|
||||
Scene *scene_ = nullptr; // 8 bytes
|
||||
|
||||
// 14. 布尔标志(打包在一起)
|
||||
mutable bool transformDirty_ = true; // 1 byte
|
||||
mutable bool worldTransformDirty_ = true; // 1 byte
|
||||
bool childrenOrderDirty_ = false; // 1 byte
|
||||
bool visible_ = true; // 1 byte
|
||||
bool running_ = false; // 1 byte
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
struct RenderCommand;
|
||||
|
||||
// ============================================================================
|
||||
// 场景类 - 节点容器,管理整个场景图
|
||||
// ============================================================================
|
||||
class Scene : public Node {
|
||||
public:
|
||||
Scene();
|
||||
~Scene() override = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景属性
|
||||
// ------------------------------------------------------------------------
|
||||
void setBackgroundColor(const Color &color) { backgroundColor_ = color; }
|
||||
Color getBackgroundColor() const { return backgroundColor_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 摄像机
|
||||
// ------------------------------------------------------------------------
|
||||
void setCamera(Ptr<Camera> camera);
|
||||
Ptr<Camera> getCamera() const { return camera_; }
|
||||
|
||||
Camera *getActiveCamera() const {
|
||||
return camera_ ? camera_.get() : defaultCamera_.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 视口和尺寸
|
||||
// ------------------------------------------------------------------------
|
||||
void setViewportSize(float width, float height);
|
||||
void setViewportSize(const Size &size);
|
||||
Size getViewportSize() const { return viewportSize_; }
|
||||
|
||||
float getWidth() const { return viewportSize_.width; }
|
||||
float getHeight() const { return viewportSize_.height; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景状态
|
||||
// ------------------------------------------------------------------------
|
||||
bool isPaused() const { return paused_; }
|
||||
void pause() { paused_ = true; }
|
||||
void resume() { paused_ = false; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 渲染和更新
|
||||
// ------------------------------------------------------------------------
|
||||
void renderScene(RenderBackend &renderer);
|
||||
virtual void renderContent(RenderBackend &renderer);
|
||||
void updateScene(float dt);
|
||||
void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder = 0) override;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 静态创建方法
|
||||
// ------------------------------------------------------------------------
|
||||
static Ptr<Scene> create();
|
||||
|
||||
protected:
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
|
||||
// 过渡场景生命周期回调(供 TransitionScene 使用)
|
||||
virtual void onExitTransitionDidStart() {}
|
||||
virtual void onEnterTransitionDidFinish() {}
|
||||
|
||||
friend class SceneManager;
|
||||
friend class TransitionScene;
|
||||
|
||||
private:
|
||||
Color backgroundColor_ = Colors::Black;
|
||||
Size viewportSize_ = Size::Zero();
|
||||
|
||||
Ptr<Camera> camera_;
|
||||
Ptr<Camera> defaultCamera_;
|
||||
|
||||
bool paused_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
struct RenderCommand;
|
||||
class TransitionScene;
|
||||
enum class TransitionType;
|
||||
|
||||
/**
|
||||
* @brief 场景管理器 - 管理场景的生命周期和切换
|
||||
*/
|
||||
class SceneManager {
|
||||
public:
|
||||
using TransitionCallback = std::function<void()>;
|
||||
|
||||
static SceneManager &get();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 基本场景操作(无过渡效果)
|
||||
// ------------------------------------------------------------------------
|
||||
void runWithScene(Ptr<Scene> scene);
|
||||
void replaceScene(Ptr<Scene> scene);
|
||||
void pushScene(Ptr<Scene> scene);
|
||||
void popScene();
|
||||
void popToRootScene();
|
||||
void popToScene(const std::string &name);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 带过渡效果的场景操作
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 替换当前场景(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void replaceScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 压入新场景(带过渡效果)
|
||||
* @param scene 新场景
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void pushScene(Ptr<Scene> scene, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出当前场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popScene(TransitionType transition, float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出到根场景(带过渡效果)
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popToRootScene(TransitionType transition, float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 弹出到指定场景(带过渡效果)
|
||||
* @param name 目标场景名称
|
||||
* @param transition 过渡类型
|
||||
* @param duration 过渡持续时间(秒)
|
||||
*/
|
||||
void popToScene(const std::string &name, TransitionType transition,
|
||||
float duration = 0.5f);
|
||||
|
||||
/**
|
||||
* @brief 使用自定义过渡场景进入场景
|
||||
* @param scene 新场景
|
||||
* @param transitionScene 过渡场景
|
||||
*/
|
||||
void enterScene(Ptr<Scene> scene, Ptr<TransitionScene> transitionScene);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景查询
|
||||
// ------------------------------------------------------------------------
|
||||
Ptr<Scene> getCurrentScene() const;
|
||||
Ptr<Scene> getPreviousScene() const;
|
||||
Ptr<Scene> getRootScene() const;
|
||||
Ptr<Scene> getSceneByName(const std::string &name) const;
|
||||
|
||||
size_t getSceneCount() const { return sceneStack_.size(); }
|
||||
bool isEmpty() const { return sceneStack_.empty(); }
|
||||
bool hasScene(const std::string &name) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 更新和渲染
|
||||
// ------------------------------------------------------------------------
|
||||
void update(float dt);
|
||||
void render(RenderBackend &renderer);
|
||||
void collectRenderCommands(std::vector<RenderCommand> &commands);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 过渡状态
|
||||
// ------------------------------------------------------------------------
|
||||
bool isTransitioning() const { return isTransitioning_; }
|
||||
void setTransitionCallback(TransitionCallback callback) {
|
||||
transitionCallback_ = callback;
|
||||
}
|
||||
|
||||
void end();
|
||||
void purgeCachedScenes();
|
||||
|
||||
public:
|
||||
SceneManager() = default;
|
||||
~SceneManager() = default;
|
||||
SceneManager(const SceneManager &) = delete;
|
||||
SceneManager &operator=(const SceneManager &) = delete;
|
||||
|
||||
void enterScene(Ptr<Scene> scene);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 启动过渡
|
||||
* @param from 源场景
|
||||
* @param to 目标场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param stackAction 过渡完成后的栈操作
|
||||
*/
|
||||
void startTransition(Ptr<Scene> from, Ptr<Scene> to, TransitionType type,
|
||||
float duration, std::function<void()> stackAction);
|
||||
|
||||
/**
|
||||
* @brief 创建过渡场景
|
||||
* @param type 过渡类型
|
||||
* @param duration 过渡持续时间
|
||||
* @param inScene 目标场景
|
||||
* @return 过渡场景智能指针
|
||||
*/
|
||||
Ptr<TransitionScene> createTransitionScene(TransitionType type, float duration,
|
||||
Ptr<Scene> inScene);
|
||||
|
||||
/**
|
||||
* @brief 完成过渡
|
||||
*/
|
||||
void finishTransition();
|
||||
|
||||
void doSceneSwitch();
|
||||
void dispatchPointerEvents(Scene &scene);
|
||||
|
||||
std::stack<Ptr<Scene>> sceneStack_;
|
||||
std::unordered_map<std::string, Ptr<Scene>> namedScenes_;
|
||||
|
||||
bool isTransitioning_ = false;
|
||||
TransitionCallback transitionCallback_;
|
||||
|
||||
Ptr<Scene> nextScene_;
|
||||
bool sendCleanupToScene_ = false;
|
||||
|
||||
Ptr<TransitionScene> activeTransitionScene_;
|
||||
std::function<void()> transitionStackAction_;
|
||||
|
||||
Node *hoverTarget_ = nullptr;
|
||||
Node *captureTarget_ = nullptr;
|
||||
Vec2 lastPointerWorld_ = Vec2::Zero();
|
||||
bool hasLastPointerWorld_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 形状类型
|
||||
// ============================================================================
|
||||
enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon };
|
||||
|
||||
// ============================================================================
|
||||
// 形状节点 - 用于绘制几何形状
|
||||
// ============================================================================
|
||||
class ShapeNode : public Node {
|
||||
public:
|
||||
ShapeNode();
|
||||
~ShapeNode() override = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 静态创建方法
|
||||
// ------------------------------------------------------------------------
|
||||
static Ptr<ShapeNode> create();
|
||||
|
||||
// 点
|
||||
static Ptr<ShapeNode> createPoint(const Vec2 &pos, const Color &color);
|
||||
|
||||
// 线
|
||||
static Ptr<ShapeNode> createLine(const Vec2 &start, const Vec2 &end,
|
||||
const Color &color, float width = 1.0f);
|
||||
|
||||
// 矩形
|
||||
static Ptr<ShapeNode> createRect(const Rect &rect, const Color &color,
|
||||
float width = 1.0f);
|
||||
static Ptr<ShapeNode> createFilledRect(const Rect &rect, const Color &color);
|
||||
|
||||
// 圆形
|
||||
static Ptr<ShapeNode> createCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color, int segments = 32,
|
||||
float width = 1.0f);
|
||||
static Ptr<ShapeNode> createFilledCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color,
|
||||
int segments = 32);
|
||||
|
||||
// 三角形
|
||||
static Ptr<ShapeNode> createTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||
const Vec2 &p3, const Color &color,
|
||||
float width = 1.0f);
|
||||
static Ptr<ShapeNode> createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||
const Vec2 &p3,
|
||||
const Color &color);
|
||||
|
||||
// 多边形
|
||||
static Ptr<ShapeNode> createPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color, float width = 1.0f);
|
||||
static Ptr<ShapeNode> createFilledPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 属性设置
|
||||
// ------------------------------------------------------------------------
|
||||
void setShapeType(ShapeType type) { shapeType_ = type; }
|
||||
ShapeType getShapeType() const { return shapeType_; }
|
||||
|
||||
void setColor(const Color &color) { color_ = color; }
|
||||
Color getColor() const { return color_; }
|
||||
|
||||
void setFilled(bool filled) { filled_ = filled; }
|
||||
bool isFilled() const { return filled_; }
|
||||
|
||||
void setLineWidth(float width) { lineWidth_ = width; }
|
||||
float getLineWidth() const { return lineWidth_; }
|
||||
|
||||
void setSegments(int segments) { segments_ = segments; }
|
||||
int getSegments() const { return segments_; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 点设置
|
||||
// ------------------------------------------------------------------------
|
||||
void setPoints(const std::vector<Vec2> &points);
|
||||
const std::vector<Vec2> &getPoints() const { return points_; }
|
||||
void addPoint(const Vec2 &point);
|
||||
void clearPoints();
|
||||
|
||||
Rect getBounds() const override;
|
||||
|
||||
protected:
|
||||
void onDraw(RenderBackend &renderer) override;
|
||||
void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||
int zOrder) override;
|
||||
|
||||
private:
|
||||
ShapeType shapeType_ = ShapeType::Rect;
|
||||
Color color_ = Colors::White;
|
||||
bool filled_ = false;
|
||||
float lineWidth_ = 1.0f;
|
||||
int segments_ = 32;
|
||||
std::vector<Vec2> points_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 精灵节点
|
||||
// ============================================================================
|
||||
class Sprite : public Node {
|
||||
public:
|
||||
Sprite();
|
||||
explicit Sprite(Ptr<Texture> texture);
|
||||
~Sprite() override = default;
|
||||
|
||||
// 纹理
|
||||
void setTexture(Ptr<Texture> texture);
|
||||
Ptr<Texture> getTexture() const { return texture_; }
|
||||
|
||||
// 纹理矩形 (用于图集)
|
||||
void setTextureRect(const Rect &rect);
|
||||
Rect getTextureRect() const { return textureRect_; }
|
||||
|
||||
// 颜色混合
|
||||
void setColor(const Color &color);
|
||||
Color getColor() const { return color_; }
|
||||
|
||||
// 翻转
|
||||
void setFlipX(bool flip);
|
||||
void setFlipY(bool flip);
|
||||
bool isFlipX() const { return flipX_; }
|
||||
bool isFlipY() const { return flipY_; }
|
||||
|
||||
// 静态创建方法
|
||||
static Ptr<Sprite> create();
|
||||
static Ptr<Sprite> create(Ptr<Texture> texture);
|
||||
static Ptr<Sprite> create(Ptr<Texture> texture, const Rect &rect);
|
||||
|
||||
Rect getBounds() const override;
|
||||
|
||||
protected:
|
||||
void onDraw(RenderBackend &renderer) override;
|
||||
void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||
int zOrder) override;
|
||||
|
||||
private:
|
||||
Ptr<Texture> texture_;
|
||||
Rect textureRect_;
|
||||
Color color_ = Colors::White;
|
||||
bool flipX_ = false;
|
||||
bool flipY_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 方块/马赛克过渡场景
|
||||
// 实现原理:
|
||||
// 1. 将屏幕分成多个方块
|
||||
// 2. 方块逐个消失,显示新场景
|
||||
// ============================================================================
|
||||
class TransitionBoxScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建方块过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param divisions 方块分割数(默认为 8,表示 8x8 网格)
|
||||
*/
|
||||
TransitionBoxScene(float duration, Ptr<Scene> inScene, int divisions = 8);
|
||||
|
||||
static Ptr<TransitionBoxScene> create(float duration, Ptr<Scene> inScene,
|
||||
int divisions = 8);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
void updateTransition(float dt) override;
|
||||
|
||||
private:
|
||||
int divisions_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 淡入淡出过渡场景
|
||||
// 实现原理:
|
||||
// 1. 创建一个纯色精灵作为遮罩层
|
||||
// 2. 第一阶段:遮罩从透明淡入到不透明(黑屏),同时显示旧场景
|
||||
// 3. 切换显示新场景
|
||||
// 4. 第二阶段:遮罩从不透明淡出到透明,显示新场景
|
||||
// ============================================================================
|
||||
class TransitionFadeScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建淡入淡出过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param color 遮罩颜色(默认为黑色)
|
||||
*/
|
||||
TransitionFadeScene(float duration, Ptr<Scene> inScene,
|
||||
const Color &color = Colors::Black);
|
||||
|
||||
static Ptr<TransitionFadeScene> create(float duration, Ptr<Scene> inScene,
|
||||
const Color &color = Colors::Black);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 启动过渡动画
|
||||
* 创建遮罩层并运行动作序列
|
||||
*/
|
||||
void onTransitionStart() override;
|
||||
|
||||
/**
|
||||
* @brief 更新过渡进度
|
||||
* @param dt 帧间隔时间(秒)
|
||||
*/
|
||||
void updateTransition(float dt) override;
|
||||
|
||||
/**
|
||||
* @brief 渲染内容
|
||||
* 根据进度控制新旧场景的显示
|
||||
*/
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 隐藏退出场景,显示进入场景
|
||||
*/
|
||||
void hideOutShowIn();
|
||||
|
||||
Color maskColor_; // 遮罩颜色
|
||||
bool hasSwitched_ = false; // 是否已经切换场景
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 翻页过渡场景
|
||||
// 实现原理:
|
||||
// 1. 前半段:旧场景翻转消失
|
||||
// 2. 后半段:新场景翻转出现
|
||||
// ============================================================================
|
||||
class TransitionFlipScene : public TransitionScene {
|
||||
public:
|
||||
enum class Axis { Horizontal, Vertical };
|
||||
|
||||
/**
|
||||
* @brief 创建翻页过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param axis 翻转轴(水平或垂直)
|
||||
*/
|
||||
TransitionFlipScene(float duration, Ptr<Scene> inScene,
|
||||
Axis axis = Axis::Horizontal);
|
||||
|
||||
static Ptr<TransitionFlipScene> create(float duration, Ptr<Scene> inScene,
|
||||
Axis axis = Axis::Horizontal);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
void updateTransition(float dt) override;
|
||||
|
||||
private:
|
||||
Axis axis_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 缩放过渡场景
|
||||
// 实现原理:
|
||||
// 1. 旧场景缩小消失
|
||||
// 2. 新场景放大出现
|
||||
// ============================================================================
|
||||
class TransitionScaleScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建缩放过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScaleScene(float duration, Ptr<Scene> inScene);
|
||||
|
||||
static Ptr<TransitionScaleScene> create(float duration, Ptr<Scene> inScene);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
void updateTransition(float dt) override;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/scene.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 过渡方向
|
||||
// ============================================================================
|
||||
enum class TransitionDirection { Left, Right, Up, Down };
|
||||
|
||||
// ============================================================================
|
||||
// 过渡效果类型
|
||||
// ============================================================================
|
||||
enum class TransitionType {
|
||||
None,
|
||||
Fade,
|
||||
SlideLeft,
|
||||
SlideRight,
|
||||
SlideUp,
|
||||
SlideDown,
|
||||
Scale,
|
||||
Flip,
|
||||
Box
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 过渡场景基类 - 继承自 Scene,作为中介场景管理过渡效果
|
||||
// 设计参考 Cocos2d-x 的 TransitionScene
|
||||
// ============================================================================
|
||||
class TransitionScene : public Scene {
|
||||
public:
|
||||
using FinishCallback = std::function<void()>;
|
||||
|
||||
/**
|
||||
* @brief 创建过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
*/
|
||||
TransitionScene(float duration, Ptr<Scene> inScene);
|
||||
~TransitionScene() override = default;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 场景管理
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 获取要进入的场景
|
||||
*/
|
||||
Ptr<Scene> getInScene() const { return inScene_; }
|
||||
|
||||
/**
|
||||
* @brief 获取要退出的场景
|
||||
*/
|
||||
Ptr<Scene> getOutScene() const { return outScene_; }
|
||||
|
||||
/**
|
||||
* @brief 设置要退出的场景(由 SceneManager 调用)
|
||||
*/
|
||||
void setOutScene(Ptr<Scene> outScene) { outScene_ = outScene; }
|
||||
|
||||
/**
|
||||
* @brief 设置过渡完成回调
|
||||
*/
|
||||
void setFinishCallback(FinishCallback callback) { finishCallback_ = callback; }
|
||||
|
||||
/**
|
||||
* @brief 获取过渡持续时间
|
||||
*/
|
||||
float getDuration() const { return duration_; }
|
||||
|
||||
/**
|
||||
* @brief 获取当前进度 [0, 1]
|
||||
*/
|
||||
float getProgress() const { return progress_; }
|
||||
|
||||
/**
|
||||
* @brief 是否已完成
|
||||
*/
|
||||
bool isFinished() const { return isFinished_; }
|
||||
|
||||
/**
|
||||
* @brief 是否已取消
|
||||
*/
|
||||
bool isCancelled() const { return isCancelled_; }
|
||||
|
||||
/**
|
||||
* @brief 完成过渡,通知 SceneManager 切换到目标场景
|
||||
*/
|
||||
void finish();
|
||||
|
||||
/**
|
||||
* @brief 取消过渡
|
||||
* @param immediate 是否立即完成(false则回滚到原场景)
|
||||
*/
|
||||
void cancel(bool immediate = false);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 渲染 - 在 TransitionScene 上渲染新旧两个子场景
|
||||
// ------------------------------------------------------------------------
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 生命周期
|
||||
// ------------------------------------------------------------------------
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 子类实现具体的过渡逻辑
|
||||
* 在 onEnter 中设置动画,动画完成后调用 finish()
|
||||
*/
|
||||
virtual void onTransitionStart() = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制源场景(旧场景)
|
||||
*/
|
||||
virtual void drawOutScene(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 绘制目标场景(新场景)
|
||||
*/
|
||||
virtual void drawInScene(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 更新过渡进度(子类重写此方法更新动画)
|
||||
* @param dt 帧间隔时间(秒)
|
||||
*/
|
||||
virtual void updateTransition(float dt);
|
||||
|
||||
float duration_;
|
||||
float elapsed_ = 0.0f;
|
||||
float progress_ = 0.0f;
|
||||
bool isFinished_ = false;
|
||||
bool isCancelled_ = false;
|
||||
|
||||
Ptr<Scene> inScene_; // 要进入的场景
|
||||
Ptr<Scene> outScene_; // 要退出的场景
|
||||
|
||||
FinishCallback finishCallback_;
|
||||
FinishCallback cancelCallback_; // 取消回调
|
||||
|
||||
friend class SceneManager;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 滑动过渡场景
|
||||
// 实现原理:
|
||||
// 1. 旧场景向指定方向滑出
|
||||
// 2. 新场景从相反方向滑入
|
||||
// ============================================================================
|
||||
class TransitionSlideScene : public TransitionScene {
|
||||
public:
|
||||
/**
|
||||
* @brief 创建滑动过渡场景
|
||||
* @param duration 过渡持续时间(秒)
|
||||
* @param inScene 要进入的目标场景
|
||||
* @param direction 滑动方向
|
||||
*/
|
||||
TransitionSlideScene(float duration, Ptr<Scene> inScene,
|
||||
TransitionDirection direction);
|
||||
|
||||
static Ptr<TransitionSlideScene> create(float duration, Ptr<Scene> inScene,
|
||||
TransitionDirection direction);
|
||||
|
||||
protected:
|
||||
void onTransitionStart() override;
|
||||
void renderContent(RenderBackend &renderer) override;
|
||||
void updateTransition(float dt) override;
|
||||
|
||||
private:
|
||||
TransitionDirection direction_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 相机服务接口
|
||||
*/
|
||||
class ICameraService : public IService {
|
||||
public:
|
||||
virtual ~ICameraService() = default;
|
||||
|
||||
virtual void setPosition(const Vec2& position) = 0;
|
||||
virtual void setPosition(float x, float y) = 0;
|
||||
virtual Vec2 getPosition() const = 0;
|
||||
|
||||
virtual void setRotation(float degrees) = 0;
|
||||
virtual float getRotation() const = 0;
|
||||
|
||||
virtual void setZoom(float zoom) = 0;
|
||||
virtual float getZoom() const = 0;
|
||||
|
||||
virtual void setViewport(float left, float right, float bottom, float top) = 0;
|
||||
virtual Rect getViewport() const = 0;
|
||||
|
||||
virtual glm::mat4 getViewMatrix() const = 0;
|
||||
virtual glm::mat4 getProjectionMatrix() const = 0;
|
||||
virtual glm::mat4 getViewProjectionMatrix() const = 0;
|
||||
|
||||
virtual Vec2 screenToWorld(const Vec2& screenPos) const = 0;
|
||||
virtual Vec2 worldToScreen(const Vec2& worldPos) const = 0;
|
||||
|
||||
virtual void move(const Vec2& offset) = 0;
|
||||
virtual void move(float x, float y) = 0;
|
||||
|
||||
virtual void setBounds(const Rect& bounds) = 0;
|
||||
virtual void clearBounds() = 0;
|
||||
|
||||
virtual void lookAt(const Vec2& target) = 0;
|
||||
|
||||
virtual void setViewportConfig(const ViewportConfig& config) = 0;
|
||||
virtual const ViewportConfig& getViewportConfig() const = 0;
|
||||
virtual void updateViewport(int screenWidth, int screenHeight) = 0;
|
||||
virtual const ViewportResult& getViewportResult() const = 0;
|
||||
|
||||
virtual void applyViewportAdapter() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 相机服务实现
|
||||
*/
|
||||
class CameraService : public ICameraService {
|
||||
public:
|
||||
CameraService();
|
||||
explicit CameraService(float left, float right, float bottom, float top);
|
||||
~CameraService() override = default;
|
||||
|
||||
ServiceInfo getServiceInfo() const override;
|
||||
|
||||
bool initialize() override;
|
||||
void shutdown() override;
|
||||
|
||||
void setPosition(const Vec2& position) override;
|
||||
void setPosition(float x, float y) override;
|
||||
Vec2 getPosition() const override;
|
||||
|
||||
void setRotation(float degrees) override;
|
||||
float getRotation() const override;
|
||||
|
||||
void setZoom(float zoom) override;
|
||||
float getZoom() const override;
|
||||
|
||||
void setViewport(float left, float right, float bottom, float top) override;
|
||||
Rect getViewport() const override;
|
||||
|
||||
glm::mat4 getViewMatrix() const override;
|
||||
glm::mat4 getProjectionMatrix() const override;
|
||||
glm::mat4 getViewProjectionMatrix() const override;
|
||||
|
||||
Vec2 screenToWorld(const Vec2& screenPos) const override;
|
||||
Vec2 worldToScreen(const Vec2& worldPos) const override;
|
||||
|
||||
void move(const Vec2& offset) override;
|
||||
void move(float x, float y) override;
|
||||
|
||||
void setBounds(const Rect& bounds) override;
|
||||
void clearBounds() override;
|
||||
|
||||
void lookAt(const Vec2& target) override;
|
||||
|
||||
void setViewportConfig(const ViewportConfig& config) override;
|
||||
const ViewportConfig& getViewportConfig() const override;
|
||||
void updateViewport(int screenWidth, int screenHeight) override;
|
||||
const ViewportResult& getViewportResult() const override;
|
||||
|
||||
void applyViewportAdapter() override;
|
||||
|
||||
Camera& getCamera() { return camera_; }
|
||||
const Camera& getCamera() const { return camera_; }
|
||||
ViewportAdapter& getViewportAdapter() { return viewportAdapter_; }
|
||||
const ViewportAdapter& getViewportAdapter() const { return viewportAdapter_; }
|
||||
|
||||
private:
|
||||
Camera camera_;
|
||||
ViewportAdapter viewportAdapter_;
|
||||
|
||||
// 服务注册元数据
|
||||
E2D_AUTO_REGISTER_SERVICE(ICameraService, CameraService);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/event/event_dispatcher.h>
|
||||
#include <extra2d/event/event_queue.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 事件服务接口
|
||||
*/
|
||||
class IEventService : public IService {
|
||||
public:
|
||||
virtual ~IEventService() = default;
|
||||
|
||||
virtual void pushEvent(const Event& event) = 0;
|
||||
virtual void pushEvent(Event&& event) = 0;
|
||||
virtual bool pollEvent(Event& event) = 0;
|
||||
|
||||
virtual ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) = 0;
|
||||
virtual void removeListener(ListenerId id) = 0;
|
||||
virtual void removeAllListeners(EventType type) = 0;
|
||||
virtual void removeAllListeners() = 0;
|
||||
|
||||
virtual void dispatch(Event& event) = 0;
|
||||
virtual void processQueue() = 0;
|
||||
|
||||
virtual size_t getListenerCount(EventType type) const = 0;
|
||||
virtual size_t getTotalListenerCount() const = 0;
|
||||
virtual size_t getQueueSize() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 事件服务实现
|
||||
*/
|
||||
class EventService : public IEventService {
|
||||
public:
|
||||
EventService();
|
||||
~EventService() override = default;
|
||||
|
||||
ServiceInfo getServiceInfo() const override;
|
||||
|
||||
bool initialize() override;
|
||||
void shutdown() override;
|
||||
void update(float deltaTime) override;
|
||||
|
||||
void pushEvent(const Event& event) override;
|
||||
void pushEvent(Event&& event) override;
|
||||
bool pollEvent(Event& event) override;
|
||||
|
||||
ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) override;
|
||||
void removeListener(ListenerId id) override;
|
||||
void removeAllListeners(EventType type) override;
|
||||
void removeAllListeners() override;
|
||||
|
||||
void dispatch(Event& event) override;
|
||||
void processQueue() override;
|
||||
|
||||
size_t getListenerCount(EventType type) const override;
|
||||
size_t getTotalListenerCount() const override;
|
||||
size_t getQueueSize() const override;
|
||||
|
||||
EventQueue& getQueue() { return queue_; }
|
||||
const EventQueue& getQueue() const { return queue_; }
|
||||
EventDispatcher& getDispatcher() { return dispatcher_; }
|
||||
const EventDispatcher& getDispatcher() const { return dispatcher_; }
|
||||
|
||||
private:
|
||||
EventQueue queue_;
|
||||
EventDispatcher dispatcher_;
|
||||
|
||||
// 服务注册元数据
|
||||
E2D_AUTO_REGISTER_SERVICE(IEventService, EventService);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 日志级别枚举
|
||||
*/
|
||||
enum class LogLevel {
|
||||
Trace = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Fatal = 5,
|
||||
Off = 6
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 日志服务接口
|
||||
*/
|
||||
class ILogger : public IService {
|
||||
public:
|
||||
virtual ~ILogger() = default;
|
||||
|
||||
/**
|
||||
* @brief 设置日志级别
|
||||
*/
|
||||
virtual void setLevel(LogLevel level) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取日志级别
|
||||
*/
|
||||
virtual LogLevel getLevel() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查日志级别是否启用
|
||||
*/
|
||||
virtual bool isEnabled(LogLevel level) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 记录日志(格式化)
|
||||
*/
|
||||
virtual void log(LogLevel level, const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief 记录日志(字符串)
|
||||
*/
|
||||
virtual void log(LogLevel level, const std::string& msg) = 0;
|
||||
|
||||
/**
|
||||
* @brief Trace级别日志
|
||||
*/
|
||||
virtual void trace(const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Debug级别日志
|
||||
*/
|
||||
virtual void debug(const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Info级别日志
|
||||
*/
|
||||
virtual void info(const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Warn级别日志
|
||||
*/
|
||||
virtual void warn(const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Error级别日志
|
||||
*/
|
||||
virtual void error(const char* fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Fatal级别日志
|
||||
*/
|
||||
virtual void fatal(const char* fmt, ...) = 0;
|
||||
|
||||
ServiceInfo getServiceInfo() const override {
|
||||
ServiceInfo info;
|
||||
info.name = "Logger";
|
||||
info.priority = ServicePriority::Core;
|
||||
info.enabled = true;
|
||||
return info;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 控制台日志服务实现
|
||||
*/
|
||||
class ConsoleLogger : public ILogger {
|
||||
public:
|
||||
ConsoleLogger();
|
||||
~ConsoleLogger() override;
|
||||
|
||||
bool initialize() override;
|
||||
void shutdown() override;
|
||||
|
||||
void setLevel(LogLevel level) override;
|
||||
LogLevel getLevel() const override;
|
||||
bool isEnabled(LogLevel level) const override;
|
||||
|
||||
void log(LogLevel level, const char* fmt, ...) override;
|
||||
void log(LogLevel level, const std::string& msg) override;
|
||||
|
||||
void trace(const char* fmt, ...) override;
|
||||
void debug(const char* fmt, ...) override;
|
||||
void info(const char* fmt, ...) override;
|
||||
void warn(const char* fmt, ...) override;
|
||||
void error(const char* fmt, ...) override;
|
||||
void fatal(const char* fmt, ...) override;
|
||||
|
||||
private:
|
||||
void output(LogLevel level, const char* msg);
|
||||
const char* getLevelString(LogLevel level);
|
||||
|
||||
LogLevel level_;
|
||||
class Impl;
|
||||
UniquePtr<Impl> impl_;
|
||||
|
||||
// 服务注册元数据
|
||||
E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
||||
// 格式化辅助函数 - 将参数转换为字符串
|
||||
namespace extra2d {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
std::string to_string(T&& value) {
|
||||
using Decayed = std::decay_t<T>;
|
||||
if constexpr (std::is_same_v<Decayed, std::string>) {
|
||||
return value;
|
||||
} else if constexpr (std::is_same_v<Decayed, const char*>) {
|
||||
return value ? value : "(null)";
|
||||
} else if constexpr (std::is_arithmetic_v<Decayed>) {
|
||||
if constexpr (std::is_same_v<Decayed, bool>) {
|
||||
return value ? "true" : "false";
|
||||
} else if constexpr (std::is_floating_point_v<Decayed>) {
|
||||
return std::to_string(value);
|
||||
} else {
|
||||
return std::to_string(value);
|
||||
}
|
||||
} else {
|
||||
return "<?>";
|
||||
}
|
||||
}
|
||||
|
||||
inline void format_impl(std::string& result, const char* fmt) {
|
||||
result += fmt;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) {
|
||||
const char* p = fmt;
|
||||
while (*p) {
|
||||
if (*p == '{' && *(p + 1) == '}') {
|
||||
result += to_string(std::forward<T>(value));
|
||||
format_impl(result, p + 2, std::forward<Args>(args)...);
|
||||
return;
|
||||
}
|
||||
result += *p++;
|
||||
}
|
||||
// 没有更多的 {},追加剩余参数(不应该发生)
|
||||
result += " ";
|
||||
result += to_string(std::forward<T>(value));
|
||||
format_impl(result, p, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string format_str(const char* fmt, Args&&... args) {
|
||||
if constexpr (sizeof...(args) == 0) {
|
||||
return std::string(fmt);
|
||||
} else {
|
||||
std::string result;
|
||||
detail::format_impl(result, fmt, std::forward<Args>(args)...);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 便捷宏 - 自动获取日志服务
|
||||
#define E2D_LOG(level, ...) \
|
||||
do { \
|
||||
if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \
|
||||
if (logService->isEnabled(level)) { \
|
||||
logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define E2D_LOG_TRACE(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_DEBUG(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_INFO(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_WARN(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_ERROR(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_FATAL(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
|
||||
|
||||
// 简写宏
|
||||
#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__)
|
||||
#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__)
|
||||
#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__)
|
||||
#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__)
|
||||
|
||||
#ifdef E2D_DEBUG
|
||||
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
|
||||
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
#define E2D_DEBUG_LOG(...)
|
||||
#define E2D_TRACE(...)
|
||||
#endif
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/scene/scene_manager.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 场景服务接口
|
||||
* 定义场景管理的抽象接口,便于测试和Mock
|
||||
*/
|
||||
class ISceneService : public IService {
|
||||
public:
|
||||
virtual ~ISceneService() = default;
|
||||
|
||||
virtual void runWithScene(Ptr<Scene> scene) = 0;
|
||||
virtual void replaceScene(Ptr<Scene> scene) = 0;
|
||||
virtual void pushScene(Ptr<Scene> scene) = 0;
|
||||
virtual void popScene() = 0;
|
||||
virtual void popToRootScene() = 0;
|
||||
virtual void popToScene(const std::string& name) = 0;
|
||||
|
||||
virtual Ptr<Scene> getCurrentScene() const = 0;
|
||||
virtual Ptr<Scene> getPreviousScene() const = 0;
|
||||
virtual Ptr<Scene> getRootScene() const = 0;
|
||||
virtual Ptr<Scene> getSceneByName(const std::string& name) const = 0;
|
||||
|
||||
virtual size_t getSceneCount() const = 0;
|
||||
virtual bool isEmpty() const = 0;
|
||||
virtual bool hasScene(const std::string& name) const = 0;
|
||||
|
||||
virtual void render(RenderBackend& renderer) = 0;
|
||||
virtual void collectRenderCommands(std::vector<RenderCommand>& commands) = 0;
|
||||
|
||||
virtual bool isTransitioning() const = 0;
|
||||
virtual void setTransitionCallback(SceneManager::TransitionCallback callback) = 0;
|
||||
|
||||
virtual void end() = 0;
|
||||
virtual void purgeCachedScenes() = 0;
|
||||
virtual void enterScene(Ptr<Scene> scene) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 场景服务实现
|
||||
* 包装 SceneManager,实现 IService 接口
|
||||
*/
|
||||
class SceneService : public ISceneService {
|
||||
public:
|
||||
SceneService();
|
||||
~SceneService() override = default;
|
||||
|
||||
ServiceInfo getServiceInfo() const override;
|
||||
|
||||
bool initialize() override;
|
||||
void shutdown() override;
|
||||
void update(float deltaTime) override;
|
||||
|
||||
void runWithScene(Ptr<Scene> scene) override;
|
||||
void replaceScene(Ptr<Scene> scene) override;
|
||||
void pushScene(Ptr<Scene> scene) override;
|
||||
void popScene() override;
|
||||
void popToRootScene() override;
|
||||
void popToScene(const std::string& name) override;
|
||||
|
||||
Ptr<Scene> getCurrentScene() const override;
|
||||
Ptr<Scene> getPreviousScene() const override;
|
||||
Ptr<Scene> getRootScene() const override;
|
||||
Ptr<Scene> getSceneByName(const std::string& name) const override;
|
||||
|
||||
size_t getSceneCount() const override;
|
||||
bool isEmpty() const override;
|
||||
bool hasScene(const std::string& name) const override;
|
||||
|
||||
void render(RenderBackend& renderer) override;
|
||||
void collectRenderCommands(std::vector<RenderCommand>& commands) override;
|
||||
|
||||
bool isTransitioning() const override;
|
||||
void setTransitionCallback(SceneManager::TransitionCallback callback) override;
|
||||
|
||||
void end() override;
|
||||
void purgeCachedScenes() override;
|
||||
void enterScene(Ptr<Scene> scene) override;
|
||||
|
||||
SceneManager& getManager() { return manager_; }
|
||||
const SceneManager& getManager() const { return manager_; }
|
||||
|
||||
private:
|
||||
SceneManager manager_;
|
||||
|
||||
// 服务注册元数据
|
||||
E2D_AUTO_REGISTER_SERVICE(ISceneService, SceneService);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/utils/timer.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 计时器服务接口
|
||||
*/
|
||||
class ITimerService : public IService {
|
||||
public:
|
||||
virtual ~ITimerService() = default;
|
||||
|
||||
virtual uint32 addTimer(float delay, Timer::Callback callback) = 0;
|
||||
virtual uint32 addRepeatingTimer(float interval, Timer::Callback callback) = 0;
|
||||
virtual void cancelTimer(uint32 timerId) = 0;
|
||||
virtual void pauseTimer(uint32 timerId) = 0;
|
||||
virtual void resumeTimer(uint32 timerId) = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual size_t getTimerCount() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 计时器服务实现
|
||||
*/
|
||||
class TimerService : public ITimerService {
|
||||
public:
|
||||
TimerService();
|
||||
~TimerService() override = default;
|
||||
|
||||
ServiceInfo getServiceInfo() const override;
|
||||
|
||||
bool initialize() override;
|
||||
void shutdown() override;
|
||||
void update(float deltaTime) override;
|
||||
|
||||
uint32 addTimer(float delay, Timer::Callback callback) override;
|
||||
uint32 addRepeatingTimer(float interval, Timer::Callback callback) override;
|
||||
void cancelTimer(uint32 timerId) override;
|
||||
void pauseTimer(uint32 timerId) override;
|
||||
void resumeTimer(uint32 timerId) override;
|
||||
void clear() override;
|
||||
size_t getTimerCount() const override;
|
||||
|
||||
TimerManager& getManager() { return manager_; }
|
||||
const TimerManager& getManager() const { return manager_; }
|
||||
|
||||
private:
|
||||
TimerManager manager_;
|
||||
|
||||
// 服务注册元数据
|
||||
E2D_AUTO_REGISTER_SERVICE(ITimerService, TimerService);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file logger.h
|
||||
* @brief 日志工具头文件
|
||||
*
|
||||
* 提供便捷的日志宏定义,实际实现位于 logger_service.h
|
||||
*/
|
||||
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <random>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Random 类 - 随机数生成器
|
||||
// ============================================================================
|
||||
class Random {
|
||||
public:
|
||||
/// 获取单例实例
|
||||
static Random &get();
|
||||
|
||||
/// 设置随机种子
|
||||
void setSeed(uint32 seed);
|
||||
|
||||
/// 使用当前时间作为种子
|
||||
void randomize();
|
||||
|
||||
/// 获取 [0, 1) 范围内的随机浮点数
|
||||
float getFloat();
|
||||
|
||||
/// 获取 [min, max] 范围内的随机浮点数
|
||||
float getFloat(float min, float max);
|
||||
|
||||
/// 获取 [0, max] 范围内的随机整数
|
||||
int getInt(int max);
|
||||
|
||||
/// 获取 [min, max] 范围内的随机整数
|
||||
int getInt(int min, int max);
|
||||
|
||||
/// 获取随机布尔值
|
||||
bool getBool();
|
||||
|
||||
/// 获取随机布尔值(带概率)
|
||||
bool getBool(float probability);
|
||||
|
||||
/// 获取指定范围内的随机角度(弧度)
|
||||
float getAngle();
|
||||
|
||||
/// 获取 [-1, 1] 范围内的随机数(用于方向)
|
||||
float getSigned();
|
||||
|
||||
private:
|
||||
Random();
|
||||
~Random() = default;
|
||||
|
||||
Random(const Random &) = delete;
|
||||
Random &operator=(const Random &) = delete;
|
||||
|
||||
std::mt19937 generator_;
|
||||
std::uniform_real_distribution<float> floatDist_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 便捷函数
|
||||
// ============================================================================
|
||||
|
||||
/// 获取 [0, 1) 范围内的随机浮点数
|
||||
inline float randomFloat() { return Random::get().getFloat(); }
|
||||
|
||||
/// 获取 [min, max] 范围内的随机浮点数
|
||||
inline float randomFloat(float min, float max) {
|
||||
return Random::get().getFloat(min, max);
|
||||
}
|
||||
|
||||
/// 获取 [0, max] 范围内的随机整数
|
||||
inline int randomInt(int max) { return Random::get().getInt(max); }
|
||||
|
||||
/// 获取 [min, max] 范围内的随机整数
|
||||
inline int randomInt(int min, int max) {
|
||||
return Random::get().getInt(min, max);
|
||||
}
|
||||
|
||||
/// 获取随机布尔值
|
||||
inline bool randomBool() { return Random::get().getBool(); }
|
||||
|
||||
/// 获取随机布尔值(带概率)
|
||||
inline bool randomBool(float probability) {
|
||||
return Random::get().getBool(probability);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// Timer 类 - 单次/重复计时器
|
||||
// ============================================================================
|
||||
class Timer {
|
||||
public:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
using Duration = Clock::duration;
|
||||
using Callback = Function<void()>;
|
||||
|
||||
Timer(float interval, bool repeat, Callback callback);
|
||||
|
||||
/// 更新计时器,返回 true 如果触发了回调
|
||||
bool update(float deltaTime);
|
||||
|
||||
/// 重置计时器
|
||||
void reset();
|
||||
|
||||
/// 暂停计时器
|
||||
void pause();
|
||||
|
||||
/// 恢复计时器
|
||||
void resume();
|
||||
|
||||
/// 取消计时器(标记为无效)
|
||||
void cancel();
|
||||
|
||||
/// 是否有效
|
||||
bool isValid() const { return valid_; }
|
||||
|
||||
/// 是否暂停
|
||||
bool isPaused() const { return paused_; }
|
||||
|
||||
/// 获取剩余时间(秒)
|
||||
float getRemaining() const;
|
||||
|
||||
/// 获取唯一ID
|
||||
uint32 getId() const { return id_; }
|
||||
|
||||
private:
|
||||
uint32 id_;
|
||||
float interval_;
|
||||
float elapsed_;
|
||||
bool repeat_;
|
||||
bool paused_;
|
||||
bool valid_;
|
||||
Callback callback_;
|
||||
|
||||
static uint32 nextId_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// TimerManager 类 - 管理所有计时器
|
||||
// ============================================================================
|
||||
class TimerManager {
|
||||
public:
|
||||
TimerManager() = default;
|
||||
~TimerManager() = default;
|
||||
|
||||
/// 创建单次计时器,返回计时器ID
|
||||
uint32 addTimer(float delay, Timer::Callback callback);
|
||||
|
||||
/// 创建重复计时器,返回计时器ID
|
||||
uint32 addRepeatingTimer(float interval, Timer::Callback callback);
|
||||
|
||||
/// 取消指定ID的计时器
|
||||
void cancelTimer(uint32 timerId);
|
||||
|
||||
/// 暂停指定ID的计时器
|
||||
void pauseTimer(uint32 timerId);
|
||||
|
||||
/// 恢复指定ID的计时器
|
||||
void resumeTimer(uint32 timerId);
|
||||
|
||||
/// 更新所有计时器(每帧调用)
|
||||
void update(float deltaTime);
|
||||
|
||||
/// 清除所有计时器
|
||||
void clear();
|
||||
|
||||
/// 获取计时器数量
|
||||
size_t getTimerCount() const { return timers_.size(); }
|
||||
|
||||
private:
|
||||
std::map<uint32, std::unique_ptr<Timer>> timers_;
|
||||
std::vector<uint32> timersToRemove_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,428 +0,0 @@
|
|||
// stb_perlin.h - v0.5 - perlin noise
|
||||
// public domain single-file C implementation by Sean Barrett
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
//
|
||||
//
|
||||
// to create the implementation,
|
||||
// #define STB_PERLIN_IMPLEMENTATION
|
||||
// in *one* C/CPP file that includes this file.
|
||||
//
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// float stb_perlin_noise3( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0)
|
||||
//
|
||||
// This function computes a random value at the coordinate (x,y,z).
|
||||
// Adjacent random values are continuous but the noise fluctuates
|
||||
// its randomness with period 1, i.e. takes on wholly unrelated values
|
||||
// at integer points. Specifically, this implements Ken Perlin's
|
||||
// revised noise function from 2002.
|
||||
//
|
||||
// The "wrap" parameters can be used to create wraparound noise that
|
||||
// wraps at powers of two. The numbers MUST be powers of two. Specify
|
||||
// 0 to mean "don't care". (The noise always wraps every 256 due
|
||||
// details of the implementation, even if you ask for larger or no
|
||||
// wrapping.)
|
||||
//
|
||||
// float stb_perlin_noise3_seed( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0,
|
||||
// int seed)
|
||||
//
|
||||
// As above, but 'seed' selects from multiple different variations of the
|
||||
// noise function. The current implementation only uses the bottom 8 bits
|
||||
// of 'seed', but possibly in the future more bits will be used.
|
||||
//
|
||||
//
|
||||
// Fractal Noise:
|
||||
//
|
||||
// Three common fractal noise functions are included, which produce
|
||||
// a wide variety of nice effects depending on the parameters
|
||||
// provided. Note that each function will call stb_perlin_noise3
|
||||
// 'octaves' times, so this parameter will affect runtime.
|
||||
//
|
||||
// float stb_perlin_ridge_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, float offset, int octaves)
|
||||
//
|
||||
// float stb_perlin_fbm_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// float stb_perlin_turbulence_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// Typical values to start playing with:
|
||||
// octaves = 6 -- number of "octaves" of noise3() to sum
|
||||
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
|
||||
// gain = 0.5 -- relative weighting applied to each successive octave
|
||||
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
|
||||
//
|
||||
//
|
||||
// Contributors:
|
||||
// Jack Mott - additional noise functions
|
||||
// Jordan Peck - seeded noise
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
|
||||
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // fabs()
|
||||
|
||||
// not same permutation table as Perlin's reference to avoid copyright issues;
|
||||
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
|
||||
static unsigned char stb__perlin_randtab[512] =
|
||||
{
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
};
|
||||
|
||||
|
||||
// perlin's gradient has 12 cases so some get used 1/16th of the time
|
||||
// and some 2/16ths. We reduce bias by changing those fractions
|
||||
// to 5/64ths and 6/64ths
|
||||
|
||||
// this array is designed to match the previous implementation
|
||||
// of gradient hash: indices[stb__perlin_randtab[i]&63]
|
||||
static unsigned char stb__perlin_randtab_grad_idx[512] =
|
||||
{
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
};
|
||||
|
||||
static float stb__perlin_lerp(float a, float b, float t)
|
||||
{
|
||||
return a + (b-a) * t;
|
||||
}
|
||||
|
||||
static int stb__perlin_fastfloor(float a)
|
||||
{
|
||||
int ai = (int) a;
|
||||
return (a < ai) ? ai-1 : ai;
|
||||
}
|
||||
|
||||
// different grad function from Perlin's, but easy to modify to match reference
|
||||
static float stb__perlin_grad(int grad_idx, float x, float y, float z)
|
||||
{
|
||||
static float basis[12][4] =
|
||||
{
|
||||
{ 1, 1, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 1,-1, 0 },
|
||||
{ -1,-1, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 1, 0,-1 },
|
||||
{ -1, 0,-1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0,-1, 1 },
|
||||
{ 0, 1,-1 },
|
||||
{ 0,-1,-1 },
|
||||
};
|
||||
|
||||
float *grad = basis[grad_idx];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_internal(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
unsigned int x_mask = (x_wrap-1) & 255;
|
||||
unsigned int y_mask = (y_wrap-1) & 255;
|
||||
unsigned int z_mask = (z_wrap-1) & 255;
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x0 = px & x_mask, x1 = (px+1) & x_mask;
|
||||
int y0 = py & y_mask, y1 = (py+1) & y_mask;
|
||||
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0+seed];
|
||||
r1 = stb__perlin_randtab[x1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap,0);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap, (unsigned char) seed);
|
||||
}
|
||||
|
||||
float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float prev = 1.0f;
|
||||
float amplitude = 0.5f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i);
|
||||
r = offset - (float) fabs(r);
|
||||
r = r*r;
|
||||
sum += r*amplitude*prev;
|
||||
prev = r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
|
||||
sum += (float) fabs(r);
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x_wrap2 = (x_wrap ? x_wrap : 256);
|
||||
int y_wrap2 = (y_wrap ? y_wrap : 256);
|
||||
int z_wrap2 = (z_wrap ? z_wrap : 256);
|
||||
int x0 = px % x_wrap2, x1;
|
||||
int y0 = py % y_wrap2, y1;
|
||||
int z0 = pz % z_wrap2, z1;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
if (x0 < 0) x0 += x_wrap2;
|
||||
if (y0 < 0) y0 += y_wrap2;
|
||||
if (z0 < 0) z0 += z_wrap2;
|
||||
x1 = (x0+1) % x_wrap2;
|
||||
y1 = (y0+1) % y_wrap2;
|
||||
z1 = (z0+1) % z_wrap2;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r0 = stb__perlin_randtab[r0+seed];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
r1 = stb__perlin_randtab[r1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec4 v_color;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = v_color;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) in vec2 a_position;
|
||||
layout(location = 1) in vec4 a_color;
|
||||
|
||||
uniform mat4 u_viewProjection;
|
||||
|
||||
out vec4 v_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_viewProjection * vec4(a_position, 0.0, 1.0);
|
||||
v_color = a_color;
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec2 v_texCoord;
|
||||
in vec4 v_color;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
uniform float u_opacity;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 texColor = texture(u_texture, v_texCoord);
|
||||
fragColor = texColor * v_color;
|
||||
fragColor.a *= u_opacity;
|
||||
|
||||
if (fragColor.a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) in vec2 a_position;
|
||||
layout(location = 1) in vec2 a_texCoord;
|
||||
layout(location = 2) in vec4 a_color;
|
||||
|
||||
uniform mat4 u_viewProjection;
|
||||
uniform mat4 u_model;
|
||||
|
||||
out vec2 v_texCoord;
|
||||
out vec4 v_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_viewProjection * u_model * vec4(a_position, 0.0, 1.0);
|
||||
v_texCoord = a_texCoord;
|
||||
v_color = a_color;
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
// ============================================
|
||||
// Common Color Functions
|
||||
// ============================================
|
||||
|
||||
#ifndef E2D_COLOR_GLSL
|
||||
#define E2D_COLOR_GLSL
|
||||
|
||||
/**
|
||||
* @brief RGB转灰度
|
||||
* @param color RGB颜色
|
||||
* @return 灰度值
|
||||
*/
|
||||
float rgbToGrayscale(vec3 color) {
|
||||
return dot(color, vec3(0.299, 0.587, 0.114));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RGB转HSV
|
||||
* @param c RGB颜色
|
||||
* @return HSV颜色
|
||||
*/
|
||||
vec3 rgbToHsv(vec3 c) {
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HSV转RGB
|
||||
* @param c HSV颜色
|
||||
* @return RGB颜色
|
||||
*/
|
||||
vec3 hsvToRgb(vec3 c) {
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整亮度
|
||||
* @param color 原始颜色
|
||||
* @param amount 亮度调整量
|
||||
* @return 调整后的颜色
|
||||
*/
|
||||
vec3 adjustBrightness(vec3 color, float amount) {
|
||||
return color + amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整对比度
|
||||
* @param color 原始颜色
|
||||
* @param amount 对比度调整量
|
||||
* @return 调整后的颜色
|
||||
*/
|
||||
vec3 adjustContrast(vec3 color, float amount) {
|
||||
return (color - 0.5) * amount + 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整饱和度
|
||||
* @param color 原始颜色
|
||||
* @param amount 饱和度调整量
|
||||
* @return 调整后的颜色
|
||||
*/
|
||||
vec3 adjustSaturation(vec3 color, float amount) {
|
||||
float gray = rgbToGrayscale(color);
|
||||
return mix(vec3(gray), color, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色混合(正片叠底)
|
||||
* @param a 底色
|
||||
* @param b 混合色
|
||||
* @return 混合结果
|
||||
*/
|
||||
vec3 blendMultiply(vec3 a, vec3 b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色混合(滤色)
|
||||
* @param a 底色
|
||||
* @param b 混合色
|
||||
* @return 混合结果
|
||||
*/
|
||||
vec3 blendScreen(vec3 a, vec3 b) {
|
||||
return 1.0 - (1.0 - a) * (1.0 - b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色混合(叠加)
|
||||
* @param a 底色
|
||||
* @param b 混合色
|
||||
* @return 混合结果
|
||||
*/
|
||||
vec3 blendOverlay(vec3 a, vec3 b) {
|
||||
return mix(
|
||||
2.0 * a * b,
|
||||
1.0 - 2.0 * (1.0 - a) * (1.0 - b),
|
||||
step(0.5, a)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色调色
|
||||
* @param color 原始颜色
|
||||
* @param tintColor 色调颜色
|
||||
* @param amount 色调强度
|
||||
* @return 调色结果
|
||||
*/
|
||||
vec3 tint(vec3 color, vec3 tintColor, float amount) {
|
||||
return mix(color, tintColor, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 预乘Alpha
|
||||
* @param color RGBA颜色
|
||||
* @return 预乘后的RGB颜色
|
||||
*/
|
||||
vec3 premultiplyAlpha(vec4 color) {
|
||||
return color.rgb * color.a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消预乘Alpha
|
||||
* @param color RGB颜色
|
||||
* @param alpha Alpha值
|
||||
* @return 未预乘的RGB颜色
|
||||
*/
|
||||
vec3 unpremultiplyAlpha(vec3 color, float alpha) {
|
||||
return alpha > 0.0 ? color / alpha : color;
|
||||
}
|
||||
|
||||
#endif // E2D_COLOR_GLSL
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
// ============================================
|
||||
// Common Math Functions
|
||||
// ============================================
|
||||
|
||||
#ifndef E2D_MATH_GLSL
|
||||
#define E2D_MATH_GLSL
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float E = 2.71828182846;
|
||||
|
||||
/**
|
||||
* @brief 角度转弧度
|
||||
* @param deg 角度值
|
||||
* @return 弧度值
|
||||
*/
|
||||
float degToRad(float deg) {
|
||||
return deg * PI / 180.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 弧度转角度
|
||||
* @param rad 弧度值
|
||||
* @return 角度值
|
||||
*/
|
||||
float radToDeg(float rad) {
|
||||
return rad * 180.0 / PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 线性插值
|
||||
* @param a 起始值
|
||||
* @param b 结束值
|
||||
* @param t 插值因子 [0, 1]
|
||||
* @return 插值结果
|
||||
*/
|
||||
float lerp(float a, float b, float t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 平滑插值
|
||||
* @param edge0 下边界
|
||||
* @param edge1 上边界
|
||||
* @param x 输入值
|
||||
* @return 平滑插值结果
|
||||
*/
|
||||
float smoothStep(float edge0, float edge1, float x) {
|
||||
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 2D向量线性插值
|
||||
*/
|
||||
vec2 lerpVec2(vec2 a, vec2 b, float t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算两点之间的距离
|
||||
*/
|
||||
float distance2D(vec2 a, vec2 b) {
|
||||
return length(b - a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算两点之间的距离平方
|
||||
*/
|
||||
float distance2DSquared(vec2 a, vec2 b) {
|
||||
vec2 diff = b - a;
|
||||
return dot(diff, diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将值限制在范围内
|
||||
*/
|
||||
float clamp01(float x) {
|
||||
return clamp(x, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重复平铺
|
||||
*/
|
||||
float repeat(float x, float period) {
|
||||
return mod(x, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 镜像重复
|
||||
*/
|
||||
float mirrorRepeat(float x, float period) {
|
||||
float m = mod(x, period * 2.0);
|
||||
return m > period ? period * 2.0 - m : m;
|
||||
}
|
||||
|
||||
#endif // E2D_MATH_GLSL
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"name": "shape",
|
||||
"category": "builtin",
|
||||
"version": "1.0",
|
||||
"description": "基本形状渲染Shader",
|
||||
"uniforms": {
|
||||
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" }
|
||||
},
|
||||
"samplers": {},
|
||||
"backends": {
|
||||
"opengl": {
|
||||
"vertex": "backends/opengl/builtin/shape.vert",
|
||||
"fragment": "backends/opengl/builtin/shape.frag"
|
||||
},
|
||||
"vulkan": {
|
||||
"vertex": "backends/vulkan/builtin/shape.vert.spv",
|
||||
"fragment": "backends/vulkan/builtin/shape.frag.spv"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"name": "sprite",
|
||||
"category": "builtin",
|
||||
"version": "1.0",
|
||||
"description": "标准2D精灵渲染Shader",
|
||||
"uniforms": {
|
||||
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" },
|
||||
"u_model": { "type": "mat4", "description": "模型矩阵" },
|
||||
"u_opacity": { "type": "float", "default": 1.0, "description": "透明度" }
|
||||
},
|
||||
"samplers": {
|
||||
"u_texture": { "binding": 0, "description": "纹理采样器" }
|
||||
},
|
||||
"backends": {
|
||||
"opengl": {
|
||||
"vertex": "backends/opengl/builtin/sprite.vert",
|
||||
"fragment": "backends/opengl/builtin/sprite.frag"
|
||||
},
|
||||
"vulkan": {
|
||||
"vertex": "backends/vulkan/builtin/sprite.vert.spv",
|
||||
"fragment": "backends/vulkan/builtin/sprite.frag.spv"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/input_module.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/services/camera_service.h>
|
||||
#include <extra2d/services/event_service.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/services/scene_service.h>
|
||||
#include <extra2d/services/timer_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
static double getTimeSeconds() {
|
||||
#ifdef __SWITCH__
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return static_cast<double>(ts.tv_sec) +
|
||||
static_cast<double>(ts.tv_nsec) / 1000000000.0;
|
||||
#else
|
||||
using namespace std::chrono;
|
||||
auto now = steady_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
return duration_cast<std::chrono::duration<double>>(duration).count();
|
||||
#endif
|
||||
}
|
||||
|
||||
Application &Application::get() {
|
||||
static Application instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Application::Application() { Registry::instance().setApp(this); }
|
||||
|
||||
Application::~Application() {
|
||||
if (initialized_) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 初始化所有模块(拓扑排序)
|
||||
// 服务通过 E2D_AUTO_REGISTER_SERVICE 宏自动注册
|
||||
if (!Registry::instance().init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 配置相机服务(需要窗口信息)
|
||||
configureCameraService();
|
||||
|
||||
// 初始化所有服务
|
||||
ServiceLocator::instance().initializeAll();
|
||||
|
||||
initialized_ = true;
|
||||
running_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::configureCameraService() {
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (!winMod || !winMod->win()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
||||
if (!cameraService) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *win = winMod->win();
|
||||
cameraService->setViewport(0, static_cast<float>(win->width()),
|
||||
static_cast<float>(win->height()), 0);
|
||||
|
||||
ViewportConfig vpConfig;
|
||||
vpConfig.logicWidth = static_cast<float>(win->width());
|
||||
vpConfig.logicHeight = static_cast<float>(win->height());
|
||||
vpConfig.mode = ViewportMode::AspectRatio;
|
||||
cameraService->setViewportConfig(vpConfig);
|
||||
cameraService->updateViewport(win->width(), win->height());
|
||||
|
||||
win->onResize([cameraService](int width, int height) {
|
||||
cameraService->updateViewport(width, height);
|
||||
cameraService->applyViewportAdapter();
|
||||
});
|
||||
}
|
||||
|
||||
void Application::shutdown() {
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
VRAMMgr::get().printStats();
|
||||
|
||||
ServiceLocator::instance().shutdownAll();
|
||||
ServiceLocator::instance().clear();
|
||||
Registry::instance().shutdown();
|
||||
Registry::instance().clear();
|
||||
|
||||
initialized_ = false;
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void Application::run() {
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (!winMod || !winMod->win())
|
||||
return;
|
||||
|
||||
lastFrameTime_ = getTimeSeconds();
|
||||
|
||||
while (running_ && !winMod->win()->shouldClose()) {
|
||||
mainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::quit() {
|
||||
shouldQuit_ = true;
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void Application::pause() {
|
||||
if (!paused_) {
|
||||
paused_ = true;
|
||||
ServiceLocator::instance().pauseAll();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::resume() {
|
||||
if (paused_) {
|
||||
paused_ = false;
|
||||
ServiceLocator::instance().resumeAll();
|
||||
lastFrameTime_ = getTimeSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::mainLoop() {
|
||||
double currentTime = getTimeSeconds();
|
||||
deltaTime_ = static_cast<float>(currentTime - lastFrameTime_);
|
||||
lastFrameTime_ = currentTime;
|
||||
|
||||
totalTime_ += deltaTime_;
|
||||
|
||||
frameCount_++;
|
||||
fpsTimer_ += deltaTime_;
|
||||
if (fpsTimer_ >= 1.0f) {
|
||||
currentFps_ = frameCount_;
|
||||
frameCount_ = 0;
|
||||
fpsTimer_ -= 1.0f;
|
||||
}
|
||||
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (winMod && winMod->win()) {
|
||||
winMod->win()->poll();
|
||||
}
|
||||
|
||||
auto eventService = ServiceLocator::instance().getService<IEventService>();
|
||||
if (eventService) {
|
||||
eventService->processQueue();
|
||||
}
|
||||
|
||||
if (!paused_) {
|
||||
update();
|
||||
}
|
||||
|
||||
render();
|
||||
|
||||
// 帧率限制
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (renderMod && renderMod->renderer()) {
|
||||
// 这里可以添加帧率限制逻辑
|
||||
}
|
||||
}
|
||||
|
||||
void Application::update() {
|
||||
ServiceLocator::instance().updateAll(deltaTime_);
|
||||
|
||||
auto *inputMod = get<InputModule>();
|
||||
if (inputMod) {
|
||||
inputMod->update();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::render() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (!renderMod || !renderMod->renderer())
|
||||
return;
|
||||
|
||||
auto *renderer = renderMod->renderer();
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (!winMod || !winMod->win())
|
||||
return;
|
||||
|
||||
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
||||
if (cameraService) {
|
||||
const auto &vp = cameraService->getViewportResult().viewport;
|
||||
renderer->setViewport(
|
||||
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
|
||||
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
|
||||
renderer->setViewProjection(cameraService->getViewProjectionMatrix());
|
||||
} else {
|
||||
renderer->setViewport(0, 0, winMod->win()->width(),
|
||||
winMod->win()->height());
|
||||
}
|
||||
|
||||
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
||||
if (sceneService) {
|
||||
sceneService->render(*renderer);
|
||||
}
|
||||
|
||||
winMod->win()->swap();
|
||||
}
|
||||
|
||||
IWindow *Application::window() {
|
||||
auto *winMod = get<WindowModule>();
|
||||
return winMod ? winMod->win() : nullptr;
|
||||
}
|
||||
|
||||
RenderBackend *Application::renderer() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
return renderMod ? renderMod->renderer() : nullptr;
|
||||
}
|
||||
|
||||
IInput *Application::input() {
|
||||
auto *winMod = get<WindowModule>();
|
||||
return (winMod && winMod->win()) ? winMod->win()->input() : nullptr;
|
||||
}
|
||||
|
||||
void Application::enterScene(Ptr<Scene> scene) {
|
||||
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (sceneService && scene && winMod && winMod->win()) {
|
||||
scene->setViewportSize(static_cast<float>(winMod->win()->width()),
|
||||
static_cast<float>(winMod->win()->height()));
|
||||
sceneService->enterScene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <iostream>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Registry& Registry::instance() {
|
||||
static Registry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool Registry::init() {
|
||||
auto sorted = topologicalSort();
|
||||
|
||||
std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl;
|
||||
|
||||
for (auto* module : sorted) {
|
||||
std::cout << "[Registry] Initializing module: " << module->name() << std::endl;
|
||||
if (!module->init()) {
|
||||
std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "[Registry] All modules initialized" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Registry::shutdown() {
|
||||
auto sorted = topologicalSort();
|
||||
|
||||
// 反向关闭
|
||||
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) {
|
||||
(*it)->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void Registry::clear() {
|
||||
shutdown();
|
||||
modules_.clear();
|
||||
}
|
||||
|
||||
std::vector<Module*> Registry::topologicalSort() {
|
||||
std::vector<Module*> result;
|
||||
std::unordered_map<Module*, int> inDegree;
|
||||
std::unordered_map<Module*, std::vector<Module*>> adj;
|
||||
|
||||
// 构建图
|
||||
for (auto& [typeIdx, module] : modules_) {
|
||||
inDegree[module.get()] = 0;
|
||||
}
|
||||
|
||||
for (auto& [typeIdx, module] : modules_) {
|
||||
for (auto& depType : module->deps()) {
|
||||
Module* dep = get(depType);
|
||||
if (dep) {
|
||||
adj[dep].push_back(module.get());
|
||||
inDegree[module.get()]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 优先级队列(优先级小的先处理)
|
||||
auto cmp = [](Module* a, Module* b) {
|
||||
return a->priority() > b->priority();
|
||||
};
|
||||
std::priority_queue<Module*, std::vector<Module*>, decltype(cmp)> pq(cmp);
|
||||
|
||||
for (auto& [mod, degree] : inDegree) {
|
||||
if (degree == 0) {
|
||||
pq.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
// 拓扑排序
|
||||
while (!pq.empty()) {
|
||||
Module* curr = pq.top();
|
||||
pq.pop();
|
||||
result.push_back(curr);
|
||||
|
||||
for (Module* next : adj[curr]) {
|
||||
inDegree[next]--;
|
||||
if (inDegree[next] == 0) {
|
||||
pq.push(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ServiceLocator& ServiceLocator::instance() {
|
||||
static ServiceLocator instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool ServiceLocator::initializeAll() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto& service : orderedServices_) {
|
||||
if (!service) continue;
|
||||
|
||||
auto info = service->getServiceInfo();
|
||||
if (!info.enabled) continue;
|
||||
|
||||
if (!service->isInitialized()) {
|
||||
service->setState(ServiceState::Initializing);
|
||||
if (!service->initialize()) {
|
||||
service->setState(ServiceState::Stopped);
|
||||
return false;
|
||||
}
|
||||
service->setState(ServiceState::Running);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServiceLocator::shutdownAll() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto it = orderedServices_.rbegin();
|
||||
it != orderedServices_.rend(); ++it) {
|
||||
if (*it && (*it)->isInitialized()) {
|
||||
(*it)->setState(ServiceState::Stopping);
|
||||
(*it)->shutdown();
|
||||
(*it)->setState(ServiceState::Stopped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceLocator::updateAll(float deltaTime) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto& service : orderedServices_) {
|
||||
if (service && service->isInitialized()) {
|
||||
auto state = service->getState();
|
||||
if (state == ServiceState::Running) {
|
||||
service->update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceLocator::pauseAll() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto& service : orderedServices_) {
|
||||
if (service && service->isInitialized()) {
|
||||
service->pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceLocator::resumeAll() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto& service : orderedServices_) {
|
||||
if (service && service->isInitialized()) {
|
||||
service->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SharedPtr<IService>> ServiceLocator::getAllServices() const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return orderedServices_;
|
||||
}
|
||||
|
||||
void ServiceLocator::clear() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
for (auto it = orderedServices_.rbegin();
|
||||
it != orderedServices_.rend(); ++it) {
|
||||
if (*it && (*it)->isInitialized()) {
|
||||
(*it)->setState(ServiceState::Stopping);
|
||||
(*it)->shutdown();
|
||||
(*it)->setState(ServiceState::Stopped);
|
||||
}
|
||||
}
|
||||
|
||||
services_.clear();
|
||||
factories_.clear();
|
||||
orderedServices_.clear();
|
||||
}
|
||||
|
||||
void ServiceLocator::sortServices() {
|
||||
std::stable_sort(orderedServices_.begin(), orderedServices_.end(),
|
||||
[](const SharedPtr<IService>& a, const SharedPtr<IService>& b) {
|
||||
if (!a || !b) return false;
|
||||
return static_cast<int>(a->getServiceInfo().priority) <
|
||||
static_cast<int>(b->getServiceInfo().priority);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#include <extra2d/core/service_registry.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ServiceRegistry& ServiceRegistry::instance() {
|
||||
static ServiceRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ServiceRegistry::setServiceEnabled(const std::string& name, bool enabled) {
|
||||
for (auto& reg : registrations_) {
|
||||
if (reg.name == name) {
|
||||
reg.enabled = enabled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceRegistry::createAllServices() {
|
||||
std::sort(registrations_.begin(), registrations_.end(),
|
||||
[](const ServiceRegistration& a, const ServiceRegistration& b) {
|
||||
return static_cast<int>(a.priority) < static_cast<int>(b.priority);
|
||||
});
|
||||
|
||||
for (const auto& reg : registrations_) {
|
||||
if (!reg.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto service = reg.factory();
|
||||
if (service) {
|
||||
ServiceLocator::instance().registerService<IService>(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
#include <extra2d/event/event.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 创建窗口大小改变事件
|
||||
*
|
||||
* 创建一个表示窗口尺寸变化的Event对象
|
||||
*
|
||||
* @param width 新的窗口宽度(像素)
|
||||
* @param height 新的窗口高度(像素)
|
||||
* @return 包含窗口大小改变信息的Event对象
|
||||
*/
|
||||
Event Event::createWindowResize(int width, int height) {
|
||||
Event event;
|
||||
event.type = EventType::WindowResize;
|
||||
event.data = WindowResizeEvent{width, height};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建窗口关闭事件
|
||||
*
|
||||
* 创建一个表示窗口请求关闭的Event对象
|
||||
*
|
||||
* @return 表示窗口关闭请求的Event对象
|
||||
*/
|
||||
Event Event::createWindowClose() {
|
||||
Event event;
|
||||
event.type = EventType::WindowClose;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建键盘按键按下事件
|
||||
*
|
||||
* 创建一个表示键盘按键被按下的Event对象
|
||||
*
|
||||
* @param keyCode 按键码
|
||||
* @param scancode 扫描码
|
||||
* @param mods 修饰键状态(如Shift、Ctrl等)
|
||||
* @return 包含按键按下信息的Event对象
|
||||
*/
|
||||
Event Event::createKeyPress(int keyCode, int scancode, int mods) {
|
||||
Event event;
|
||||
event.type = EventType::KeyPressed;
|
||||
event.data = KeyEvent{keyCode, scancode, mods};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建键盘按键释放事件
|
||||
*
|
||||
* 创建一个表示键盘按键被释放的Event对象
|
||||
*
|
||||
* @param keyCode 按键码
|
||||
* @param scancode 扫描码
|
||||
* @param mods 修饰键状态(如Shift、Ctrl等)
|
||||
* @return 包含按键释放信息的Event对象
|
||||
*/
|
||||
Event Event::createKeyRelease(int keyCode, int scancode, int mods) {
|
||||
Event event;
|
||||
event.type = EventType::KeyReleased;
|
||||
event.data = KeyEvent{keyCode, scancode, mods};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建鼠标按钮按下事件
|
||||
*
|
||||
* 创建一个表示鼠标按钮被按下的Event对象
|
||||
*
|
||||
* @param button 鼠标按钮编号
|
||||
* @param mods 修饰键状态
|
||||
* @param pos 鼠标按下时的位置坐标
|
||||
* @return 包含鼠标按钮按下信息的Event对象
|
||||
*/
|
||||
Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) {
|
||||
Event event;
|
||||
event.type = EventType::MouseButtonPressed;
|
||||
event.data = MouseButtonEvent{button, mods, pos};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建鼠标按钮释放事件
|
||||
*
|
||||
* 创建一个表示鼠标按钮被释放的Event对象
|
||||
*
|
||||
* @param button 鼠标按钮编号
|
||||
* @param mods 修饰键状态
|
||||
* @param pos 鼠标释放时的位置坐标
|
||||
* @return 包含鼠标按钮释放信息的Event对象
|
||||
*/
|
||||
Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) {
|
||||
Event event;
|
||||
event.type = EventType::MouseButtonReleased;
|
||||
event.data = MouseButtonEvent{button, mods, pos};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建鼠标移动事件
|
||||
*
|
||||
* 创建一个表示鼠标移动的Event对象
|
||||
*
|
||||
* @param pos 鼠标当前位置坐标
|
||||
* @param delta 鼠标移动的位移量
|
||||
* @return 包含鼠标移动信息的Event对象
|
||||
*/
|
||||
Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) {
|
||||
Event event;
|
||||
event.type = EventType::MouseMoved;
|
||||
event.data = MouseMoveEvent{pos, delta};
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建鼠标滚轮滚动事件
|
||||
*
|
||||
* 创建一个表示鼠标滚轮滚动的Event对象
|
||||
*
|
||||
* @param offset 滚轮滚动的偏移量
|
||||
* @param pos 滚动时鼠标的位置坐标
|
||||
* @return 包含鼠标滚轮滚动信息的Event对象
|
||||
*/
|
||||
Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) {
|
||||
Event event;
|
||||
event.type = EventType::MouseScrolled;
|
||||
event.data = MouseScrollEvent{offset, pos};
|
||||
return event;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
#include <extra2d/event/event_dispatcher.h>
|
||||
#include <extra2d/event/event_queue.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*
|
||||
* 初始化事件分发器,设置下一个监听器ID为1
|
||||
*/
|
||||
EventDispatcher::EventDispatcher() : nextId_(1) {}
|
||||
|
||||
/**
|
||||
* @brief 添加事件监听器
|
||||
*
|
||||
* 为指定的事件类型注册一个回调函数,返回监听器ID用于后续移除
|
||||
*
|
||||
* @param type 要监听的事件类型
|
||||
* @param callback 事件触发时调用的回调函数
|
||||
* @return 新注册监听器的唯一ID
|
||||
*/
|
||||
ListenerId EventDispatcher::addListener(EventType type,
|
||||
EventCallback callback) {
|
||||
ListenerId id = nextId_++;
|
||||
listeners_[type].push_back({id, type, callback});
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除指定的事件监听器
|
||||
*
|
||||
* 根据监听器ID移除对应的事件监听器
|
||||
*
|
||||
* @param id 要移除的监听器ID
|
||||
*/
|
||||
void EventDispatcher::removeListener(ListenerId id) {
|
||||
for (auto &[type, listeners] : listeners_) {
|
||||
auto it = std::remove_if(listeners.begin(), listeners.end(),
|
||||
[id](const Listener &l) { return l.id == id; });
|
||||
if (it != listeners.end()) {
|
||||
listeners.erase(it, listeners.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除指定类型的所有监听器
|
||||
*
|
||||
* 移除某个事件类型下的所有已注册监听器
|
||||
*
|
||||
* @param type 要移除监听器的事件类型
|
||||
*/
|
||||
void EventDispatcher::removeAllListeners(EventType type) {
|
||||
listeners_.erase(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除所有监听器
|
||||
*
|
||||
* 清除事件分发器中所有已注册的监听器
|
||||
*/
|
||||
void EventDispatcher::removeAllListeners() { listeners_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 分发事件
|
||||
*
|
||||
* 将事件分发给对应类型的所有监听器,直到事件被标记为已处理或所有监听器执行完毕
|
||||
*
|
||||
* @param event 要分发的事件对象(可修改)
|
||||
*/
|
||||
void EventDispatcher::dispatch(Event &event) {
|
||||
auto it = listeners_.find(event.type);
|
||||
if (it != listeners_.end()) {
|
||||
for (auto &listener : it->second) {
|
||||
if (event.handled)
|
||||
break;
|
||||
listener.callback(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 分发事件(常量版本)
|
||||
*
|
||||
* 创建事件的副本并分发,适用于常量事件对象
|
||||
*
|
||||
* @param event 要分发的常量事件对象
|
||||
*/
|
||||
void EventDispatcher::dispatch(const Event &event) {
|
||||
Event mutableEvent = event;
|
||||
dispatch(mutableEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理事件队列
|
||||
*
|
||||
* 从事件队列中依次取出所有事件并分发
|
||||
*
|
||||
* @param queue 要处理的事件队列
|
||||
*/
|
||||
void EventDispatcher::processQueue(EventQueue &queue) {
|
||||
Event event;
|
||||
while (queue.poll(event)) {
|
||||
dispatch(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定类型监听器的数量
|
||||
*
|
||||
* 返回某个事件类型下已注册的监听器数量
|
||||
*
|
||||
* @param type 要查询的事件类型
|
||||
* @return 该类型下的监听器数量
|
||||
*/
|
||||
size_t EventDispatcher::getListenerCount(EventType type) const {
|
||||
auto it = listeners_.find(type);
|
||||
return (it != listeners_.end()) ? it->second.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有监听器的总数量
|
||||
*
|
||||
* 返回所有事件类型的监听器总数
|
||||
*
|
||||
* @return 所有监听器的总数量
|
||||
*/
|
||||
size_t EventDispatcher::getTotalListenerCount() const {
|
||||
size_t count = 0;
|
||||
for (const auto &[type, listeners] : listeners_) {
|
||||
count += listeners.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
#include <extra2d/event/event_queue.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 默认构造函数
|
||||
*
|
||||
* 构造一个空的事件队列对象
|
||||
*/
|
||||
EventQueue::EventQueue() = default;
|
||||
|
||||
/**
|
||||
* @brief 将事件压入队列(左值引用版本)
|
||||
*
|
||||
* 将事件以拷贝方式添加到队列末尾,线程安全
|
||||
*
|
||||
* @param event 要添加的事件对象
|
||||
*/
|
||||
void EventQueue::push(const Event &event) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
queue_.push(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将事件压入队列(右值引用版本)
|
||||
*
|
||||
* 将事件以移动方式添加到队列末尾,线程安全
|
||||
*
|
||||
* @param event 要添加的事件对象(右值引用)
|
||||
*/
|
||||
void EventQueue::push(Event &&event) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
queue_.push(std::move(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从队列中取出事件
|
||||
*
|
||||
* 从队列头部取出一个事件,如果队列不为空则移除该事件,线程安全
|
||||
*
|
||||
* @param event 输出参数,用于存储取出的事件
|
||||
* @return 如果成功取出事件返回true,队列为空返回false
|
||||
*/
|
||||
bool EventQueue::poll(Event &event) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (queue_.empty()) {
|
||||
return false;
|
||||
}
|
||||
event = queue_.front();
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查看队列头部事件
|
||||
*
|
||||
* 获取队列头部的事件但不移除,线程安全
|
||||
*
|
||||
* @param event 输出参数,用于存储查看到的事件
|
||||
* @return 如果队列不为空返回true,队列为空返回false
|
||||
*/
|
||||
bool EventQueue::peek(Event &event) const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (queue_.empty()) {
|
||||
return false;
|
||||
}
|
||||
event = queue_.front();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清空队列
|
||||
*
|
||||
* 移除队列中的所有事件,线程安全
|
||||
*/
|
||||
void EventQueue::clear() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
while (!queue_.empty()) {
|
||||
queue_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查队列是否为空
|
||||
*
|
||||
* 线程安全地检查队列中是否有事件
|
||||
*
|
||||
* @return 如果队列为空返回true,否则返回false
|
||||
*/
|
||||
bool EventQueue::empty() const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取队列中的事件数量
|
||||
*
|
||||
* 线程安全地获取队列中当前存储的事件数量
|
||||
*
|
||||
* @return 队列中的事件数量
|
||||
*/
|
||||
size_t EventQueue::size() const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return queue_.size();
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
#include <extra2d/graphics/backends/backend_factory.h>
|
||||
|
||||
// 条件编译包含对应后端实现
|
||||
#ifdef E2D_BACKEND_OPENGL
|
||||
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
|
||||
#endif
|
||||
|
||||
#ifdef E2D_BACKEND_VULKAN
|
||||
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
|
||||
#endif
|
||||
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
BackendFactory& BackendFactory::getInstance() {
|
||||
static BackendFactory instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackend(BackendType type) {
|
||||
switch (type) {
|
||||
#ifdef E2D_BACKEND_OPENGL
|
||||
case BackendType::OpenGL:
|
||||
E2D_LOG_INFO("Creating OpenGL render backend");
|
||||
return makeUnique<GLRenderer>();
|
||||
#endif
|
||||
|
||||
#ifdef E2D_BACKEND_VULKAN
|
||||
case BackendType::Vulkan:
|
||||
E2D_LOG_INFO("Creating Vulkan render backend");
|
||||
return makeUnique<VulkanRenderer>();
|
||||
#endif
|
||||
|
||||
default:
|
||||
E2D_LOG_ERROR("Unsupported render backend type: {}", static_cast<int>(type));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
||||
BackendType recommended = getRecommendedBackend();
|
||||
return createBackend(recommended);
|
||||
}
|
||||
|
||||
bool BackendFactory::isBackendAvailable(BackendType type) const {
|
||||
switch (type) {
|
||||
#ifdef E2D_BACKEND_OPENGL
|
||||
case BackendType::OpenGL:
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef E2D_BACKEND_VULKAN
|
||||
case BackendType::Vulkan:
|
||||
return true;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BackendType BackendFactory::getRecommendedBackend() const {
|
||||
// 平台特定的默认后端选择
|
||||
// 优先级:Vulkan > OpenGL
|
||||
|
||||
#ifdef E2D_BACKEND_VULKAN
|
||||
return BackendType::Vulkan;
|
||||
#endif
|
||||
|
||||
#ifdef E2D_BACKEND_OPENGL
|
||||
return BackendType::OpenGL;
|
||||
#endif
|
||||
|
||||
// 如果没有可用的后端,返回OpenGL作为默认值
|
||||
return BackendType::OpenGL;
|
||||
}
|
||||
|
||||
const char* BackendFactory::getBackendName(BackendType type) const {
|
||||
switch (type) {
|
||||
case BackendType::OpenGL:
|
||||
return "OpenGL";
|
||||
case BackendType::Vulkan:
|
||||
return "Vulkan";
|
||||
case BackendType::Metal:
|
||||
return "Metal";
|
||||
case BackendType::D3D11:
|
||||
return "D3D11";
|
||||
case BackendType::D3D12:
|
||||
return "D3D12";
|
||||
case BackendType::OpenGLES:
|
||||
return "OpenGL ES";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
BackendType BackendFactory::parseBackendType(const char* name) const {
|
||||
if (!name) {
|
||||
return BackendType::OpenGL;
|
||||
}
|
||||
|
||||
if (std::strcmp(name, "opengl") == 0 || std::strcmp(name, "OpenGL") == 0) {
|
||||
return BackendType::OpenGL;
|
||||
}
|
||||
if (std::strcmp(name, "vulkan") == 0 || std::strcmp(name, "Vulkan") == 0) {
|
||||
return BackendType::Vulkan;
|
||||
}
|
||||
if (std::strcmp(name, "metal") == 0 || std::strcmp(name, "Metal") == 0) {
|
||||
return BackendType::Metal;
|
||||
}
|
||||
if (std::strcmp(name, "d3d11") == 0 || std::strcmp(name, "D3D11") == 0) {
|
||||
return BackendType::D3D11;
|
||||
}
|
||||
if (std::strcmp(name, "d3d12") == 0 || std::strcmp(name, "D3D12") == 0) {
|
||||
return BackendType::D3D12;
|
||||
}
|
||||
if (std::strcmp(name, "opengles") == 0 || std::strcmp(name, "OpenGLES") == 0) {
|
||||
return BackendType::OpenGLES;
|
||||
}
|
||||
|
||||
E2D_LOG_WARN("Unknown backend type '{}', defaulting to OpenGL", name);
|
||||
return BackendType::OpenGL;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// GLBuffer 实现
|
||||
// ============================================================================
|
||||
|
||||
GLBuffer::GLBuffer() = default;
|
||||
|
||||
GLBuffer::~GLBuffer() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
bool GLBuffer::init(const BufferDesc& desc) {
|
||||
if (bufferID_ != 0) {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
type_ = desc.type;
|
||||
usage_ = desc.usage;
|
||||
size_ = desc.size;
|
||||
target_ = convertType(type_);
|
||||
glUsage_ = convertUsage(usage_);
|
||||
|
||||
// 生成缓冲区
|
||||
glGenBuffers(1, &bufferID_);
|
||||
if (bufferID_ == 0) {
|
||||
E2D_LOG_ERROR("Failed to generate OpenGL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 绑定并分配缓冲区
|
||||
glBindBuffer(target_, bufferID_);
|
||||
glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData, glUsage_);
|
||||
glBindBuffer(target_, 0);
|
||||
|
||||
// 追踪显存使用
|
||||
VRAMMgr::get().allocBuffer(size_);
|
||||
|
||||
E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}",
|
||||
bufferID_, size_, static_cast<int>(type_), static_cast<int>(usage_));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLBuffer::shutdown() {
|
||||
if (bufferID_ != 0) {
|
||||
if (mapped_) {
|
||||
unmap();
|
||||
}
|
||||
// 释放显存追踪
|
||||
VRAMMgr::get().freeBuffer(size_);
|
||||
glDeleteBuffers(1, &bufferID_);
|
||||
E2D_LOG_DEBUG("GLBuffer destroyed: ID={}", bufferID_);
|
||||
bufferID_ = 0;
|
||||
}
|
||||
size_ = 0;
|
||||
mapped_ = false;
|
||||
mappedPtr_ = nullptr;
|
||||
}
|
||||
|
||||
void GLBuffer::bind() {
|
||||
if (bufferID_ != 0) {
|
||||
glBindBuffer(target_, bufferID_);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBuffer::unbind() {
|
||||
glBindBuffer(target_, 0);
|
||||
}
|
||||
|
||||
void GLBuffer::setData(const void* data, size_t size) {
|
||||
if (bufferID_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bind();
|
||||
|
||||
// 如果大小相同,使用 glBufferSubData 更高效
|
||||
if (size == size_) {
|
||||
glBufferSubData(target_, 0, static_cast<GLsizeiptr>(size), data);
|
||||
} else {
|
||||
// 大小不同,重新分配
|
||||
size_ = size;
|
||||
glBufferData(target_, static_cast<GLsizeiptr>(size_), data, glUsage_);
|
||||
}
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
void GLBuffer::updateData(const void* data, size_t offset, size_t size) {
|
||||
if (bufferID_ == 0 || data == nullptr || size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset + size > size_) {
|
||||
E2D_LOG_WARN("GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}",
|
||||
offset, size, size_);
|
||||
return;
|
||||
}
|
||||
|
||||
bind();
|
||||
glBufferSubData(target_, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), data);
|
||||
unbind();
|
||||
}
|
||||
|
||||
void* GLBuffer::map() {
|
||||
if (bufferID_ == 0 || mapped_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bind();
|
||||
|
||||
// 使用 glMapBufferRange 替代 glMapBuffer,更现代且安全
|
||||
GLbitfield access = GL_MAP_WRITE_BIT;
|
||||
if (usage_ == BufferUsage::Dynamic || usage_ == BufferUsage::Stream) {
|
||||
access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据
|
||||
}
|
||||
|
||||
mappedPtr_ = glMapBufferRange(target_, 0, static_cast<GLsizeiptr>(size_), access);
|
||||
if (mappedPtr_) {
|
||||
mapped_ = true;
|
||||
} else {
|
||||
E2D_LOG_ERROR("Failed to map GLBuffer");
|
||||
}
|
||||
|
||||
return mappedPtr_;
|
||||
}
|
||||
|
||||
void GLBuffer::unmap() {
|
||||
if (!mapped_ || bufferID_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
glUnmapBuffer(target_);
|
||||
mapped_ = false;
|
||||
mappedPtr_ = nullptr;
|
||||
unbind();
|
||||
}
|
||||
|
||||
GLenum GLBuffer::convertUsage(BufferUsage usage) {
|
||||
switch (usage) {
|
||||
case BufferUsage::Static:
|
||||
return GL_STATIC_DRAW;
|
||||
case BufferUsage::Dynamic:
|
||||
return GL_DYNAMIC_DRAW;
|
||||
case BufferUsage::Stream:
|
||||
return GL_STREAM_DRAW;
|
||||
default:
|
||||
return GL_STATIC_DRAW;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum GLBuffer::convertType(BufferType type) {
|
||||
switch (type) {
|
||||
case BufferType::Vertex:
|
||||
return GL_ARRAY_BUFFER;
|
||||
case BufferType::Index:
|
||||
return GL_ELEMENT_ARRAY_BUFFER;
|
||||
case BufferType::Uniform:
|
||||
return GL_UNIFORM_BUFFER;
|
||||
default:
|
||||
return GL_ARRAY_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
#include <extra2d/graphics/backends/opengl/gl_context.h>
|
||||
#include <extra2d/graphics/memory/gpu_context.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// GLContext 实现
|
||||
// ============================================================================
|
||||
|
||||
GLContext& GLContext::get() {
|
||||
static GLContext instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool GLContext::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 解析 OpenGL 版本
|
||||
parseVersion();
|
||||
|
||||
// 加载扩展(GLAD 已在 glad.c 中完成)
|
||||
if (!loadExtensions()) {
|
||||
E2D_LOG_ERROR("Failed to load OpenGL extensions");
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
// 标记 GPU 上下文为有效
|
||||
GPUContext::get().markValid();
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context initialized");
|
||||
E2D_LOG_INFO(" Version: {}", getVersionString());
|
||||
E2D_LOG_INFO(" Vendor: {}", getVendor());
|
||||
E2D_LOG_INFO(" Renderer: {}", getRenderer());
|
||||
E2D_LOG_INFO(" Max Texture Size: {}", getMaxTextureSize());
|
||||
E2D_LOG_INFO(" Max Texture Units: {}", getMaxTextureUnits());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::shutdown() {
|
||||
// 标记 GPU 上下文为无效
|
||||
GPUContext::get().markInvalid();
|
||||
|
||||
initialized_ = false;
|
||||
version_ = GLVersion{};
|
||||
maxTextureSize_ = -1;
|
||||
maxTextureUnits_ = -1;
|
||||
maxVertexAttribs_ = -1;
|
||||
maxUniformBufferBindings_ = -1;
|
||||
}
|
||||
|
||||
std::string GLContext::getVersionString() const {
|
||||
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
return version ? version : "Unknown";
|
||||
}
|
||||
|
||||
std::string GLContext::getVendor() const {
|
||||
const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
return vendor ? vendor : "Unknown";
|
||||
}
|
||||
|
||||
std::string GLContext::getRenderer() const {
|
||||
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
return renderer ? renderer : "Unknown";
|
||||
}
|
||||
|
||||
bool GLContext::hasExtension(const std::string& extension) const {
|
||||
GLint numExtensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
||||
|
||||
for (GLint i = 0; i < numExtensions; ++i) {
|
||||
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (ext && extension == ext) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GLContext::getMaxTextureSize() const {
|
||||
if (maxTextureSize_ < 0) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_);
|
||||
}
|
||||
return maxTextureSize_;
|
||||
}
|
||||
|
||||
int GLContext::getMaxTextureUnits() const {
|
||||
if (maxTextureUnits_ < 0) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_);
|
||||
}
|
||||
return maxTextureUnits_;
|
||||
}
|
||||
|
||||
int GLContext::getMaxVertexAttribs() const {
|
||||
if (maxVertexAttribs_ < 0) {
|
||||
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_);
|
||||
}
|
||||
return maxVertexAttribs_;
|
||||
}
|
||||
|
||||
int GLContext::getMaxUniformBufferBindings() const {
|
||||
if (maxUniformBufferBindings_ < 0) {
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_);
|
||||
}
|
||||
return maxUniformBufferBindings_;
|
||||
}
|
||||
|
||||
bool GLContext::hasVAO() const {
|
||||
// OpenGL 3.0+ 或 OpenGL ES 3.0+ 原生支持 VAO
|
||||
if (version_.es) {
|
||||
return version_.major >= 3;
|
||||
}
|
||||
return version_.major > 3 || (version_.major == 3 && version_.minor >= 0);
|
||||
}
|
||||
|
||||
bool GLContext::hasFBO() const {
|
||||
// OpenGL 3.0+ 或 OpenGL ES 2.0+ 原生支持 FBO
|
||||
if (version_.es) {
|
||||
return version_.major >= 2;
|
||||
}
|
||||
return version_.major >= 3;
|
||||
}
|
||||
|
||||
bool GLContext::hasShader() const {
|
||||
// OpenGL 2.0+ 或 OpenGL ES 2.0+ 原生支持 Shader
|
||||
if (version_.es) {
|
||||
return version_.major >= 2;
|
||||
}
|
||||
return version_.major >= 2;
|
||||
}
|
||||
|
||||
void GLContext::parseVersion() {
|
||||
const char* versionStr = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
if (!versionStr) {
|
||||
version_ = GLVersion{0, 0, false};
|
||||
return;
|
||||
}
|
||||
|
||||
std::string version(versionStr);
|
||||
|
||||
// 检查是否为 OpenGL ES
|
||||
if (version.find("OpenGL ES") != std::string::npos) {
|
||||
version_.es = true;
|
||||
// 解析 ES 版本号,格式如 "OpenGL ES 3.0"
|
||||
std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, &version_.minor);
|
||||
} else {
|
||||
version_.es = false;
|
||||
// 解析桌面版本号,格式如 "3.3.0 NVIDIA"
|
||||
std::sscanf(version.c_str(), "%d.%d", &version_.major, &version_.minor);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::loadExtensions() {
|
||||
// GLAD 已经在 glad.c 中加载了所有扩展
|
||||
// 这里可以添加额外的扩展检查
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue