diff --git a/include/assets/asset_loader.h b/include/assets/asset_loader.h new file mode 100644 index 0000000..2ee4413 --- /dev/null +++ b/include/assets/asset_loader.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 资源加载器接口 + * + * 每种资源类型实现一个加载器,插件化设计。 + * + * @tparam T 资源类型 + */ +template +class AssetLoader { +public: + virtual ~AssetLoader() = default; + + /** + * @brief 从文件加载资源 + * @param path 文件路径 + * @return 资源指针,失败返回 nullptr + */ + virtual Ptr load(const std::string& path) = 0; + + /** + * @brief 从内存加载资源 + * @param data 数据指针 + * @param size 数据大小 + * @return 资源指针,失败返回 nullptr + */ + virtual Ptr loadFromMemory(const uint8_t* data, size_t size) = 0; + + /** + * @brief 获取支持的文件扩展名 + * @return 扩展名列表(如 ".png", ".jpg") + */ + virtual std::vector getExtensions() const = 0; +}; + +} // namespace extra2d diff --git a/include/assets/asset_storage.h b/include/assets/asset_storage.h new file mode 100644 index 0000000..0f4aeac --- /dev/null +++ b/include/assets/asset_storage.h @@ -0,0 +1,147 @@ +#pragma once + +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 密集存储的资源仓库 + * + * 使用 Dense Vec 存储,类似 ECS 的组件存储。 + * 提供 O(1) 的插入、删除、访问。 + * + * @tparam T 资源类型 + */ +template +class AssetStorage { +public: + struct Slot { + Ptr asset; + typename Handle::Generation generation = 0; + bool active = false; + }; + + AssetStorage() = default; + ~AssetStorage() = default; + + AssetStorage(const AssetStorage&) = delete; + AssetStorage& operator=(const AssetStorage&) = delete; + + /** + * @brief 插入资源,返回句柄 + * @param asset 资源指针 + * @return 资源句柄 + */ + Handle insert(Ptr asset) { + uint32_t index; + + if (!freeIndices_.empty()) { + index = freeIndices_.back(); + freeIndices_.pop_back(); + slots_[index].asset = std::move(asset); + slots_[index].active = true; + } else { + index = static_cast(slots_.size()); + Slot slot; + slot.asset = std::move(asset); + slot.generation = nextGeneration_++; + slot.active = true; + slots_.push_back(std::move(slot)); + } + + ++activeCount_; + return Handle(index, slots_[index].generation); + } + + /** + * @brief 移除资源 + * @param handle 资源句柄 + */ + void remove(Handle handle) { + if (!isValid(handle)) return; + + uint32_t index = handle.index(); + slots_[index].asset.reset(); + slots_[index].active = false; + slots_[index].generation = nextGeneration_++; + freeIndices_.push_back(index); + --activeCount_; + } + + /** + * @brief 获取资源(返回指针,可能为 nullptr) + * @param handle 资源句柄 + * @return 资源指针 + */ + T* get(Handle handle) const { + if (!isValid(handle)) return nullptr; + return slots_[handle.index()].asset.get(); + } + + /** + * @brief 获取资源(返回智能指针) + * @param handle 资源句柄 + * @return 资源智能指针 + */ + Ptr getPtr(Handle handle) const { + if (!isValid(handle)) return Ptr(); + return slots_[handle.index()].asset; + } + + /** + * @brief 检查句柄是否有效 + * @param handle 资源句柄 + * @return 是否有效 + */ + bool isValid(Handle handle) const { + if (!handle.isValid()) return false; + uint32_t index = handle.index(); + if (index >= slots_.size()) return false; + const Slot& slot = slots_[index]; + return slot.active && slot.generation == handle.generation(); + } + + /** + * @brief 遍历所有资源 + * @param func 回调函数,签名 void(Handle, T*) + */ + template + void forEach(Func&& func) const { + for (size_t i = 0; i < slots_.size(); ++i) { + const Slot& slot = slots_[i]; + if (slot.active && slot.asset) { + func(Handle(static_cast(i), slot.generation), slot.asset.get()); + } + } + } + + /** + * @brief 清空所有资源 + */ + void clear() { + slots_.clear(); + freeIndices_.clear(); + activeCount_ = 0; + } + + /** + * @brief 获取活跃资源数量 + */ + size_t count() const { return activeCount_; } + + /** + * @brief 获取存储容量 + */ + size_t capacity() const { return slots_.size(); } + +private: + std::vector slots_; + std::vector freeIndices_; + uint32_t nextGeneration_ = 1; + size_t activeCount_ = 0; +}; + +} // namespace extra2d diff --git a/include/assets/assets_module.h b/include/assets/assets_module.h new file mode 100644 index 0000000..225d419 --- /dev/null +++ b/include/assets/assets_module.h @@ -0,0 +1,399 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 资源管理模块(主流 ECS 风格) + * + * 设计参考 Bevy/Amethyst: + * - AssetStorage: 密集存储资源 + * - load(): 统一加载接口 + * - Handle: 轻量级句柄 + */ +class AssetsModule : public Module { + E2D_REGISTER_MODULE(AssetsModule, "Assets", 2) + +public: + AssetsModule(); + ~AssetsModule() override; + + bool init() override; + void shutdown() override; + + /** + * @brief 在 OpenGL 上下文就绪后创建默认资源 + */ + void onGLContextReady(); + + //=========================================================================== + // 核心加载接口(模板方法,主流设计) + //=========================================================================== + + /** + * @brief 加载资源(自动缓存,重复加载返回已有) + * + * 示例: + * @code + * Handle tex = assets->load("player.png"); + * Handle shader = assets->load("sprite.vert", "sprite.frag"); + * @endcode + * + * @tparam T 资源类型 + * @param path 文件路径 + * @return 资源句柄 + */ + template + Handle load(const std::string& path, Args&&... args); + + /** + * @brief 从内存加载资源 + * @tparam T 资源类型 + * @param key 缓存键名 + * @param data 数据指针 + * @param size 数据大小 + * @return 资源句柄 + */ + template + Handle loadFromMemory(const std::string& key, const uint8_t* data, size_t size); + + /** + * @brief 获取资源(返回指针,可能为 nullptr) + * + * 示例: + * @code + * Texture* tex = assets->get(handle); + * if (tex) { + * tex->bind(); + * } + * @endcode + */ + template + T* get(Handle handle); + + /** + * @brief 获取资源(返回智能指针) + */ + template + Ptr getPtr(Handle handle); + + /** + * @brief 检查句柄是否有效 + */ + template + bool isValid(Handle handle) const; + + /** + * @brief 移除资源 + */ + template + void remove(Handle handle); + + //=========================================================================== + // 批量加载(目录/包) + //=========================================================================== + + /** + * @brief 加载整个目录 + * @tparam T 资源类型 + * @param directory 目录路径 + * @param pattern 文件模式(如 "*.png") + * @param recursive 是否递归 + * @return 句柄列表 + */ + template + std::vector> loadDir(const std::string& directory, + const std::string& pattern = "*", + bool recursive = true); + + //=========================================================================== + // 异步加载 + //=========================================================================== + + /** + * @brief 异步加载资源 + * @tparam T 资源类型 + * @param path 文件路径 + * @param callback 加载完成回调 + */ + template + void loadAsync(const std::string& path, + std::function)> callback); + + //=========================================================================== + // 注册加载器(扩展点) + //=========================================================================== + + /** + * @brief 注册资源加载器 + * @tparam T 资源类型 + * @param loader 加载器实例 + */ + template + void registerLoader(std::unique_ptr> loader); + + //=========================================================================== + // 默认资源 + //=========================================================================== + + /** + * @brief 创建默认资源 + * @return 是否成功 + */ + bool createDefaultResources(); + + /** + * @brief 销毁默认资源 + */ + void destroyDefaultResources(); + + Handle getDefaultTexture(); + Handle getDefaultShader(); + Handle getDefaultMaterial(); + Handle getDefaultQuad(); + + Texture* getDefaultTexturePtr(); + Shader* getDefaultShaderPtr(); + Material* getDefaultMaterialPtr(); + Mesh* getDefaultQuadPtr(); + + //=========================================================================== + // 热重载 + //=========================================================================== + + /** + * @brief 启用/禁用热重载 + * @param enable 是否启用 + */ + void enableHotReload(bool enable); + + /** + * @brief 检查文件变更并重新加载 + */ + void checkForChanges(); + + //=========================================================================== + // 统计 + //=========================================================================== + + struct Stats { + size_t textureCount = 0; + size_t shaderCount = 0; + size_t materialCount = 0; + size_t meshCount = 0; + }; + + Stats getStats() const; + +private: + // 资源存储 + AssetStorage textures_; + AssetStorage shaders_; + AssetStorage materials_; + AssetStorage meshes_; + + // 加载器 + std::unique_ptr> textureLoader_; + std::unique_ptr> shaderLoader_; + + // 路径缓存(避免重复加载) + std::unordered_map> texturePathCache_; + std::unordered_map> shaderPathCache_; + + // 默认资源 + Handle defaultTexture_; + Handle defaultShader_; + Handle defaultMaterial_; + Handle defaultQuad_; + + // 热重载 + bool hotReloadEnabled_ = false; + + // 线程安全 + mutable std::mutex mutex_; + + // 事件监听器 + std::unique_ptr onShowListener_; + + // 标记默认资源是否已创建 + bool defaultResourcesCreated_ = false; +}; + +// 全局访问 +AssetsModule* getAssets(); + +//=========================================================================== +// 模板实现 +//=========================================================================== + +template +Handle AssetsModule::load(const std::string& path, Args&&... args) { + static_assert(sizeof...(Args) == 0 || sizeof...(Args) == 1, + "load() accepts 0 or 1 additional arguments"); + return Handle::invalid(); +} + +template<> +Handle AssetsModule::load(const std::string& path); + +template<> +Handle AssetsModule::load(const std::string& path); + +template<> +Handle AssetsModule::load(const std::string& vertPath, const std::string& fragPath); + +template +Handle AssetsModule::loadFromMemory(const std::string& key, const uint8_t* data, size_t size) { + return Handle::invalid(); +} + +template<> +Handle AssetsModule::loadFromMemory(const std::string& key, const uint8_t* data, size_t size); + +template +T* AssetsModule::get(Handle handle) { + return nullptr; +} + +template<> +inline Texture* AssetsModule::get(Handle handle) { + return textures_.get(handle); +} + +template<> +inline Shader* AssetsModule::get(Handle handle) { + return shaders_.get(handle); +} + +template<> +inline Material* AssetsModule::get(Handle handle) { + return materials_.get(handle); +} + +template<> +inline Mesh* AssetsModule::get(Handle handle) { + return meshes_.get(handle); +} + +template +Ptr AssetsModule::getPtr(Handle handle) { + return Ptr(); +} + +template<> +inline Ptr AssetsModule::getPtr(Handle handle) { + return textures_.getPtr(handle); +} + +template<> +inline Ptr AssetsModule::getPtr(Handle handle) { + return shaders_.getPtr(handle); +} + +template<> +inline Ptr AssetsModule::getPtr(Handle handle) { + return materials_.getPtr(handle); +} + +template<> +inline Ptr AssetsModule::getPtr(Handle handle) { + return meshes_.getPtr(handle); +} + +template +bool AssetsModule::isValid(Handle handle) const { + return false; +} + +template<> +inline bool AssetsModule::isValid(Handle handle) const { + return textures_.isValid(handle); +} + +template<> +inline bool AssetsModule::isValid(Handle handle) const { + return shaders_.isValid(handle); +} + +template<> +inline bool AssetsModule::isValid(Handle handle) const { + return materials_.isValid(handle); +} + +template<> +inline bool AssetsModule::isValid(Handle handle) const { + return meshes_.isValid(handle); +} + +template +void AssetsModule::remove(Handle handle) { +} + +template<> +inline void AssetsModule::remove(Handle handle) { + textures_.remove(handle); +} + +template<> +inline void AssetsModule::remove(Handle handle) { + shaders_.remove(handle); +} + +template<> +inline void AssetsModule::remove(Handle handle) { + materials_.remove(handle); +} + +template<> +inline void AssetsModule::remove(Handle handle) { + meshes_.remove(handle); +} + +template +std::vector> AssetsModule::loadDir(const std::string& directory, + const std::string& pattern, + bool recursive) { + return {}; +} + +template<> +std::vector> AssetsModule::loadDir(const std::string& directory, + const std::string& pattern, + bool recursive); + +template +void AssetsModule::loadAsync(const std::string& path, + std::function)> callback) { +} + +template<> +void AssetsModule::loadAsync(const std::string& path, + std::function)> callback); + +template +void AssetsModule::registerLoader(std::unique_ptr> loader) { +} + +template<> +void AssetsModule::registerLoader(std::unique_ptr> loader); + +template<> +void AssetsModule::registerLoader(std::unique_ptr> loader); + +} // namespace extra2d diff --git a/include/assets/handle.h b/include/assets/handle.h new file mode 100644 index 0000000..6d9e783 --- /dev/null +++ b/include/assets/handle.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 轻量级资源句柄 + * + * 只包含 32-bit 索引和世代,类似 ECS 中的 Entity ID。 + * 不直接管理生命周期,由 AssetStorage 统一管理。 + * + * @tparam T 资源类型 + */ +template +class Handle { +public: + using Index = uint32_t; + using Generation = uint32_t; + + Handle() : index_(0), generation_(0) {} + Handle(Index index, Generation generation) + : index_(index), generation_(generation) {} + + bool isValid() const { return generation_ != 0; } + Index index() const { return index_; } + Generation generation() const { return generation_; } + + bool operator==(const Handle& other) const { + return index_ == other.index_ && generation_ == other.generation_; + } + bool operator!=(const Handle& other) const { return !(*this == other); } + + static Handle invalid() { return Handle(); } + +private: + Index index_; + Generation generation_; +}; + +} // namespace extra2d + +namespace std { + template + struct hash> { + size_t operator()(const extra2d::Handle& h) const { + return std::hash{}( + (static_cast(h.index()) << 32) | h.generation() + ); + } + }; +} diff --git a/include/assets/loaders/shader_loader.h b/include/assets/loaders/shader_loader.h new file mode 100644 index 0000000..adcee90 --- /dev/null +++ b/include/assets/loaders/shader_loader.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 着色器资源加载器 + * + * 支持从文件或源码加载着色器资源 + */ +class ShaderLoader : public AssetLoader { +public: + /** + * @brief 从文件加载着色器 + * @param path 单个文件路径(自动推断 .vert/.frag) + * @return 着色器指针,失败返回 nullptr + */ + Ptr load(const std::string& path) override; + + /** + * @brief 从文件加载着色器(指定顶点和片段着色器) + * @param vertPath 顶点着色器路径 + * @param fragPath 片段着色器路径 + * @return 着色器指针,失败返回 nullptr + */ + Ptr load(const std::string& vertPath, const std::string& fragPath); + + /** + * @brief 从内存加载着色器(不支持) + * @param data 数据指针 + * @param size 数据大小 + * @return nullptr + */ + Ptr loadFromMemory(const uint8_t* data, size_t size) override; + + /** + * @brief 从源码加载着色器 + * @param vsSource 顶点着色器源码 + * @param fsSource 片段着色器源码 + * @return 着色器指针,失败返回 nullptr + */ + Ptr loadFromSource(const std::string& vsSource, const std::string& fsSource); + + /** + * @brief 获取支持的文件扩展名 + * @return 扩展名列表 + */ + std::vector getExtensions() const override { + return {".glsl", ".vert", ".frag"}; + } +}; + +} // namespace extra2d diff --git a/include/assets/loaders/texture_loader.h b/include/assets/loaders/texture_loader.h new file mode 100644 index 0000000..83695da --- /dev/null +++ b/include/assets/loaders/texture_loader.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +namespace extra2d { + +/** + * @brief 纹理资源加载器 + * + * 支持从文件或内存加载纹理资源 + */ +class TextureLoader : public AssetLoader { +public: + /** + * @brief 从文件加载纹理 + * @param path 文件路径 + * @return 纹理指针,失败返回 nullptr + */ + Ptr load(const std::string& path) override; + + /** + * @brief 从内存加载纹理 + * @param data 图像数据 + * @param size 数据大小 + * @return 纹理指针,失败返回 nullptr + */ + Ptr loadFromMemory(const uint8_t* data, size_t size) override; + + /** + * @brief 获取支持的文件扩展名 + * @return 扩展名列表 + */ + std::vector getExtensions() const override { + return {".png", ".jpg", ".jpeg", ".bmp", ".tga"}; + } +}; + +} // namespace extra2d diff --git a/include/renderer/material.h b/include/renderer/material.h index 9930f2a..7f4daa1 100644 --- a/include/renderer/material.h +++ b/include/renderer/material.h @@ -30,7 +30,7 @@ struct MaterialParamInfo { * @brief 纹理槽位信息 */ struct TextureSlot { - TextureHandle handle; + Handle handle; uint32_t slot; std::string uniformName; }; @@ -196,7 +196,7 @@ public: * @param texture 纹理句柄 * @param slot 纹理槽位(0-15) */ - void setTexture(const std::string& uniformName, TextureHandle texture, uint32_t slot); + void setTexture(const std::string& uniformName, Handle texture, uint32_t slot); /** * @brief 获取所有纹理槽位 diff --git a/include/renderer/render_types.h b/include/renderer/render_types.h index b41621e..eada0aa 100644 --- a/include/renderer/render_types.h +++ b/include/renderer/render_types.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -14,15 +15,10 @@ class Material; class Mesh; class Texture; -// 资源句柄类型(64位,替代智能指针) -using MaterialHandle = uint64_t; -using MeshHandle = uint64_t; -using TextureHandle = uint64_t; - -// 无效句柄值 -constexpr MaterialHandle INVALID_MATERIAL_HANDLE = 0; -constexpr MeshHandle INVALID_MESH_HANDLE = 0; -constexpr TextureHandle INVALID_TEXTURE_HANDLE = 0; +// 资源句柄类型(使用新的 Handle) +using MaterialHandle = Handle; +using MeshHandle = Handle; +using TextureHandle = Handle; /** * @brief 渲染命令类型 @@ -87,7 +83,7 @@ inline uint32_t getMaterialParamSize(MaterialParamType type) { case MaterialParamType::Vec4: return sizeof(float) * 4; case MaterialParamType::Color: return sizeof(float) * 4; case MaterialParamType::Mat4: return sizeof(float) * 16; - case MaterialParamType::Texture: return sizeof(TextureHandle); + case MaterialParamType::Texture: return sizeof(uint32_t) * 2; // Handle size default: return 0; } } @@ -143,8 +139,8 @@ struct RenderCommand { * @brief 默认构造函数 */ RenderCommand() : type(RenderCommandType::DrawMesh), sortKey(0) { - drawMesh.mesh = INVALID_MESH_HANDLE; - drawMesh.material = INVALID_MATERIAL_HANDLE; + drawMesh.mesh = MeshHandle::invalid(); + drawMesh.material = MaterialHandle::invalid(); drawMesh.pos = Vec2(0.0f, 0.0f); drawMesh.scale = Vec2(1.0f, 1.0f); drawMesh.rot = 0.0f; diff --git a/include/renderer/renderer_module.h b/include/renderer/renderer_module.h index 5400a23..47166e5 100644 --- a/include/renderer/renderer_module.h +++ b/include/renderer/renderer_module.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -16,17 +15,20 @@ namespace extra2d { +// 前向声明 +class AssetsModule; + /** * @brief 渲染器模块 * * 核心渲染系统模块,负责: * - 通过事件接收渲染命令 * - 自动批处理和排序 - * - GPU 资源管理 * - 执行实际渲染 + * + * 资源管理已迁移到 AssetsModule */ class RendererModule : public Module { - // 自动注册到模块系统,优先级为 3(在 Window、Timer、Input 之后) E2D_REGISTER_MODULE(RendererModule, "Renderer", 3) public: @@ -65,94 +67,26 @@ public: void shutdown() override; //=========================================================================== - // 资源注册接口(供其他模块使用) - //=========================================================================== - - /** - * @brief 注册材质 - * @param material 材质对象 - * @return 材质句柄 - */ - MaterialHandle registerMaterial(Ptr material); - - /** - * @brief 注册网格 - * @param mesh 网格对象 - * @return 网格句柄 - */ - MeshHandle registerMesh(Ptr mesh); - - /** - * @brief 注册纹理 - * @param texture 纹理对象 - * @return 纹理句柄 - */ - TextureHandle registerTexture(Ptr texture); - - /** - * @brief 注销材质 - * @param handle 材质句柄 - */ - void unregisterMaterial(MaterialHandle handle); - - /** - * @brief 注销网格 - * @param handle 网格句柄 - */ - void unregisterMesh(MeshHandle handle); - - /** - * @brief 注销纹理 - * @param handle 纹理句柄 - */ - void unregisterTexture(TextureHandle handle); - - /** - * @brief 获取材质 - * @param handle 材质句柄 - * @return 材质对象,无效句柄返回 nullptr - */ - Ptr getMaterial(MaterialHandle handle); - - /** - * @brief 获取网格 - * @param handle 网格句柄 - * @return 网格对象,无效句柄返回 nullptr - */ - Ptr getMesh(MeshHandle handle); - - /** - * @brief 获取纹理 - * @param handle 纹理句柄 - * @return 纹理对象,无效句柄返回 nullptr - */ - Ptr getTexture(TextureHandle handle); - - //=========================================================================== - // 默认资源 + // 默认资源(通过 AssetsModule 获取) //=========================================================================== /** * @brief 获取默认材质句柄 * @return 默认材质句柄 */ - MaterialHandle getDefaultMaterialHandle() const { - return defaultMaterialHandle_; - } + MaterialHandle getDefaultMaterialHandle() const; /** * @brief 获取默认四边形网格句柄 * @return 默认四边形网格句柄 */ - MeshHandle getDefaultQuadHandle() const { return defaultQuadHandle_; } + MeshHandle getDefaultQuadHandle() const; /** * @brief 获取默认纹理句柄(1x1 白色纹理) * @return 默认纹理句柄 */ - TextureHandle getDefaultTextureHandle() const { - return defaultTextureHandle_; - } + TextureHandle getDefaultTextureHandle() const; //=========================================================================== // 渲染状态设置 @@ -266,105 +200,6 @@ private: */ void executeCommand(const RenderCommand &cmd); - //=========================================================================== - // 默认资源创建与销毁 - //=========================================================================== - - /** - * @brief 创建默认资源 - * @return 创建是否成功 - */ - bool createDefaultResources(); - - /** - * @brief 销毁默认资源 - */ - void destroyDefaultResources(); - - //=========================================================================== - // 资源句柄管理 - //=========================================================================== - - /** - * @brief 资源槽位结构 - * - * 用于管理资源对象和句柄生命周期 - */ - struct ResourceSlot { - Ptr material; - Ptr mesh; - Ptr texture; - uint32 generation = 0; - bool active = false; - }; - - /** - * @brief 句柄池模板类 - * - * 管理资源句柄的分配和回收 - */ - template struct HandlePool { - std::vector slots; - std::queue freeIndices; - uint32 nextGeneration = 1; - - /** - * @brief 分配新句柄 - * @return 编码后的句柄(高32位索引,低32位世代) - */ - uint64 acquire() { - uint32 index; - if (!freeIndices.empty()) { - index = freeIndices.front(); - freeIndices.pop(); - } else { - index = static_cast(slots.size()); - slots.emplace_back(); - } - - slots[index].active = true; - slots[index].generation = nextGeneration++; - - // 编码句柄:高32位是索引,低32位是世代 - return (static_cast(index) << 32) | slots[index].generation; - } - - /** - * @brief 释放句柄 - * @param handle 要释放的句柄 - */ - void release(uint64 handle) { - uint32 index = static_cast(handle >> 32); - if (index < slots.size() && slots[index].active) { - slots[index].active = false; - slots[index].material.reset(); - slots[index].mesh.reset(); - slots[index].texture.reset(); - freeIndices.push(index); - } - } - - /** - * @brief 获取资源槽位 - * @param handle 资源句柄 - * @return 资源槽位指针,无效句柄返回 nullptr - */ - ResourceSlot *get(uint64 handle) { - uint32 index = static_cast(handle >> 32); - uint32 generation = static_cast(handle & 0xFFFFFFFF); - - if (index < slots.size() && slots[index].active && - slots[index].generation == generation) { - return &slots[index]; - } - return nullptr; - } - }; - - HandlePool materialPool_; // 材质资源池 - HandlePool meshPool_; // 网格资源池 - HandlePool texturePool_; // 纹理资源池 - //=========================================================================== // 命令缓冲区 //=========================================================================== @@ -379,14 +214,6 @@ private: UniformBufferManager uniformManager_; - //=========================================================================== - // 默认资源句柄 - //=========================================================================== - - MaterialHandle defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE; - MeshHandle defaultQuadHandle_ = INVALID_MESH_HANDLE; - TextureHandle defaultTextureHandle_ = INVALID_TEXTURE_HANDLE; - //=========================================================================== // 事件监听器 //=========================================================================== diff --git a/include/scene/components/sprite_renderer.h b/include/scene/components/sprite_renderer.h index 0189b8e..bc7fefe 100644 --- a/include/scene/components/sprite_renderer.h +++ b/include/scene/components/sprite_renderer.h @@ -3,9 +3,14 @@ #include #include #include +#include namespace extra2d { +// 前向声明 +class Material; +class Texture; + /** * @brief 精灵渲染组件 * @@ -22,7 +27,7 @@ namespace extra2d { * material->setShader(customShader); * material->setTexture("uTexture", textureHandle, 0); * material->setColor("uTintColor", Color::Red); - * MaterialHandle matHandle = renderer->registerMaterial(material); + * Handle matHandle = assets->load("material.mat"); * sprite->setMaterial(matHandle); * * // 方式2:只设置纹理(使用默认材质) @@ -60,13 +65,13 @@ public: * 材质包含着色器、参数和纹理 * @param material 材质句柄 */ - void setMaterial(MaterialHandle material); + void setMaterial(Handle material); /** * @brief 获取材质 * @return 材质句柄 */ - MaterialHandle getMaterial() const { return material_; } + Handle getMaterial() const { return material_; } // ======================================== // 纹理设置(便捷方式) @@ -79,13 +84,13 @@ public: * 如果设置了材质,此设置被忽略(材质中的纹理优先) * @param texture 纹理句柄 */ - void setTexture(TextureHandle texture); + void setTexture(Handle texture); /** * @brief 获取纹理 * @return 纹理句柄 */ - TextureHandle getTexture() const { return texture_; } + Handle getTexture() const { return texture_; } // ======================================== // 颜色(顶点颜色) @@ -113,9 +118,9 @@ public: void render() override; private: - MaterialHandle material_ = INVALID_MATERIAL_HANDLE; // 材质句柄 - TextureHandle texture_ = INVALID_TEXTURE_HANDLE; // 纹理句柄(便捷方式) - Color color_ = Color::White; // 顶点颜色 + Handle material_; // 材质句柄 + Handle texture_; // 纹理句柄(便捷方式) + Color color_ = Color::White; // 顶点颜色 }; } // namespace extra2d diff --git a/src/assets/assets_module.cpp b/src/assets/assets_module.cpp new file mode 100644 index 0000000..b8f9316 --- /dev/null +++ b/src/assets/assets_module.cpp @@ -0,0 +1,404 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +AssetsModule *g_assetsModule = nullptr; + +AssetsModule::AssetsModule() { g_assetsModule = this; } + +AssetsModule::~AssetsModule() { + if (g_assetsModule == this) { + g_assetsModule = nullptr; + } +} + +bool AssetsModule::init() { + E2D_LOG_INFO("AssetsModule initializing..."); + + textureLoader_ = std::make_unique(); + shaderLoader_ = std::make_unique(); + + // 监听窗口显示事件,在 OpenGL 上下文创建完成后创建默认资源 + onShowListener_ = std::make_unique(); + onShowListener_->bind([this]() { this->onGLContextReady(); }); + + E2D_LOG_INFO( + "AssetsModule initialized successfully (waiting for GL context)"); + return true; +} + +void AssetsModule::onGLContextReady() { + if (defaultResourcesCreated_) { + return; + } + + E2D_LOG_INFO("OpenGL context ready, creating default resources..."); + + if (!createDefaultResources()) { + E2D_LOG_ERROR("Failed to create default resources"); + return; + } + + defaultResourcesCreated_ = true; + E2D_LOG_INFO("Default resources created successfully"); +} + +void AssetsModule::shutdown() { + E2D_LOG_INFO("AssetsModule shutting down..."); + + // 释放事件监听器 + onShowListener_.reset(); + + destroyDefaultResources(); + + textures_.clear(); + shaders_.clear(); + materials_.clear(); + meshes_.clear(); + + texturePathCache_.clear(); + shaderPathCache_.clear(); + + textureLoader_.reset(); + shaderLoader_.reset(); + + defaultResourcesCreated_ = false; + + E2D_LOG_INFO("AssetsModule shutdown complete"); +} + +AssetsModule *getAssets() { return g_assetsModule; } + +//=========================================================================== +// Texture 加载特化 +//=========================================================================== + +template <> +Handle AssetsModule::load(const std::string &path) { + auto it = texturePathCache_.find(path); + if (it != texturePathCache_.end()) { + if (textures_.isValid(it->second)) { + return it->second; + } + texturePathCache_.erase(it); + } + + if (!textureLoader_) { + E2D_LOG_ERROR("TextureLoader not registered"); + return Handle::invalid(); + } + + Ptr texture = textureLoader_->load(path); + if (!texture) { + E2D_LOG_ERROR("Failed to load texture: {}", path); + return Handle::invalid(); + } + + Handle handle = textures_.insert(texture); + texturePathCache_[path] = handle; + + E2D_LOG_DEBUG("Loaded texture: {} -> handle index {}", path, handle.index()); + return handle; +} + +template <> +Handle AssetsModule::loadFromMemory(const std::string &key, + const uint8_t *data, + size_t size) { + auto it = texturePathCache_.find(key); + if (it != texturePathCache_.end()) { + if (textures_.isValid(it->second)) { + return it->second; + } + texturePathCache_.erase(it); + } + + if (!textureLoader_) { + E2D_LOG_ERROR("TextureLoader not registered"); + return Handle::invalid(); + } + + Ptr texture = textureLoader_->loadFromMemory(data, size); + if (!texture) { + E2D_LOG_ERROR("Failed to load texture from memory: {}", key); + return Handle::invalid(); + } + + Handle handle = textures_.insert(texture); + texturePathCache_[key] = handle; + + return handle; +} + +//=========================================================================== +// Shader 加载特化 +//=========================================================================== + +template <> Handle AssetsModule::load(const std::string &path) { + auto it = shaderPathCache_.find(path); + if (it != shaderPathCache_.end()) { + if (shaders_.isValid(it->second)) { + return it->second; + } + shaderPathCache_.erase(it); + } + + if (!shaderLoader_) { + E2D_LOG_ERROR("ShaderLoader not registered"); + return Handle::invalid(); + } + + Ptr shader = shaderLoader_->load(path); + if (!shader) { + E2D_LOG_ERROR("Failed to load shader: {}", path); + return Handle::invalid(); + } + + Handle handle = shaders_.insert(shader); + shaderPathCache_[path] = handle; + + E2D_LOG_DEBUG("Loaded shader: {} -> handle index {}", path, handle.index()); + return handle; +} + +template <> +Handle AssetsModule::load(const std::string &vertPath, + const std::string &fragPath) { + std::string cacheKey = vertPath + "|" + fragPath; + + auto it = shaderPathCache_.find(cacheKey); + if (it != shaderPathCache_.end()) { + if (shaders_.isValid(it->second)) { + return it->second; + } + shaderPathCache_.erase(it); + } + + if (!shaderLoader_) { + E2D_LOG_ERROR("ShaderLoader not registered"); + return Handle::invalid(); + } + + ShaderLoader *shaderLoader = static_cast(shaderLoader_.get()); + Ptr shader = shaderLoader->load(vertPath, fragPath); + if (!shader) { + E2D_LOG_ERROR("Failed to load shader: {} + {}", vertPath, fragPath); + return Handle::invalid(); + } + + Handle handle = shaders_.insert(shader); + shaderPathCache_[cacheKey] = handle; + + E2D_LOG_DEBUG("Loaded shader: {} + {} -> handle index {}", vertPath, fragPath, + handle.index()); + return handle; +} + +//=========================================================================== +// 批量加载 +//=========================================================================== + +template <> +std::vector> +AssetsModule::loadDir(const std::string &directory, + const std::string &pattern, bool recursive) { + std::vector> handles; + + try { + std::filesystem::path dirPath(directory); + if (!std::filesystem::exists(dirPath)) { + E2D_LOG_WARN("Directory not found: {}", directory); + return handles; + } + + auto loadFile = [this, &handles](const std::filesystem::path &filePath) { + std::string ext = filePath.extension().string(); + std::string pathStr = filePath.string(); + + for (const auto &supportedExt : textureLoader_->getExtensions()) { + if (ext == supportedExt) { + Handle handle = load(pathStr); + if (handle.isValid()) { + handles.push_back(handle); + } + break; + } + } + }; + + if (recursive) { + for (const auto &entry : + std::filesystem::recursive_directory_iterator(dirPath)) { + if (entry.is_regular_file()) { + loadFile(entry.path()); + } + } + } else { + for (const auto &entry : std::filesystem::directory_iterator(dirPath)) { + if (entry.is_regular_file()) { + loadFile(entry.path()); + } + } + } + } catch (const std::exception &e) { + E2D_LOG_ERROR("Error loading directory {}: {}", directory, e.what()); + } + + E2D_LOG_DEBUG("Loaded {} textures from {}", handles.size(), directory); + return handles; +} + +//=========================================================================== +// 异步加载 +//=========================================================================== + +template <> +void AssetsModule::loadAsync( + const std::string &path, std::function)> callback) { + std::thread([this, path, callback]() { + Handle handle = load(path); + if (callback) { + callback(handle); + } + }).detach(); +} + +//=========================================================================== +// 加载器注册 +//=========================================================================== + +template <> +void AssetsModule::registerLoader( + std::unique_ptr> loader) { + textureLoader_ = std::move(loader); +} + +template <> +void AssetsModule::registerLoader( + std::unique_ptr> loader) { + shaderLoader_ = std::move(loader); +} + +//=========================================================================== +// 默认资源 +//=========================================================================== + +bool AssetsModule::createDefaultResources() { + { + Ptr texture = makePtr(); + uint8_t whitePixel[] = {255, 255, 255, 255}; + if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) { + E2D_LOG_ERROR("Failed to create default texture"); + return false; + } + defaultTexture_ = textures_.insert(texture); + E2D_LOG_DEBUG("Created default texture"); + } + + { + // 从文件加载默认着色器 + std::filesystem::path vertPath = "shader/default.vert"; + std::filesystem::path fragPath = "shader/default.frag"; + + Ptr shader = makePtr(); + + if (!std::filesystem::exists(vertPath) || + !std::filesystem::exists(fragPath)) { + E2D_LOG_ERROR("Default shader files not found: {}, {}", vertPath.string(), + fragPath.string()); + return false; + } + + if (!shader->loadFromFile(vertPath.string(), fragPath.string())) { + E2D_LOG_ERROR("Failed to load default shader from files: {}, {}", + vertPath.string(), fragPath.string()); + return false; + } + + defaultShader_ = shaders_.insert(shader); + E2D_LOG_DEBUG("Loaded default shader from files: {}, {}", vertPath.string(), + fragPath.string()); + } + + { + Ptr material = makePtr(); + material->setShader(getPtr(defaultShader_)); + defaultMaterial_ = materials_.insert(material); + E2D_LOG_DEBUG("Created default material"); + } + + { + Ptr mesh = Mesh::createQuad(Vec2(1.0f, 1.0f)); + if (!mesh) { + E2D_LOG_ERROR("Failed to create default quad mesh"); + return false; + } + defaultQuad_ = meshes_.insert(mesh); + E2D_LOG_DEBUG("Created default quad mesh"); + } + + return true; +} + +void AssetsModule::destroyDefaultResources() { + materials_.remove(defaultMaterial_); + meshes_.remove(defaultQuad_); + textures_.remove(defaultTexture_); + shaders_.remove(defaultShader_); + + defaultMaterial_ = Handle::invalid(); + defaultQuad_ = Handle::invalid(); + defaultTexture_ = Handle::invalid(); + defaultShader_ = Handle::invalid(); +} + +Handle AssetsModule::getDefaultTexture() { return defaultTexture_; } + +Handle AssetsModule::getDefaultShader() { return defaultShader_; } + +Handle AssetsModule::getDefaultMaterial() { return defaultMaterial_; } + +Handle AssetsModule::getDefaultQuad() { return defaultQuad_; } + +Texture *AssetsModule::getDefaultTexturePtr() { + return textures_.get(defaultTexture_); +} + +Shader *AssetsModule::getDefaultShaderPtr() { + return shaders_.get(defaultShader_); +} + +Material *AssetsModule::getDefaultMaterialPtr() { + return materials_.get(defaultMaterial_); +} + +Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); } + +//=========================================================================== +// 热重载 +//=========================================================================== + +void AssetsModule::enableHotReload(bool enable) { hotReloadEnabled_ = enable; } + +void AssetsModule::checkForChanges() {} + +//=========================================================================== +// 统计 +//=========================================================================== + +AssetsModule::Stats AssetsModule::getStats() const { + Stats stats; + stats.textureCount = textures_.count(); + stats.shaderCount = shaders_.count(); + stats.materialCount = materials_.count(); + stats.meshCount = meshes_.count(); + return stats; +} + +} // namespace extra2d diff --git a/src/assets/loaders/shader_loader.cpp b/src/assets/loaders/shader_loader.cpp new file mode 100644 index 0000000..e672e3e --- /dev/null +++ b/src/assets/loaders/shader_loader.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +namespace extra2d { + +Ptr ShaderLoader::load(const std::string &path) { + std::string basePath = path; + + std::string::size_type dotPos = basePath.rfind('.'); + if (dotPos != std::string::npos) { + basePath = basePath.substr(0, dotPos); + } + + std::string vertPath = basePath + ".vert"; + std::string fragPath = basePath + ".frag"; + + if (!std::filesystem::exists(vertPath)) { + vertPath = basePath + ".vs"; + } + if (!std::filesystem::exists(fragPath)) { + fragPath = basePath + ".fs"; + } + + return load(vertPath, fragPath); +} + +Ptr ShaderLoader::load(const std::string &vertPath, + const std::string &fragPath) { + Ptr shader = makePtr(); + + if (!shader->loadFromFile(vertPath, fragPath)) { + E2D_LOG_ERROR("ShaderLoader: Failed to load shader {} + {}", vertPath, + fragPath); + return Ptr(); + } + + E2D_LOG_DEBUG("ShaderLoader: Loaded shader {} + {}", vertPath, fragPath); + return shader; +} + +Ptr ShaderLoader::loadFromMemory(const uint8_t *data, size_t size) { + E2D_LOG_ERROR("ShaderLoader: loadFromMemory not supported for shaders"); + return Ptr(); +} + +Ptr ShaderLoader::loadFromSource(const std::string &vsSource, + const std::string &fsSource) { + Ptr shader = makePtr(); + + if (!shader->loadFromSource(vsSource, fsSource)) { + E2D_LOG_ERROR("ShaderLoader: Failed to compile shader from source"); + return Ptr(); + } + + E2D_LOG_DEBUG("ShaderLoader: Compiled shader from source"); + return shader; +} + +} // namespace extra2d diff --git a/src/assets/loaders/texture_loader.cpp b/src/assets/loaders/texture_loader.cpp new file mode 100644 index 0000000..b212600 --- /dev/null +++ b/src/assets/loaders/texture_loader.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include + +namespace extra2d { + +Ptr TextureLoader::load(const std::string &path) { + Ptr texture = makePtr(); + + if (!texture->loadFromFile(path)) { + E2D_LOG_ERROR("TextureLoader: Failed to load texture from {}", path); + return Ptr(); + } + + E2D_LOG_DEBUG("TextureLoader: Loaded texture {}", path); + return texture; +} + +Ptr TextureLoader::loadFromMemory(const uint8_t *data, size_t size) { + int width, height, channels; + + stbi_set_flip_vertically_on_load(true); + uint8_t *imageData = stbi_load_from_memory(data, static_cast(size), + &width, &height, &channels, 0); + + if (!imageData) { + E2D_LOG_ERROR("TextureLoader: Failed to decode image from memory"); + return Ptr(); + } + + TextureFormat format; + switch (channels) { + case 1: + format = TextureFormat::R8; + break; + case 2: + format = TextureFormat::RG8; + break; + case 3: + format = TextureFormat::RGB8; + break; + case 4: + format = TextureFormat::RGBA8; + break; + default: + format = TextureFormat::RGBA8; + break; + } + + Ptr texture = makePtr(); + bool success = texture->loadFromMemory(imageData, width, height, format); + stbi_image_free(imageData); + + if (!success) { + E2D_LOG_ERROR("TextureLoader: Failed to create texture from memory"); + return Ptr(); + } + + E2D_LOG_DEBUG("TextureLoader: Created texture from memory ({}x{})", width, + height); + return texture; +} + +} // namespace extra2d diff --git a/src/renderer/material.cpp b/src/renderer/material.cpp index 40b3d14..02da2bd 100644 --- a/src/renderer/material.cpp +++ b/src/renderer/material.cpp @@ -197,7 +197,7 @@ void Material::setMat4(const std::string& name, const float* value) { * @param texture 纹理句柄 * @param slot 纹理槽位(0-15) */ -void Material::setTexture(const std::string& uniformName, TextureHandle texture, uint32_t slot) { +void Material::setTexture(const std::string& uniformName, Handle texture, uint32_t slot) { // 查找是否已存在相同名称的纹理 for (auto& texSlot : textures_) { if (texSlot.uniformName == uniformName) { diff --git a/src/renderer/renderer_module.cpp b/src/renderer/renderer_module.cpp index 174409f..c66c461 100644 --- a/src/renderer/renderer_module.cpp +++ b/src/renderer/renderer_module.cpp @@ -1,11 +1,11 @@ #include "glad/glad.h" #include +#include #include #include #include #include -// SDL for window size query #include namespace extra2d { @@ -15,29 +15,22 @@ RendererModule::RendererModule() = default; RendererModule::~RendererModule() = default; RendererModule::RendererModule(RendererModule &&other) noexcept - : materialPool_(std::move(other.materialPool_)), - meshPool_(std::move(other.meshPool_)), - texturePool_(std::move(other.texturePool_)), - commandBuffer_(std::move(other.commandBuffer_)), + : commandBuffer_(std::move(other.commandBuffer_)), commandCount_(other.commandCount_), uniformManager_(std::move(other.uniformManager_)), - defaultMaterialHandle_(other.defaultMaterialHandle_), - defaultQuadHandle_(other.defaultQuadHandle_), - defaultTextureHandle_(other.defaultTextureHandle_), onRenderBeginListener_(std::move(other.onRenderBeginListener_)), onRenderSubmitListener_(std::move(other.onRenderSubmitListener_)), + onRenderSetCameraListener_(std::move(other.onRenderSetCameraListener_)), onRenderEndListener_(std::move(other.onRenderEndListener_)), onResizeListener_(std::move(other.onResizeListener_)), onShowListener_(std::move(other.onShowListener_)), glInitialized_(other.glInitialized_), stats_(other.stats_), viewportX_(other.viewportX_), viewportY_(other.viewportY_), viewportWidth_(other.viewportWidth_), - viewportHeight_(other.viewportHeight_) { - // 重置源对象状态 + viewportHeight_(other.viewportHeight_), + viewportAdapter_(std::move(other.viewportAdapter_)), + viewProjectionMatrix_(std::move(other.viewProjectionMatrix_)) { other.commandCount_ = 0; - other.defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE; - other.defaultQuadHandle_ = INVALID_MESH_HANDLE; - other.defaultTextureHandle_ = INVALID_TEXTURE_HANDLE; other.glInitialized_ = false; other.stats_ = {}; other.viewportX_ = 0; @@ -48,24 +41,16 @@ RendererModule::RendererModule(RendererModule &&other) noexcept RendererModule &RendererModule::operator=(RendererModule &&other) noexcept { if (this != &other) { - // 清理当前资源 if (glInitialized_) { - destroyDefaultResources(); uniformManager_.shutdown(); } - // 移动资源 - materialPool_ = std::move(other.materialPool_); - meshPool_ = std::move(other.meshPool_); - texturePool_ = std::move(other.texturePool_); commandBuffer_ = std::move(other.commandBuffer_); commandCount_ = other.commandCount_; uniformManager_ = std::move(other.uniformManager_); - defaultMaterialHandle_ = other.defaultMaterialHandle_; - defaultQuadHandle_ = other.defaultQuadHandle_; - defaultTextureHandle_ = other.defaultTextureHandle_; onRenderBeginListener_ = std::move(other.onRenderBeginListener_); onRenderSubmitListener_ = std::move(other.onRenderSubmitListener_); + onRenderSetCameraListener_ = std::move(other.onRenderSetCameraListener_); onRenderEndListener_ = std::move(other.onRenderEndListener_); onResizeListener_ = std::move(other.onResizeListener_); onShowListener_ = std::move(other.onShowListener_); @@ -75,12 +60,10 @@ RendererModule &RendererModule::operator=(RendererModule &&other) noexcept { viewportY_ = other.viewportY_; viewportWidth_ = other.viewportWidth_; viewportHeight_ = other.viewportHeight_; + viewportAdapter_ = std::move(other.viewportAdapter_); + viewProjectionMatrix_ = std::move(other.viewProjectionMatrix_); - // 重置源对象状态 other.commandCount_ = 0; - other.defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE; - other.defaultQuadHandle_ = INVALID_MESH_HANDLE; - other.defaultTextureHandle_ = INVALID_TEXTURE_HANDLE; other.glInitialized_ = false; other.stats_ = {}; other.viewportX_ = 0; @@ -94,16 +77,14 @@ RendererModule &RendererModule::operator=(RendererModule &&other) noexcept { bool RendererModule::init() { E2D_LOG_INFO("Initializing RendererModule..."); - // 绑定事件监听器 onRenderBeginListener_.bind([this]() { onRenderBegin(); }); onRenderSubmitListener_.bind( [this](const RenderCommand &cmd) { onRenderSubmit(cmd); }); onRenderSetCameraListener_.bind( [this](const Mat4 &viewProj) { onRenderSetCamera(viewProj); }); onRenderEndListener_.bind([this]() { onRenderEnd(); }); - onResizeListener_.bind([this](int32_t w, int32_t h) { onResize(w, h); }); + onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); }); - // 延迟 GL 初始化到窗口显示时 onShowListener_.bind([this]() { onWindowShow(); }); E2D_LOG_INFO("RendererModule initialized (waiting for GL context)"); @@ -117,26 +98,17 @@ void RendererModule::onWindowShow() { E2D_LOG_INFO("Initializing OpenGL context..."); - // 初始化 UBO 管理器(需要 GL 上下文) if (!uniformManager_.initialize()) { E2D_LOG_ERROR("Failed to initialize UniformBufferManager"); return; } - // 创建默认资源(需要 GL 上下文) - if (!createDefaultResources()) { - E2D_LOG_ERROR("Failed to create default resources"); - return; - } - - // 获取实际窗口大小并设置视口 - // 查询当前 SDL 窗口大小 int windowWidth = 800, windowHeight = 600; SDL_Window *sdlWindow = SDL_GL_GetCurrentWindow(); if (sdlWindow) { SDL_GetWindowSize(sdlWindow, &windowWidth, &windowHeight); E2D_LOG_INFO("Setting initial viewport to window size: {}x{}", windowWidth, - windowHeight); + windowHeight); } else { E2D_LOG_WARN("Could not get SDL window, using default viewport 800x600"); } @@ -153,85 +125,28 @@ void RendererModule::onWindowShow() { void RendererModule::shutdown() { E2D_LOG_INFO("Shutting down RendererModule..."); - // 只有在 GL 初始化后才销毁 GL 相关资源 if (glInitialized_) { - // 销毁默认资源 - destroyDefaultResources(); - - // 关闭 UBO 管理器 uniformManager_.shutdown(); } - // 清理资源池 - materialPool_.slots.clear(); - while (!materialPool_.freeIndices.empty()) - materialPool_.freeIndices.pop(); - - meshPool_.slots.clear(); - while (!meshPool_.freeIndices.empty()) - meshPool_.freeIndices.pop(); - - texturePool_.slots.clear(); - while (!texturePool_.freeIndices.empty()) - texturePool_.freeIndices.pop(); - glInitialized_ = false; E2D_LOG_INFO("RendererModule shutdown complete"); } -MaterialHandle RendererModule::registerMaterial(Ptr material) { - uint64_t handle = materialPool_.acquire(); - auto *slot = materialPool_.get(handle); - if (slot) { - slot->material = material; - } - return handle; +MaterialHandle RendererModule::getDefaultMaterialHandle() const { + auto* assets = getAssets(); + return assets ? assets->getDefaultMaterial() : MaterialHandle::invalid(); } -MeshHandle RendererModule::registerMesh(Ptr mesh) { - uint64_t handle = meshPool_.acquire(); - auto *slot = meshPool_.get(handle); - if (slot) { - slot->mesh = mesh; - } - return handle; +MeshHandle RendererModule::getDefaultQuadHandle() const { + auto* assets = getAssets(); + return assets ? assets->getDefaultQuad() : MeshHandle::invalid(); } -TextureHandle RendererModule::registerTexture(Ptr texture) { - uint64_t handle = texturePool_.acquire(); - auto *slot = texturePool_.get(handle); - if (slot) { - slot->texture = texture; - } - return handle; -} - -void RendererModule::unregisterMaterial(MaterialHandle handle) { - materialPool_.release(handle); -} - -void RendererModule::unregisterMesh(MeshHandle handle) { - meshPool_.release(handle); -} - -void RendererModule::unregisterTexture(TextureHandle handle) { - texturePool_.release(handle); -} - -Ptr RendererModule::getMaterial(MaterialHandle handle) { - auto *slot = materialPool_.get(handle); - return slot ? slot->material : nullptr; -} - -Ptr RendererModule::getMesh(MeshHandle handle) { - auto *slot = meshPool_.get(handle); - return slot ? slot->mesh : nullptr; -} - -Ptr RendererModule::getTexture(TextureHandle handle) { - auto *slot = texturePool_.get(handle); - return slot ? slot->texture : nullptr; +TextureHandle RendererModule::getDefaultTextureHandle() const { + auto* assets = getAssets(); + return assets ? assets->getDefaultTexture() : TextureHandle::invalid(); } void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) { @@ -240,10 +155,8 @@ void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) { viewportWidth_ = width; viewportHeight_ = height; - // 更新视口适配器 viewportAdapter_.update(width, height); - // 获取适配后的视口 auto result = viewportAdapter_.getResult(); glViewport(static_cast(result.viewport.x), static_cast(result.viewport.y), @@ -251,7 +164,7 @@ void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) { static_cast(result.viewport.h)); } -void RendererModule::clear(const Color &color, uint32_t flags) { +void RendererModule::clear(const Color &color, uint32 flags) { GLbitfield mask = 0; if (flags & CLEAR_COLOR_FLAG) { @@ -273,68 +186,53 @@ void RendererModule::clear(const Color &color, uint32_t flags) { } void RendererModule::onRenderBegin() { - // 如果 GL 未初始化,跳过渲染 if (!glInitialized_) { return; } - // 清除屏幕(黑色背景) glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - // 清空命令缓冲区 commandCount_ = 0; - // 重置统计 stats_ = {}; - // 重置 UBO 管理器 uniformManager_.resetMaterialUBOs(); } void RendererModule::onRenderSubmit(const RenderCommand &cmd) { - // 如果 GL 未初始化,跳过提交 if (!glInitialized_) { return; } - // 检查缓冲区是否已满 if (commandCount_ >= MAX_RENDER_COMMANDS) { E2D_LOG_WARN("Render command buffer full!"); return; } - // 直接存入预分配缓冲区(无动态分配) commandBuffer_[commandCount_++] = cmd; stats_.commandsSubmitted++; } void RendererModule::onRenderSetCamera(const Mat4 &viewProj) { - // 如果 GL 未初始化,跳过 if (!glInitialized_) { return; } - // 保存视图投影矩阵 viewProjectionMatrix_ = viewProj; - // 更新全局 UBO 中的视图投影矩阵 uniformManager_.updateGlobalUBO(&viewProj, sizeof(Mat4)); } void RendererModule::onRenderEnd() { - // 如果 GL 未初始化,跳过渲染 if (!glInitialized_) { return; } - // 排序命令 sortCommands(); - // 批处理并绘制 batchAndDraw(); - // 输出统计 E2D_LOG_DEBUG("Render: {} commands, {} draw calls, {} batches", stats_.commandsExecuted, stats_.drawCalls, stats_.batches); } @@ -344,7 +242,6 @@ void RendererModule::onResize(int32 width, int32 height) { } void RendererModule::sortCommands() { - // 使用 std::sort 对命令进行排序 std::sort(commandBuffer_.begin(), commandBuffer_.begin() + commandCount_, [](const RenderCommand &a, const RenderCommand &b) { return a.sortKey < b.sortKey; @@ -352,8 +249,14 @@ void RendererModule::sortCommands() { } void RendererModule::batchAndDraw() { - MaterialHandle lastMaterial = INVALID_MATERIAL_HANDLE; - MeshHandle lastMesh = INVALID_MESH_HANDLE; + auto* assets = getAssets(); + if (!assets) { + E2D_LOG_ERROR("AssetsModule not available"); + return; + } + + MaterialHandle lastMaterial = MaterialHandle::invalid(); + MeshHandle lastMesh = MeshHandle::invalid(); uint32_t batchStart = 0; uint32_t batchCount = 0; @@ -361,7 +264,6 @@ void RendererModule::batchAndDraw() { const auto &cmd = commandBuffer_[i]; if (cmd.type != RenderCommandType::DrawMesh) { - // 处理非绘制命令 if (batchCount > 0) { drawBatch(batchStart, batchCount, lastMaterial, lastMesh); stats_.batches++; @@ -371,11 +273,9 @@ void RendererModule::batchAndDraw() { continue; } - // 检查是否需要刷新批次 if (cmd.drawMesh.material != lastMaterial || cmd.drawMesh.mesh != lastMesh) { - // 刷新上一批次 if (batchCount > 0) { drawBatch(batchStart, batchCount, lastMaterial, lastMesh); stats_.batches++; @@ -392,7 +292,6 @@ void RendererModule::batchAndDraw() { stats_.commandsExecuted++; } - // 刷新最后一批 if (batchCount > 0) { drawBatch(batchStart, batchCount, lastMaterial, lastMesh); stats_.batches++; @@ -402,79 +301,66 @@ void RendererModule::batchAndDraw() { void RendererModule::drawBatch(uint32_t start, uint32_t count, MaterialHandle materialHandle, MeshHandle meshHandle) { - auto material = getMaterial(materialHandle); - // 如果材质无效,使用默认材质 + auto* assets = getAssets(); + if (!assets) return; + + Material* material = assets->get(materialHandle); if (!material) { - material = getMaterial(defaultMaterialHandle_); + material = assets->getDefaultMaterialPtr(); } - auto mesh = getMesh(meshHandle); - // 如果网格无效,使用默认四边形 + Mesh* mesh = assets->get(meshHandle); if (!mesh) { - mesh = getMesh(defaultQuadHandle_); + mesh = assets->getDefaultQuadPtr(); } if (!material || !mesh) return; - // 获取着色器 - auto shader = material->getShader(); + Shader* shader = material->getShader().get(); if (!shader) return; - // 绑定着色器 shader->bind(); - // 设置视图投影矩阵 shader->setMat4("uViewProjection", glm::value_ptr(viewProjectionMatrix_)); - // 设置材质参数 - // 注意:直接使用默认值,因为材质数据布局可能不匹配 - // tintColor 和 opacity 由着色器默认值处理 shader->setVec4("uTintColor", 1.0f, 1.0f, 1.0f, 1.0f); shader->setFloat("uOpacity", 1.0f); - // 绑定材质中的纹理 const auto &textureSlots = material->getTextures(); bool hasMaterialTexture = false; for (const auto &slot : textureSlots) { - if (slot.handle != INVALID_TEXTURE_HANDLE) { - auto texture = getTexture(slot.handle); + if (slot.handle.isValid()) { + Texture* texture = assets->get(slot.handle); if (texture) { texture->bind(slot.slot); - // 设置采样器 uniform shader->setInt(slot.uniformName, static_cast(slot.slot)); hasMaterialTexture = true; } } } - // 如果材质没有纹理,绑定默认纹理 - if (!hasMaterialTexture && defaultTextureHandle_ != INVALID_TEXTURE_HANDLE) { - auto defaultTexture = getTexture(defaultTextureHandle_); + if (!hasMaterialTexture) { + Texture* defaultTexture = assets->getDefaultTexturePtr(); if (defaultTexture) { defaultTexture->bind(0); shader->setInt("uTexture", 0); } } - // 绑定网格 mesh->bind(); - // 对每个实例单独绘制 for (uint32_t i = 0; i < count; ++i) { Transform transform = commandBuffer_[start + i].getTransform(); float matrix[16]; transform.toMatrix(matrix); - // 设置模型矩阵 shader->setMat4("uModelMatrix", matrix); - // 设置顶点颜色 Color color = commandBuffer_[start + i].getColor(); shader->setVec4("uColor", color.r, color.g, color.b, color.a); - // 绘制 mesh->draw(); stats_.drawCalls++; } @@ -496,59 +382,4 @@ void RendererModule::executeCommand(const RenderCommand &cmd) { } } -bool RendererModule::createDefaultResources() { - // 创建默认着色器 - auto defaultShader = makePtr(); - if (!defaultShader->loadFromFile("shader/default.vert", - "shader/default.frag")) { - E2D_LOG_ERROR("Failed to load default shader"); - return false; - } - - // 创建默认材质布局 - auto defaultLayout = makePtr(); - defaultLayout->addParam("tintColor", MaterialParamType::Color); - defaultLayout->addParam("opacity", MaterialParamType::Float); - defaultLayout->finalize(); - - // 创建默认材质 - auto defaultMaterial = makePtr(); - defaultMaterial->setLayout(defaultLayout); - defaultMaterial->setShader(defaultShader); - defaultMaterial->setColor("tintColor", Color::White); - defaultMaterial->setFloat("opacity", 1.0f); - - defaultMaterialHandle_ = registerMaterial(defaultMaterial); - - // 创建默认四边形 - auto defaultQuad = Mesh::createQuad(Vec2(1.0f, 1.0f)); - defaultQuadHandle_ = registerMesh(defaultQuad); - - // 创建默认纹理(1x1 白色) - auto defaultTexture = makePtr(); - uint8_t whitePixel[4] = {255, 255, 255, 255}; - defaultTexture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8); - defaultTextureHandle_ = registerTexture(defaultTexture); - - E2D_LOG_INFO("Default resources created"); - return true; -} - -void RendererModule::destroyDefaultResources() { - if (defaultMaterialHandle_ != INVALID_MATERIAL_HANDLE) { - unregisterMaterial(defaultMaterialHandle_); - defaultMaterialHandle_ = INVALID_MATERIAL_HANDLE; - } - - if (defaultQuadHandle_ != INVALID_MESH_HANDLE) { - unregisterMesh(defaultQuadHandle_); - defaultQuadHandle_ = INVALID_MESH_HANDLE; - } - - if (defaultTextureHandle_ != INVALID_TEXTURE_HANDLE) { - unregisterTexture(defaultTextureHandle_); - defaultTextureHandle_ = INVALID_TEXTURE_HANDLE; - } -} - } // namespace extra2d diff --git a/src/scene/components/sprite_renderer.cpp b/src/scene/components/sprite_renderer.cpp index 4ba67f6..5ddbf32 100644 --- a/src/scene/components/sprite_renderer.cpp +++ b/src/scene/components/sprite_renderer.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,17 +7,15 @@ namespace extra2d { SpriteRenderer::SpriteRenderer() { - // 默认材质和纹理为无效句柄 - // 渲染时会使用默认材质 } void SpriteRenderer::onAttach(Node *owner) { Component::onAttach(owner); } -void SpriteRenderer::setMaterial(MaterialHandle material) { +void SpriteRenderer::setMaterial(Handle material) { material_ = material; } -void SpriteRenderer::setTexture(TextureHandle texture) { texture_ = texture; } +void SpriteRenderer::setTexture(Handle texture) { texture_ = texture; } void SpriteRenderer::setColor(const Color &color) { color_ = color; } @@ -25,27 +24,21 @@ void SpriteRenderer::render() { return; } - // 获取世界变换(已包含锚点计算) Transform worldTransform = owner_->getWorldTransform(); - // 构建渲染命令 RenderCommand cmd; cmd.type = RenderCommandType::DrawMesh; - // 计算排序键(简单实现:材质ID + 纹理ID) - uint32_t materialId = static_cast(material_ & 0xFFFFFFFF); - uint32_t textureId = static_cast(texture_ & 0xFFFFFFFF); + uint32_t materialId = material_.index(); + uint32_t textureId = texture_.index(); cmd.sortKey = (materialId << 16) | (textureId & 0xFFFF); - // 设置网格(使用默认四边形) - cmd.drawMesh.mesh = INVALID_MESH_HANDLE; // 渲染器会使用默认四边形 - cmd.drawMesh.material = material_; + cmd.drawMesh.mesh = MeshHandle::invalid(); + cmd.drawMesh.material = material_.isValid() ? material_ : MaterialHandle::invalid(); cmd.setTransform(worldTransform); - // 设置顶点颜色 cmd.setColor(color_); - // 提交渲染命令 events::OnRenderSubmit::emit(cmd); }