渲染后端加入

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

View File

@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are 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 Materials.
**
** THE MATERIALS ARE 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
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,428 @@
// 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.
------------------------------------------------------------------------------
*/

View File

@@ -0,0 +1,623 @@
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
typedef int stbrp_coord;
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
context->extra[1].y = (1<<30);
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
// if it can't possibly fit, bail immediately
if (width > c->width || height > c->height) {
fr.prev_link = NULL;
fr.x = fr.y = 0;
return fr;
}
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
STBRP_ASSERT(y <= best_y);
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
int count=0;
cur = context->active_head;
while (cur) {
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff