#pragma once #include #include #include #include #include #include #include // 使用 stb_rect_pack 进行矩形打包 #define STB_RECT_PACK_IMPLEMENTATION #include namespace extra2d { /** * @brief 图集区域 * * 存储子图在图集中的位置和 UV 坐标 */ struct AtlasRegion { int x; // 在图集中的 X 坐标(像素) int y; // 在图集中的 Y 坐标(像素) int width; // 宽度(像素) int height; // 高度(像素) /** * @brief 获取归一化 UV 坐标 * @param atlasWidth 图集宽度 * @param atlasHeight 图集高度 * @return UV 矩形 (x, y, width, height) */ Rect getUVRect(int atlasWidth, int atlasHeight) const { return Rect( static_cast(x) / atlasWidth, static_cast(y) / atlasHeight, static_cast(width) / atlasWidth, static_cast(height) / atlasHeight ); } /** * @brief 获取归一化 UV 坐标(翻转 Y 轴) * @param atlasWidth 图集宽度 * @param atlasHeight 图集高度 * @return UV 矩形 (x, y, width, height),Y 轴翻转 */ Rect getUVRectFlipped(int atlasWidth, int atlasHeight) const { float u = static_cast(x) / atlasWidth; float v = static_cast(atlasHeight - y - height) / atlasHeight; float w = static_cast(width) / atlasWidth; float h = static_cast(height) / atlasHeight; return Rect(u, v, w, h); } }; /** * @brief 纹理图集 * * 使用 stb_rect_pack 将多个小纹理打包到一个大纹理中 * 减少纹理切换,提高批处理效率 */ class TextureAtlas : public RefCounted { public: /** * @brief 默认构造函数 */ TextureAtlas(); /** * @brief 析构函数 */ ~TextureAtlas(); // 禁止拷贝 TextureAtlas(const TextureAtlas&) = delete; TextureAtlas& operator=(const TextureAtlas&) = delete; // 允许移动 TextureAtlas(TextureAtlas&& other) noexcept; TextureAtlas& operator=(TextureAtlas&& other) noexcept; /** * @brief 初始化图集 * @param width 图集宽度(必须是 2 的幂) * @param height 图集高度(必须是 2 的幂) * @return 初始化是否成功 */ bool initialize(int width, int height); /** * @brief 关闭图集 */ void shutdown(); /** * @brief 添加纹理到图集 * @param name 纹理名称(用于后续查询) * @param texture 纹理指针 * @return 是否成功添加 */ bool addTexture(const std::string& name, Ptr texture); /** * @brief 从内存添加纹理数据 * @param name 纹理名称 * @param data 像素数据 * @param width 纹理宽度 * @param height 纹理高度 * @param format 像素格式 * @return 是否成功添加 */ bool addTextureData(const std::string& name, const uint8_t* data, int width, int height, TextureFormat format); /** * @brief 完成打包并生成图集纹理 * @return 生成是否成功 */ bool finalize(); /** * @brief 获取图集纹理 * @return 图集纹理指针 */ Ptr getAtlasTexture() const { return atlasTexture_; } /** * @brief 获取子图区域 * @param name 纹理名称 * @return 区域信息,不存在返回 nullptr */ const AtlasRegion* getRegion(const std::string& name) const; /** * @brief 获取子图的 UV 坐标 * @param name 纹理名称 * @return UV 矩形,不存在返回 (0,0,1,1) */ Rect getUVRect(const std::string& name) const; /** * @brief 检查是否包含指定纹理 * @param name 纹理名称 * @return 是否包含 */ bool hasTexture(const std::string& name) const; /** * @brief 获取图集宽度 */ int getWidth() const { return width_; } /** * @brief 获取图集高度 */ int getHeight() const { return height_; } /** * @brief 获取已用空间百分比 */ float getUsageRatio() const; /** * @brief 获取已添加纹理数量 */ size_t getTextureCount() const { return regions_.size(); } /** * @brief 检查是否已最终化 */ bool isFinalized() const { return finalized_; } private: // 待打包的矩形信息 struct PendingTexture { std::string name; int width; int height; std::vector data; TextureFormat format; }; int width_ = 0; int height_ = 0; Ptr atlasTexture_; std::unordered_map regions_; std::vector pendingTextures_; // stb_rect_pack 上下文 std::unique_ptr packContext_; std::vector packNodes_; bool finalized_ = false; /** * @brief 将像素数据复制到图集 */ void copyTextureData(const PendingTexture& tex, const AtlasRegion& region); }; /** * @brief 图集构建器 * * 辅助构建纹理图集的工具类 */ class AtlasBuilder { public: /** * @brief 设置目标图集大小 * @param width 宽度 * @param height 高度 */ void setSize(int width, int height) { width_ = width; height_ = height; } /** * @brief 添加纹理 * @param name 纹理名称 * @param texture 纹理 */ void addTexture(const std::string& name, Ptr texture) { textures_.push_back({name, texture}); } /** * @brief 构建图集 * @return 图集指针,失败返回 nullptr */ Ptr build(); /** * @brief 自动选择最佳图集大小并构建 * @return 图集指针,失败返回 nullptr */ Ptr buildAuto(); private: int width_ = 2048; int height_ = 2048; std::vector>> textures_; }; } // namespace extra2d