Compare commits

..

58 Commits
master ... main

Author SHA1 Message Date
ChestnutYueyue e011cea090 style: 调整main.cpp的代码格式和include顺序
- 统一缩进为2个空格
- 调整头文件include顺序
- 移除多余的注释分隔线
2026-03-03 19:41:20 +08:00
ChestnutYueyue d5cb194552 refactor(shader): 移除实例化渲染相关的着色器文件
这些着色器文件用于已废弃的实例化渲染功能,现已被更高效的实现方式取代
2026-03-03 19:37:34 +08:00
ChestnutYueyue 44e0d65f10 feat(assets): 添加资源热重载和智能卸载功能
实现纹理和着色器的热重载功能,支持文件修改后自动重新加载
添加资源引用计数和LRU缓存机制,支持智能卸载长时间未使用的资源
重构文件监控系统,减少重复代码
扩展AssetStorage功能,增加加载状态管理和访问时间追踪
2026-03-03 19:32:23 +08:00
ChestnutYueyue e0b0a7883d refactor(renderer): 移除实例化渲染功能及相关代码
移除不再需要的实例化渲染功能,包括着色器、材质、渲染命令和测试代码
优化实例缓冲区实现,添加脏标记和增量更新功能
2026-03-03 12:18:32 +08:00
ChestnutYueyue 97be1b746a chore: 删除未使用的实例化顶点着色器文件
该着色器文件未被实际使用,为保持代码库整洁故移除
2026-03-03 11:42:13 +08:00
ChestnutYueyue 717112c437 perf(渲染): 优化渲染性能并添加统计功能
- 实现全局UBO双缓冲机制减少CPU-GPU等待
- 添加渲染统计功能,每60帧输出一次性能数据
- 优化命令列表状态缓存减少冗余OpenGL调用
- 改进材质UBO管理,支持批量更新和CPU缓冲区
- 重构命令队列执行逻辑,支持双缓冲和统计收集
2026-03-03 11:25:43 +08:00
ChestnutYueyue ec6ced9db2 refactor(模块系统): 调整模块初始化优先级并重构文件加载逻辑
重构模块初始化顺序,确保文件模块优先加载
移除Shader类中直接文件操作,统一通过FileModule进行文件访问
添加FileModule实现跨平台文件系统操作,支持RomFS
重构资源加载逻辑,统一使用FileModule进行文件操作
2026-03-03 05:53:40 +08:00
ChestnutYueyue 8cd883ede7 feat(着色器): 添加默认和实例化着色器到场景图示例
添加默认和实例化着色器文件到场景图示例,包括顶点和片段着色器
修改构建脚本自动复制着色器文件到romfs目录
2026-03-03 03:57:19 +08:00
ChestnutYueyue 91e3e8fe57 feat(渲染): 实现实例化渲染功能并优化渲染管线
- 添加实例化渲染支持,包括InstanceBuffer、InstanceBufferManager和相关着色器
- 重构渲染命令队列以支持实例化绘制
- 优化材质系统,使用vector保持参数顺序并添加快速查找
- 改进顶点布局系统,支持实例属性
- 添加全局UBO管理,优化uniform数据传递
- 实现新的实例化测试场景节点
- 更新着色器以支持实例化渲染和UBO
- 改进GL命令列表,支持实例属性绑定
- 添加AssetsModule对实例化资源的支持
- 修复Director在没有主相机时的警告日志
2026-03-03 03:48:55 +08:00
ChestnutYueyue 9041833430 refactor(rhi): 重构渲染硬件接口模块
feat(rhi): 新增RHI模块抽象层
feat(opengl): 实现OpenGL后端支持
refactor(renderer): 重构材质、纹理和网格类以使用RHI接口
refactor(scene): 移除移动构造函数并禁止移动操作
fix(shader): 修复默认片段着色器纹理采样问题
refactor(module): 改进模块注册表以支持实例存储
refactor(window): 移除OpenGL上下文管理交由RHI处理
feat(assets): 为默认材质添加纹理支持
refactor(timer): 移除移动操作并简化实现
refactor(input): 移除移动操作并简化实现
2026-03-03 02:16:29 +08:00
ChestnutYueyue b4a3d6b14b refactor(assets): 移除未使用的chrono头文件 2026-03-02 22:58:03 +08:00
ChestnutYueyue d387532738 refactor(renderer): 移除冗余的<vector>头文件引入
清理不再需要的<vector>头文件,保持头文件简洁性
2026-03-02 22:57:00 +08:00
ChestnutYueyue f7e4f89cca feat(assets): 实现资源热重载和异步加载系统
添加资源热重载功能,支持监控文件变更并自动重新加载
实现异步加载系统,支持多线程资源加载和回调处理
增加资源依赖跟踪机制,自动更新依赖材质的引用
使用读写锁保护资源存储,提升多线程访问性能
2026-03-02 22:54:06 +08:00
ChestnutYueyue 46ec1c665f refactor(assets): 重构资源管理系统为ECS风格
- 引入新的Handle<T>轻量级资源句柄,替代原有的uint64_t句柄
- 新增AssetStorage类实现密集存储管理
- 添加AssetsModule模块统一管理资源加载和生命周期
- 实现TextureLoader和ShaderLoader资源加载器
- 重构RendererModule移除资源管理职责,改为使用AssetsModule
- 更新SpriteRenderer和相关组件使用新Handle接口
- 修改RenderTypes.h中的资源句柄类型定义
2026-03-02 22:44:42 +08:00
ChestnutYueyue 3b827149ba refactor(renderer): 清理代码并优化结构
- 移除renderer_module.cpp中注释掉的代码
- 重新组织director.cpp的代码格式和结构
- 简化shader.cpp的日志输出和代码格式
- 添加glad头文件包含
2026-03-02 04:57:44 +08:00
ChestnutYueyue 92be7d9d18 feat(场景图系统): 实现完整的场景图模块和示例程序
新增场景图系统核心组件:
- Director 场景管理
- Scene 场景容器
- Node 节点层级
- Component 组件系统
- Transform 变换(含锚点)
- Camera 相机
- SpriteRenderer 精灵渲染

添加场景图示例程序,演示:
- 节点层级和变换继承
- 组件系统使用
- 相机设置
- 精灵渲染

同时优化了渲染系统:
- 修改渲染命令结构
- 添加视口适配器
- 改进着色器错误处理
- 增强材质系统功能
2026-03-02 04:50:28 +08:00
ChestnutYueyue b4be0d84f8 feat(渲染器): 实现核心渲染系统模块
添加渲染器模块及相关组件,包括材质、网格、纹理、着色器和统一缓冲区管理。主要变更包括:

- 新增渲染器模块,负责接收渲染命令、批处理和排序
- 实现材质系统支持参数和着色器管理
- 添加网格类管理顶点和索引数据
- 实现纹理加载和绑定功能
- 添加着色器编译和链接功能
- 实现统一缓冲区对象(UBO)管理系统
- 提供默认资源(材质、网格、纹理)
- 支持实例化渲染和命令批处理
- 添加渲染事件系统(OnRenderBegin/Submit/End)
- 完善资源句柄管理机制
- 优化GL资源初始化和清理流程

移除不再使用的IModule接口,调整窗口模块事件触发时机确保GL上下文安全
2026-03-02 00:25:14 +08:00
ChestnutYueyue 46393fd027 refactor(resource): 移除资源系统相关代码
移除资源管理器及其相关组件,包括纹理、着色器、材质、字体、音频等资源类
删除资源加载示例及其构建配置
清理引擎上下文中与资源管理相关的接口和实现
2026-03-01 23:21:54 +08:00
ChestnutYueyue bbdc1435ce refactor(tests): 移除测试套件及相关配置
移除整个tests目录及其内容,包括测试代码、构建脚本和文档
同时更新xmake.lua移除测试套件配置
重构src/resource/material.cpp代码格式
2026-03-01 22:53:28 +08:00
ChestnutYueyue bdf78f5eca feat(resource): 实现资源管理系统及示例程序
新增资源管理系统,支持纹理、字体、着色器、音频等资源的加载和管理:
- 添加 ResourceManager 核心模块
- 实现 Texture、Font、Shader、Audio 等资源类
- 添加 FontAtlas 动态字符图集管理
- 实现 Material 材质系统
- 添加 Text 文本渲染支持
- 新增资源加载示例程序
- 更新构建系统以支持资源加载示例
- 完善文档和 README
2026-03-01 15:39:07 +08:00
ChestnutYueyue 6717015e28 feat(switch): 添加 Nintendo Switch 平台支持
- 添加 Switch 平台专用的日志输出和初始化处理
- 修改窗口模块以支持 OpenGL ES 3.2 渲染
- 更新构建系统以支持 Switch 平台编译
- 添加 Switch 平台文件系统操作支持
- 移除 Vulkan 相关依赖,改用 OpenGL ES
- 更新插件加载器以适配 Switch 平台限制
2026-03-01 03:48:51 +08:00
ChestnutYueyue fb11f2a71e refactor(渲染): 迁移OpenGL到Vulkan并重构相关模块
- 移除OpenGL相关代码和依赖,添加Vulkan SDK支持
- 重构窗口模块为Vulkan实现,移除GL上下文和VSync相关功能
- 简化配置结构,移除不再需要的OpenGL版本设置
- 重构上下文模块,使用单例模块注册表
- 移动定时器模块到utils目录并优化实现
- 清理废弃代码和头文件引用
2026-03-01 00:01:48 +08:00
ChestnutYueyue f9be301dae refactor(引擎核心): 重构模块系统并引入自动注册机制
重构引擎核心模块系统,使用新的 Module 基类替代旧版 IModule 接口
新增模块自动注册机制,通过 E2D_REGISTER_MODULE 宏实现模块注册
将窗口、文件、定时器等模块迁移到新系统,支持配置事件驱动初始化
移除旧版 SDL2 封装和模块管理器,简化应用程序初始化流程
2026-02-28 23:35:34 +08:00
ChestnutYueyue ebf73a4492 feat: 添加窗口和输入模块支持并简化示例程序
重构应用类以支持窗口和输入模块,添加相关接口方法
移除碰撞演示示例,简化hello world示例为控制台输出
启用控制台子系统以便在mingw平台查看输出
2026-02-28 22:30:48 +08:00
ChestnutYueyue 418d2c8f92 feat(tests): 添加完整的测试套件框架和核心模块测试
refactor(module): 改进模块注册表同名模块处理逻辑
refactor(plugin): 优化插件加载器依赖检查机制
refactor(event): 重构事件总线监听器添加顺序逻辑

build: 添加测试构建选项和配置
docs: 添加测试套件README文档
2026-02-28 21:48:35 +08:00
ChestnutYueyue e68ce87638 refactor(engine): 重构引擎架构,引入模块化系统和事件总线
重构引擎核心架构,移除旧的服务和调度器系统,引入基于事件总线的模块化设计:
1. 新增 Context 类作为引擎核心上下文,管理模块和插件生命周期
2. 新增 IModule 接口和 ModuleRegistry 实现模块注册与管理
3. 新增 IPlugin 接口和 PluginLoader 实现插件动态加载
4. 重构事件系统,扩展触摸和游戏手柄事件
5. 移除 Director、Scheduler 和 Service 等旧系统
6. 重构文件、窗口等平台模块为独立模块
7. 更新应用类以使用新架构
8. 优化随机数生成器为非单例设计
9. 添加详细的模块优先级常量
10. 改进代码组织结构和文档注释

此次重构提高了代码的可维护性和扩展性,支持运行时模块和插件动态加载,为后续功能扩展奠定基础。
2026-02-28 20:56:11 +08:00
ChestnutYueyue 5a3d0cd9de refactor(core): 移除TBB依赖并重构事件系统和调度器
重构服务管理器和调度器,使用标准库替代TBB并发容器
将事件系统从core移动到独立event目录并优化实现
更新构建脚本移除TBB相关配置
添加线程安全队列实现并行调度
2026-02-28 04:44:56 +08:00
ChestnutYueyue 0761b55864 refactor(platform): 移除PlatformType枚举并调整OpenGL配置
移除不再使用的PlatformType枚举及相关平台判断逻辑,简化代码结构。同时将默认OpenGL配置从3.3 Core改为3.2 ES,以支持更多平台。调整了窗口服务初始化方式,使用lambda表达式创建配置对象。
2026-02-27 23:08:49 +08:00
ChestnutYueyue 8abf58e3d5 feat: 添加SDL2平台支持及核心功能模块
实现SDL2平台初始化、窗口管理、输入处理和文件系统服务
重构服务管理机制,支持暂停/恢复状态
添加事件总线系统,实现引擎事件分发
优化应用主循环和更新机制
完善跨平台文件操作接口
2026-02-27 22:59:17 +08:00
ChestnutYueyue 5ef1873a44 refactor(core): 使用全局变量替换Director中的成员变量
将Director类中的Scheduler和SvcMgr成员变量替换为全局变量SCHED和SVC_MGR,
并添加IService的友元声明以允许SvcMgr访问其私有成员
2026-02-27 20:55:06 +08:00
ChestnutYueyue 71eeeac033 refactor(engine): 重构引擎代码结构,优化类型系统和核心模块
- 将核心类型和数学工具移动到types目录下,按功能分类
- 重构引用计数和智能指针实现,提高线程安全性
- 新增调度器和服务管理器,提供统一的更新机制
- 移除旧的输入系统和窗口管理代码
- 优化日志系统,移除冗余代码
- 添加TBB依赖,支持并行任务调度
- 统一代码风格,使用更简洁的命名规范
2026-02-27 20:46:16 +08:00
ChestnutYueyue 3b031666ae build: 添加 TBB 作为第三方子模块
添加 oneTBB 作为子模块以支持并行计算功能,路径为 third_party/tbb
2026-02-27 20:44:17 +08:00
ChestnutYueyue 24b86b4916 refactor: 移除事件系统和音频系统相关代码
移除不再使用的事件队列(EventQueue)、事件分发器(EventDispatcher)、音频引擎(AudioEngine)和声音(Sound)相关代码
删除utils/data.h数据存储模块
清理相关头文件引用和成员变量
2026-02-27 19:25:54 +08:00
ChestnutYueyue ea081b9dd3 refactor: 移除图形渲染和场景管理相关代码
移除不再需要的图形渲染、纹理、字体、场景管理等模块代码,清理相关头文件引用。主要变更包括:
- 删除renderer、graphics、scene目录下的大部分文件
- 清理extra2d.h中的冗余头文件引用
- 简化Application类,移除渲染和场景管理相关功能
2026-02-27 19:12:24 +08:00
ChestnutYueyue d81f0c1e45 refactor(graphics): 移除纹理图集功能及相关实现代码 2026-02-27 18:52:24 +08:00
ChestnutYueyue b4a55239aa refactor(core): 替换shared_ptr为侵入式引用计数IntrusivePtr
重构整个项目,将std::shared_ptr替换为自定义的IntrusivePtr实现:
1. 新增RefCounted基类,提供引用计数功能
2. 实现IntrusivePtr智能指针模板类
3. 修改所有资源管理类使用IntrusivePtr
4. 更新Node类继承自RefCounted
5. 移除types.h中的shared_ptr相关定义
6. 统一使用makeRef替代shared创建对象
2026-02-26 21:17:11 +08:00
ChestnutYueyue 4afd52cc82 refactor: 移除自定义字符串模块并改用标准库
移除core/string.h和core/string.cpp,使用标准库<string>替代
删除renderer/shader.h及相关实现文件
在需要UTF-8转换的地方添加简化版实现
更新相关头文件的包含关系
2026-02-26 20:21:55 +08:00
ChestnutYueyue 60ef7ab63f refactor(ui): 移除UI组件及相关功能代码
移除所有UI组件代码,包括按钮、复选框、单选框、进度条、滑动条、标签、文本和基础Widget类
删除对象池预热功能及相关代码
清理UI组件相关的头文件引用
2026-02-26 20:16:46 +08:00
ChestnutYueyue c84aab70ed refactor(renderer): 重构着色器系统并优化渲染命令结构
- 将 shader_system.h 重命名为 shader.h 并合并相关实现
- 移除 shader_preset.h 和 shader_preset.cpp 文件
- 优化 render_command.h 中的代码格式和结构
- 清理不必要的头文件包含
2026-02-26 20:12:12 +08:00
ChestnutYueyue 00d709fcc8 refactor: 统一智能指针创建函数命名
将 makePtr 和 makeUnique 分别重命名为 shared 和 unique,以提供更简洁的智能指针创建接口
2026-02-26 20:08:04 +08:00
ChestnutYueyue aec444f2b5 refactor(core): 重构数学模块,拆分为多个独立头文件
将 math_types.h 拆分为 vec2.h, vec3.h, rect.h, size.h 和 transform.h
移除 ColorConstants 结构体,直接使用 Colors 命名空间
优化颜色结构体的运算符实现
2026-02-26 20:06:51 +08:00
ChestnutYueyue e52c117830 refactor(renderer): 重构渲染器模块结构
将渲染器相关代码从graphics目录移动到renderer目录,包括Camera、Renderer等核心类
删除过渡动画相关代码,简化场景切换逻辑
移除Tween动画系统,减少代码复杂度
重命名ShapeNode为Shape,保持命名一致性
更新所有引用路径以反映新的目录结构
2026-02-26 19:57:16 +08:00
ChestnutYueyue f41600306e refactor: 移除空间索引系统及相关示例代码
移除空间索引系统(QuadTree/SpatialHash)及相关实现代码
删除push_box和flappy_bird示例游戏及其资源文件
清理不再需要的空间索引相关函数调用和头文件引用
2026-02-26 19:41:57 +08:00
ChestnutYueyue 98bca638d0 refactor(platform): 将 input_codes.h 从 event 移动到 platform 目录
将输入相关的代码定义文件从 event 目录移动到更合适的 platform 目录
2026-02-26 19:35:20 +08:00
ChestnutYueyue 353a222c62 refactor(graphics): 重命名 render_backend 为 renderer 以统一命名
将渲染后端接口文件 render_backend.h 重命名为 renderer.h,并更新所有相关引用。这一修改旨在使命名更加清晰统一,renderer 更能准确描述该接口的职责。
2026-02-26 01:00:58 +08:00
ChestnutYueyue 7b1e1299e0 refactor(渲染系统): 重命名 RenderBackend 为 Renderer 并统一相关接口命名
将渲染后端基类从 RenderBackend 重命名为 Renderer,使其更简洁直观
更新所有相关派生类和接口引用,保持命名一致性
修改渲染器相关方法参数类型为 Renderer&
调整部分成员函数命名风格,如 getWidth()/getHeight() 改为 width()/height()
更新文档和注释中的渲染后端相关描述
2026-02-26 00:59:16 +08:00
ChestnutYueyue bd3cebf0b5 chore: 删除过时文档文件
移除不再使用的Extra2D构建系统文档和API教程文件,包括快速开始、场景系统、节点系统、输入处理、碰撞检测、音频系统和动作系统等过时内容
2026-02-26 00:55:35 +08:00
ChestnutYueyue ea5ecd383f refactor: 统一边界框方法名称为 boundingBox
将 getBoundingBox 方法重命名为 boundingBox,以遵循更简洁的命名规范
同时更新相关文档和示例代码中的调用
2026-02-26 00:55:13 +08:00
ChestnutYueyue 377ec373b0 refactor: 统一方法命名风格,使用更简洁的getter命名
将get前缀的getter方法统一改为更简洁的属性风格命名,例如getPosition()改为pos(),getRotation()改为rot()等,提升代码一致性和可读性

- 修改Window、Sound、Tween、Sprite等类的方法命名
- 更新所有调用点以适应新的命名风格
- 保持原有功能不变,仅重构命名
2026-02-26 00:38:31 +08:00
ChestnutYueyue 0f520c8e37 fix(ui): 修正按钮边界矩形计算使用错误的位置
使用convertToWorldSpace替代getRenderPosition来正确计算边界矩形,确保在不同坐标系转换下边界计算准确
2026-02-26 00:15:45 +08:00
ChestnutYueyue fa9ee0e2a7 refactor(ui): 移除坐标空间系统并简化文本组件位置处理
移除 CoordinateSpace 枚举及相关功能,改为使用统一的位置处理方式
更新示例代码以使用新的位置设置方法
2026-02-26 00:12:54 +08:00
ChestnutYueyue a6c1f66fff refactor(animation): 移除旧动画系统并添加Tween动画支持
重构动画系统,删除旧动画组件(AnimationClip, AnimatedSprite等),添加新的Tween动画系统。主要变更包括:
1. 删除旧的动画相关文件(animation_clip, animation_frame等)
2. 实现新的Tween动画系统,支持多种缓动函数
3. 更新flappy_bird示例使用新的Tween系统
4. 调整include路径和xmake配置
5. 添加输入系统对控制器和鼠标滚轮的支持
2026-02-25 21:22:35 +08:00
ChestnutYueyue 5039b1d9fc refactor: 重构项目结构,优化代码组织与文件布局
将源代码从Extra2D/src迁移到src目录,统一文件路径
更新xmake构建配置以适配新路径
清理冗余代码文件,合并重复实现
调整头文件包含路径,确保编译通过
优化过渡动画场景实现,移除不必要的动画效果
2026-02-25 06:46:13 +08:00
ChestnutYueyue f9c8f080eb refactor(效果系统): 移除效果相关代码
移除后处理、粒子系统和自定义效果管理器的头文件和实现文件
删除extra2d.h中对效果模块的包含
2026-02-25 06:27:58 +08:00
ChestnutYueyue f08a0bf583 refactor: 统一头文件引用路径并重构项目结构
重构头文件引用路径,移除冗余的extra2d前缀
更新xmake构建配置以反映新的头文件组织方式
添加缺失的核心模块头文件定义
2026-02-25 06:23:53 +08:00
ChestnutYueyue 97220e9417 refactor: 更新json库引用路径为nlohmann/json
统一将项目中所有json/json.hpp引用改为nlohmann/json.hpp,并清理不再需要的头文件路径配置
2026-02-25 06:08:58 +08:00
ChestnutYueyue a2b142eb99 refactor(engine): 重构第三方库引用路径
将glad和stb库从Extra2D目录移动到third_party目录,并更新相关引用路径
添加nlohmann和simpleini第三方库的头文件路径
2026-02-25 06:05:34 +08:00
ChestnutYueyue 7c7d9cca92 chore: 从.gitignore中移除third_party目录
不再需要忽略third_party目录,因此将其从.gitignore文件中删除
2026-02-25 06:05:24 +08:00
310 changed files with 46708 additions and 40803 deletions

View File

@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(git diff:*)"
]
}
}

1
.gitignore vendored
View File

@ -71,7 +71,6 @@ cmake-build-*/
# --------------------------------------------
/packages/
/deps/
/third_party/
/vendor/
# --------------------------------------------

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "third_party/tbb"]
path = third_party/tbb
url = https://github.com/oneapi-src/oneTBB.git

View File

@ -1,136 +0,0 @@
#pragma once
#include <extra2d/core/module.h>
#include <extra2d/core/registry.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/core/types.h>
#include <string>
namespace extra2d {
class IWindow;
class IInput;
class RenderBackend;
class WindowModule;
class RenderModule;
class InputModule;
/**
* @brief
*/
class Application {
public:
static Application &get();
Application(const Application &) = delete;
Application &operator=(const Application &) = delete;
/**
* @brief
*/
std::string appName = "Extra2D App";
std::string appVersion = "1.0.0";
std::string organization = "";
/**
* @brief
* @tparam T
* @tparam Args
* @return
*/
template <typename T, typename... Args> T *use(Args &&...args) {
return Registry::instance().use<T>(std::forward<Args>(args)...);
}
/**
* @brief
* @tparam T
* @return
*/
template <typename T> T *get() const { return Registry::instance().get<T>(); }
/**
* @brief
* @return true
*/
bool init();
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
void run();
/**
* @brief 退
*/
void quit();
/**
* @brief
*/
void pause();
/**
* @brief
*/
void resume();
bool isPaused() const { return paused_; }
bool isRunning() const { return running_; }
/**
* @brief
* @return
*/
IWindow *window();
/**
* @brief
* @return
*/
RenderBackend *renderer();
/**
* @brief
* @return
*/
IInput *input();
/**
* @brief
* @param scene
*/
void enterScene(Ptr<class Scene> scene);
float deltaTime() const { return deltaTime_; }
float totalTime() const { return totalTime_; }
int fps() const { return currentFps_; }
private:
Application();
~Application();
void mainLoop();
void update();
void render();
void configureCameraService();
bool initialized_ = false;
bool running_ = false;
bool paused_ = false;
bool shouldQuit_ = false;
float deltaTime_ = 0.0f;
float totalTime_ = 0.0f;
double lastFrameTime_ = 0.0;
int frameCount_ = 0;
float fpsTimer_ = 0.0f;
int currentFps_ = 0;
};
} // namespace extra2d

View File

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

View File

@ -1,550 +0,0 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <extra2d/core/types.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
namespace extra2d {
// ---------------------------------------------------------------------------
// 常量
// ---------------------------------------------------------------------------
constexpr float PI_F = 3.14159265358979323846f;
constexpr float DEG_TO_RAD = PI_F / 180.0f;
constexpr float RAD_TO_DEG = 180.0f / PI_F;
// ---------------------------------------------------------------------------
// 2D 向量
// ---------------------------------------------------------------------------
struct Vec2 {
float x = 0.0f;
float y = 0.0f;
constexpr Vec2() = default;
constexpr Vec2(float x, float y) : x(x), y(y) {}
explicit Vec2(const glm::vec2 &v) : x(v.x), y(v.y) {}
glm::vec2 toGlm() const { return {x, y}; }
static Vec2 fromGlm(const glm::vec2 &v) { return {v.x, v.y}; }
// 基础运算
Vec2 operator+(const Vec2 &v) const { return {x + v.x, y + v.y}; }
Vec2 operator-(const Vec2 &v) const { return {x - v.x, y - v.y}; }
Vec2 operator*(float s) const { return {x * s, y * s}; }
Vec2 operator/(float s) const { return {x / s, y / s}; }
Vec2 operator-() const { return {-x, -y}; }
Vec2 &operator+=(const Vec2 &v) {
x += v.x;
y += v.y;
return *this;
}
Vec2 &operator-=(const Vec2 &v) {
x -= v.x;
y -= v.y;
return *this;
}
Vec2 &operator*=(float s) {
x *= s;
y *= s;
return *this;
}
Vec2 &operator/=(float s) {
x /= s;
y /= s;
return *this;
}
bool operator==(const Vec2 &v) const { return x == v.x && y == v.y; }
bool operator!=(const Vec2 &v) const { return !(*this == v); }
// 向量运算
float length() const { return std::sqrt(x * x + y * y); }
float lengthSquared() const { return x * x + y * y; }
Vec2 normalized() const {
float len = length();
if (len > 0.0f)
return {x / len, y / len};
return {0.0f, 0.0f};
}
float dot(const Vec2 &v) const { return x * v.x + y * v.y; }
float cross(const Vec2 &v) const { return x * v.y - y * v.x; }
float distance(const Vec2 &v) const { return (*this - v).length(); }
float angle() const { return std::atan2(y, x) * RAD_TO_DEG; }
static Vec2 lerp(const Vec2 &a, const Vec2 &b, float t) {
return a + (b - a) * t;
}
static constexpr Vec2 Zero() { return {0.0f, 0.0f}; }
static constexpr Vec2 One() { return {1.0f, 1.0f}; }
static constexpr Vec2 UnitX() { return {1.0f, 0.0f}; }
static constexpr Vec2 UnitY() { return {0.0f, 1.0f}; }
};
inline Vec2 operator*(float s, const Vec2 &v) { return v * s; }
using Point = Vec2;
// ---------------------------------------------------------------------------
// 3D 向量 (用于3D动作)
// ---------------------------------------------------------------------------
struct Vec3 {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
constexpr Vec3() = default;
constexpr Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
explicit Vec3(const glm::vec3 &v) : x(v.x), y(v.y), z(v.z) {}
glm::vec3 toGlm() const { return {x, y, z}; }
static Vec3 fromGlm(const glm::vec3 &v) { return {v.x, v.y, v.z}; }
Vec3 operator+(const Vec3 &v) const { return {x + v.x, y + v.y, z + v.z}; }
Vec3 operator-(const Vec3 &v) const { return {x - v.x, y - v.y, z - v.z}; }
Vec3 operator*(float s) const { return {x * s, y * s, z * s}; }
Vec3 operator/(float s) const { return {x / s, y / s, z / s}; }
Vec3 operator-() const { return {-x, -y, -z}; }
Vec3 &operator+=(const Vec3 &v) {
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vec3 &operator-=(const Vec3 &v) {
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vec3 &operator*=(float s) {
x *= s;
y *= s;
z *= s;
return *this;
}
Vec3 &operator/=(float s) {
x /= s;
y /= s;
z /= s;
return *this;
}
bool operator==(const Vec3 &v) const {
return x == v.x && y == v.y && z == v.z;
}
bool operator!=(const Vec3 &v) const { return !(*this == v); }
float length() const { return std::sqrt(x * x + y * y + z * z); }
float lengthSquared() const { return x * x + y * y + z * z; }
Vec3 normalized() const {
float len = length();
if (len > 0.0f)
return {x / len, y / len, z / len};
return {0.0f, 0.0f, 0.0f};
}
float dot(const Vec3 &v) const { return x * v.x + y * v.y + z * v.z; }
static Vec3 lerp(const Vec3 &a, const Vec3 &b, float t) {
return a + (b - a) * t;
}
static constexpr Vec3 Zero() { return {0.0f, 0.0f, 0.0f}; }
static constexpr Vec3 One() { return {1.0f, 1.0f, 1.0f}; }
};
inline Vec3 operator*(float s, const Vec3 &v) { return v * s; }
// ---------------------------------------------------------------------------
// 2D 尺寸
// ---------------------------------------------------------------------------
struct Size {
float width = 0.0f;
float height = 0.0f;
constexpr Size() = default;
constexpr Size(float w, float h) : width(w), height(h) {}
bool operator==(const Size &s) const {
return width == s.width && height == s.height;
}
bool operator!=(const Size &s) const { return !(*this == s); }
float area() const { return width * height; }
bool empty() const { return width <= 0.0f || height <= 0.0f; }
static constexpr Size Zero() { return {0.0f, 0.0f}; }
};
// ---------------------------------------------------------------------------
// 2D 矩形
// ---------------------------------------------------------------------------
struct Rect {
Point origin;
Size size;
constexpr Rect() = default;
constexpr Rect(float x, float y, float w, float h)
: origin(x, y), size(w, h) {}
constexpr Rect(const Point &o, const Size &s) : origin(o), size(s) {}
float left() const { return origin.x; }
float top() const { return origin.y; }
float right() const { return origin.x + size.width; }
float bottom() const { return origin.y + size.height; }
float width() const { return size.width; }
float height() const { return size.height; }
Point center() const {
return {origin.x + size.width * 0.5f, origin.y + size.height * 0.5f};
}
bool empty() const { return size.empty(); }
bool containsPoint(const Point &p) const {
return p.x >= left() && p.x <= right() && p.y >= top() && p.y <= bottom();
}
bool contains(const Rect &r) const {
return r.left() >= left() && r.right() <= right() && r.top() >= top() &&
r.bottom() <= bottom();
}
bool intersects(const Rect &r) const {
return !(left() > r.right() || right() < r.left() || top() > r.bottom() ||
bottom() < r.top());
}
Rect intersection(const Rect &r) const {
float l = std::max(left(), r.left());
float t = std::max(top(), r.top());
float ri = std::min(right(), r.right());
float b = std::min(bottom(), r.bottom());
if (l < ri && t < b)
return {l, t, ri - l, b - t};
return {};
}
Rect unionWith(const Rect &r) const {
if (empty())
return r;
if (r.empty())
return *this;
float l = std::min(left(), r.left());
float t = std::min(top(), r.top());
float ri = std::max(right(), r.right());
float b = std::max(bottom(), r.bottom());
return {l, t, ri - l, b - t};
}
bool operator==(const Rect &r) const {
return origin == r.origin && size == r.size;
}
bool operator!=(const Rect &r) const { return !(*this == r); }
static constexpr Rect Zero() { return {0, 0, 0, 0}; }
};
// ---------------------------------------------------------------------------
// 2D 变换矩阵(基于 glm::mat4兼容 OpenGL
// ---------------------------------------------------------------------------
struct Transform2D {
glm::mat4 matrix{1.0f}; // 单位矩阵
Transform2D() = default;
explicit Transform2D(const glm::mat4 &m) : matrix(m) {}
static Transform2D identity() { return Transform2D{}; }
static Transform2D translation(float x, float y) {
Transform2D t;
t.matrix = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, 0.0f));
return t;
}
static Transform2D translation(const Vec2 &v) {
return translation(v.x, v.y);
}
static Transform2D rotation(float degrees) {
Transform2D t;
t.matrix = glm::rotate(glm::mat4(1.0f), degrees * DEG_TO_RAD,
glm::vec3(0.0f, 0.0f, 1.0f));
return t;
}
static Transform2D scaling(float sx, float sy) {
Transform2D t;
t.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(sx, sy, 1.0f));
return t;
}
static Transform2D scaling(float s) { return scaling(s, s); }
static Transform2D skewing(float skewX, float skewY) {
Transform2D t;
t.matrix = glm::mat4(1.0f);
t.matrix[1][0] = std::tan(skewX * DEG_TO_RAD);
t.matrix[0][1] = std::tan(skewY * DEG_TO_RAD);
return t;
}
Transform2D operator*(const Transform2D &other) const {
return Transform2D(matrix * other.matrix);
}
Transform2D &operator*=(const Transform2D &other) {
matrix *= other.matrix;
return *this;
}
Vec2 transformPoint(const Vec2 &p) const {
glm::vec4 result = matrix * glm::vec4(p.x, p.y, 0.0f, 1.0f);
return {result.x, result.y};
}
Transform2D inverse() const { return Transform2D(glm::inverse(matrix)); }
};
// ---------------------------------------------------------------------------
// 数学工具函数
// ---------------------------------------------------------------------------
namespace math {
inline float clamp(float value, float minVal, float maxVal) {
return std::clamp(value, minVal, maxVal);
}
inline float lerp(float a, float b, float t) { return a + (b - a) * t; }
inline float degrees(float radians) { return radians * RAD_TO_DEG; }
inline float radians(float degrees) { return degrees * DEG_TO_RAD; }
// ---------------------------------------------------------------------------
// 角度工具函数
// ---------------------------------------------------------------------------
/**
* @brief [0, 360)
* @param degrees
* @return [0, 360)
*/
inline float normalizeAngle360(float degrees) {
degrees = std::fmod(degrees, 360.0f);
if (degrees < 0.0f) {
degrees += 360.0f;
}
return degrees;
}
/**
* @brief [-180, 180)
* @param degrees
* @return [-180, 180)
*/
inline float normalizeAngle180(float degrees) {
degrees = std::fmod(degrees + 180.0f, 360.0f);
if (degrees < 0.0f) {
degrees += 360.0f;
}
return degrees - 180.0f;
}
/**
* @brief
* @param from
* @param to
* @return from to [-180, 180]
*/
inline float angleDifference(float from, float to) {
float diff = normalizeAngle360(to - from);
if (diff > 180.0f) {
diff -= 360.0f;
}
return diff;
}
/**
* @brief 线
* @param from
* @param to
* @param t [0, 1]
* @return
*/
inline float lerpAngle(float from, float to, float t) {
return from + angleDifference(from, to) * t;
}
// ---------------------------------------------------------------------------
// 向量工具函数
// ---------------------------------------------------------------------------
/**
* @brief from to
* @param from
* @param to
* @return
*/
inline Vec2 direction(const Vec2 &from, const Vec2 &to) {
return (to - from).normalized();
}
/**
* @brief
* @param from
* @param to
* @return [-180, 180]
*/
inline float angleBetween(const Vec2 &from, const Vec2 &to) {
Vec2 dir = to - from;
return std::atan2(dir.y, dir.x) * RAD_TO_DEG;
}
/**
* @brief
* @param degrees 0
* @return
*/
inline Vec2 angleToVector(float degrees) {
float rad = degrees * DEG_TO_RAD;
return {std::cos(rad), std::sin(rad)};
}
/**
* @brief
* @param v
* @param degrees
* @return
*/
inline Vec2 rotateVector(const Vec2 &v, float degrees) {
float rad = degrees * DEG_TO_RAD;
float cosA = std::cos(rad);
float sinA = std::sin(rad);
return {v.x * cosA - v.y * sinA, v.x * sinA + v.y * cosA};
}
// ---------------------------------------------------------------------------
// 坐标系转换工具
// ---------------------------------------------------------------------------
/**
* @brief Y轴向上坐标转Y轴向下坐标
* @param pos Y轴向上坐标系中的位置
* @param height /
* @return Y轴向下坐标系中的位置
*/
inline Vec2 flipY(const Vec2 &pos, float height) {
return {pos.x, height - pos.y};
}
/**
* @brief Y轴向下坐标转Y轴向上坐标
* @param pos Y轴向下坐标系中的位置
* @param height /
* @return Y轴向上坐标系中的位置
*/
inline Vec2 unflipY(const Vec2 &pos, float height) {
return {pos.x, height - pos.y};
}
// ---------------------------------------------------------------------------
// 矩阵工具函数
// ---------------------------------------------------------------------------
/**
* @brief
* @param matrix 4x4变换矩阵
* @return
*/
inline Vec2 extractPosition(const glm::mat4 &matrix) {
return {matrix[3][0], matrix[3][1]};
}
/**
* @brief
* @param matrix 4x4变换矩阵
* @return
*/
inline Vec2 extractScale(const glm::mat4 &matrix) {
float scaleX = std::sqrt(matrix[0][0] * matrix[0][0] + matrix[0][1] * matrix[0][1]);
float scaleY = std::sqrt(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1]);
return {scaleX, scaleY};
}
/**
* @brief
* @param matrix 4x4变换矩阵
* @return
*/
inline float extractRotation(const glm::mat4 &matrix) {
return std::atan2(matrix[0][1], matrix[0][0]) * RAD_TO_DEG;
}
// ---------------------------------------------------------------------------
// 碰撞检测工具
// ---------------------------------------------------------------------------
/**
* @brief
* @param point
* @param rect
* @return true false
*/
inline bool pointInRect(const Vec2 &point, const Rect &rect) {
return point.x >= rect.left() && point.x <= rect.right() &&
point.y >= rect.top() && point.y <= rect.bottom();
}
/**
* @brief
* @param point
* @param center
* @param radius
* @return true false
*/
inline bool pointInCircle(const Vec2 &point, const Vec2 &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 extra2d

View File

@ -1,76 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <string>
#include <vector>
#include <typeindex>
namespace extra2d {
class Application;
/**
* @brief
*
*/
class Module {
public:
virtual ~Module() = default;
/**
* @brief
* @return true
*/
virtual bool init() = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
* @return true
*/
virtual bool ok() const = 0;
/**
* @brief
* @return
*/
virtual const char* name() const = 0;
/**
* @brief
* @return
*/
virtual int priority() const { return 100; }
/**
* @brief
* @return
*/
virtual std::vector<std::type_index> deps() const { return {}; }
/**
* @brief Application
* @param app Application指针
*/
void setApp(class Application* app) { app_ = app; }
/**
* @brief Application
* @return Application指针
*/
class Application* app() const { return app_; }
protected:
class Application* app_ = nullptr;
};
/**
* @brief
*/
using ModuleFactory = std::function<UniquePtr<Module>()>;
} // namespace extra2d

View File

@ -1,116 +0,0 @@
#pragma once
#include <extra2d/core/module.h>
#include <extra2d/core/types.h>
#include <unordered_map>
#include <typeindex>
#include <vector>
#include <memory>
namespace extra2d {
class Application;
/**
* @brief
*
*/
class Registry {
public:
static Registry& instance();
Registry(const Registry&) = delete;
Registry& operator=(const Registry&) = delete;
/**
* @brief
* @tparam T
* @tparam Args
* @param args
* @return
*/
template<typename T, typename... Args>
T* use(Args&&... args) {
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
auto typeIdx = std::type_index(typeid(T));
if (modules_.count(typeIdx)) {
return static_cast<T*>(modules_[typeIdx].get());
}
auto module = makeUnique<T>(std::forward<Args>(args)...);
T* ptr = module.get();
module->setApp(app_);
modules_[typeIdx] = std::move(module);
return ptr;
}
/**
* @brief
* @tparam T
* @return nullptr
*/
template<typename T>
T* get() const {
auto typeIdx = std::type_index(typeid(T));
auto it = modules_.find(typeIdx);
if (it != modules_.end()) {
return static_cast<T*>(it->second.get());
}
return nullptr;
}
/**
* @brief
* @param typeIdx
* @return
*/
Module* get(std::type_index typeIdx) const {
auto it = modules_.find(typeIdx);
if (it != modules_.end()) {
return it->second.get();
}
return nullptr;
}
/**
* @brief Application
*/
void setApp(Application* app) { app_ = app; }
/**
* @brief
* @return true
*/
bool init();
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
void clear();
/**
* @brief
*/
size_t size() const { return modules_.size(); }
private:
Registry() = default;
~Registry() = default;
/**
* @brief
* @return
*/
std::vector<Module*> topologicalSort();
std::unordered_map<std::type_index, UniquePtr<Module>> modules_;
Application* app_ = nullptr;
};
} // namespace extra2d

View File

@ -1,144 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <string>
namespace extra2d {
/**
* @brief
*
*/
enum class ServicePriority : int {
Core = 0,
Event = 100,
Timer = 200,
Scene = 300,
Camera = 400,
Resource = 500,
Audio = 600,
User = 1000
};
/**
* @brief
*/
enum class ServiceState {
Uninitialized,
Initializing,
Running,
Paused,
Stopping,
Stopped
};
/**
* @brief
*/
struct ServiceInfo {
std::string name;
ServicePriority priority = ServicePriority::User;
ServiceState state = ServiceState::Uninitialized;
bool enabled = true;
};
/**
* @brief
*
*/
class IService {
friend class ServiceLocator;
public:
virtual ~IService() = default;
/**
* @brief
* @return
*/
virtual ServiceInfo getServiceInfo() const = 0;
/**
* @brief
* @return true
*/
virtual bool initialize() = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
*/
virtual void pause() {
info_.state = ServiceState::Paused;
}
/**
* @brief
*/
virtual void resume() {
if (info_.state == ServiceState::Paused) {
info_.state = ServiceState::Running;
}
}
/**
* @brief
* @param deltaTime
*/
virtual void update(float deltaTime) { }
/**
* @brief
* @return true
*/
virtual bool isInitialized() const {
return info_.state == ServiceState::Running ||
info_.state == ServiceState::Paused;
}
/**
* @brief
* @return
*/
ServiceState getState() const { return info_.state; }
/**
* @brief
* @return
*/
const std::string& getName() const { return info_.name; }
protected:
ServiceInfo info_;
/**
* @brief
* @param state
*/
void setState(ServiceState state) { info_.state = state; }
};
/**
* @brief ID生成器
* ID
*/
using ServiceTypeId = size_t;
namespace detail {
inline ServiceTypeId nextServiceTypeId() {
static ServiceTypeId id = 0;
return ++id;
}
template<typename T>
ServiceTypeId getServiceTypeId() {
static ServiceTypeId id = nextServiceTypeId();
return id;
}
}
}

View File

@ -1,302 +0,0 @@
#pragma once
#include <algorithm>
#include <extra2d/core/service_interface.h>
#include <extra2d/core/types.h>
#include <functional>
#include <memory>
#include <mutex>
#include <typeindex>
#include <unordered_map>
#include <vector>
namespace extra2d {
/**
* @brief
*/
template <typename T> using ServiceFactory = std::function<SharedPtr<T>()>;
/**
* @brief
*
*
*
* -
* -
* -
* - 线
* - Mock
*/
class ServiceLocator {
public:
/**
* @brief
* @return
*/
static ServiceLocator &instance();
ServiceLocator(const ServiceLocator &) = delete;
ServiceLocator &operator=(const ServiceLocator &) = delete;
/**
* @brief
* @tparam T
* @param service
*/
template <typename T> void registerService(SharedPtr<T> service) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
services_[typeId] = std::static_pointer_cast<IService>(service);
orderedServices_.push_back(service);
sortServices();
}
/**
* @brief
* @tparam T
* @param factory
*/
template <typename T> void registerFactory(ServiceFactory<T> factory) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
factories_[typeId] = [factory]() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(factory());
};
// 立即创建服务实例并添加到有序列表
auto service = factories_[typeId]();
services_[typeId] = service;
orderedServices_.push_back(service);
sortServices();
}
/**
* @brief
* @tparam T
* @return nullptr
*/
template <typename T> SharedPtr<T> getService() const {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
auto it = services_.find(typeId);
if (it != services_.end()) {
return std::static_pointer_cast<T>(it->second);
}
auto factoryIt = factories_.find(typeId);
if (factoryIt != factories_.end()) {
auto service = factoryIt->second();
services_[typeId] = service;
return std::static_pointer_cast<T>(service);
}
return nullptr;
}
/**
* @brief
* @tparam T
* @return nullptr
*/
template <typename T> SharedPtr<T> tryGetService() const {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
auto it = services_.find(typeId);
if (it != services_.end()) {
return std::static_pointer_cast<T>(it->second);
}
return nullptr;
}
/**
* @brief
* @tparam T
* @return true
*/
template <typename T> bool hasService() const {
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
return services_.find(typeId) != services_.end() ||
factories_.find(typeId) != factories_.end();
}
/**
* @brief
* @tparam T
*/
template <typename T> void unregisterService() {
std::lock_guard<std::mutex> lock(mutex_);
auto typeId = std::type_index(typeid(T));
auto it = services_.find(typeId);
if (it != services_.end()) {
auto service = it->second;
services_.erase(it);
auto orderIt =
std::find(orderedServices_.begin(), orderedServices_.end(), service);
if (orderIt != orderedServices_.end()) {
orderedServices_.erase(orderIt);
}
}
factories_.erase(typeId);
}
/**
* @brief
* @return true
*/
bool initializeAll();
/**
* @brief
*/
void shutdownAll();
/**
* @brief
* @param deltaTime
*/
void updateAll(float deltaTime);
/**
* @brief
*/
void pauseAll();
/**
* @brief
*/
void resumeAll();
/**
* @brief
* @return
*/
std::vector<SharedPtr<IService>> getAllServices() const;
/**
* @brief
*/
void clear();
/**
* @brief
* @return
*/
size_t size() const { return services_.size(); }
private:
ServiceLocator() = default;
~ServiceLocator() = default;
/**
* @brief
*/
void sortServices();
mutable std::unordered_map<std::type_index, SharedPtr<IService>> services_;
std::unordered_map<std::type_index, std::function<SharedPtr<IService>()>>
factories_;
std::vector<SharedPtr<IService>> orderedServices_;
mutable std::mutex mutex_;
};
/**
* @brief
*
*/
template <typename Interface, typename Implementation> class ServiceRegistrar {
public:
explicit ServiceRegistrar(ServiceFactory<Interface> factory = nullptr) {
if (factory) {
ServiceLocator::instance().registerFactory<Interface>(factory);
} else {
ServiceLocator::instance().registerFactory<Interface>(
[]() -> SharedPtr<Interface> {
return makeShared<Implementation>();
});
}
}
};
/**
* @brief
* 使
*
*/
template <typename Interface, typename Implementation> struct ServiceAutoReg {
/**
* @brief 访
*/
static const bool registered;
/**
* @brief
* @return true
*/
static bool doRegister() {
::extra2d::ServiceLocator::instance().registerFactory<Interface>(
[]() -> ::extra2d::SharedPtr<Interface> {
return ::extra2d::makeShared<Implementation>();
});
return true;
}
};
// 静态成员定义,在此处触发注册
template <typename Interface, typename Implementation>
const bool ServiceAutoReg<Interface, Implementation>::registered =
ServiceAutoReg<Interface, Implementation>::doRegister();
/**
* @brief
*/
template <typename Interface> struct ServiceAutoRegFactory {
template <typename Factory> struct Impl {
static const bool registered;
static bool doRegister(Factory factory) {
::extra2d::ServiceLocator::instance().registerFactory<Interface>(factory);
return true;
}
};
};
template <typename Interface>
template <typename Factory>
const bool ServiceAutoRegFactory<Interface>::Impl<Factory>::registered =
ServiceAutoRegFactory<Interface>::Impl<Factory>::doRegister(Factory{});
/**
* @brief
* 使
*
*/
#define E2D_AUTO_REGISTER_SERVICE(Interface, Implementation) \
static inline const bool E2D_CONCAT(_service_reg_, __LINE__) = \
ServiceAutoReg<Interface, Implementation>::registered
/**
* @brief
*/
#define E2D_AUTO_REGISTER_SERVICE_FACTORY(Interface, Factory) \
static inline const bool E2D_CONCAT(_service_factory_reg_, __LINE__) = \
ServiceAutoRegFactory<Interface>::Impl<Factory>::registered
} // namespace extra2d

View File

@ -1,137 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <functional>
#include <vector>
#include <string>
namespace extra2d {
/**
* @brief
*/
struct ServiceRegistration {
std::string name;
ServicePriority priority;
std::function<SharedPtr<IService>()> factory;
bool enabled = true;
};
/**
* @brief
*
*/
class ServiceRegistry {
public:
/**
* @brief
* @return
*/
static ServiceRegistry& instance();
ServiceRegistry(const ServiceRegistry&) = delete;
ServiceRegistry& operator=(const ServiceRegistry&) = delete;
/**
* @brief
* @tparam T
* @tparam Impl
* @param name
* @param priority
*/
template<typename T, typename Impl>
void registerService(const std::string& name, ServicePriority priority) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
static_assert(std::is_base_of_v<T, Impl>,
"Impl must derive from T");
ServiceRegistration reg;
reg.name = name;
reg.priority = priority;
reg.factory = []() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(makeShared<Impl>());
};
registrations_.push_back(reg);
}
/**
* @brief
* @tparam T
* @param name
* @param priority
* @param factory
*/
template<typename T>
void registerServiceWithFactory(
const std::string& name,
ServicePriority priority,
std::function<SharedPtr<T>()> factory) {
static_assert(std::is_base_of_v<IService, T>,
"T must derive from IService");
ServiceRegistration reg;
reg.name = name;
reg.priority = priority;
reg.factory = [factory]() -> SharedPtr<IService> {
return std::static_pointer_cast<IService>(factory());
};
registrations_.push_back(reg);
}
/**
* @brief /
* @param name
* @param enabled
*/
void setServiceEnabled(const std::string& name, bool enabled);
/**
* @brief
* ServiceLocator
*/
void createAllServices();
/**
* @brief
* @return
*/
const std::vector<ServiceRegistration>& getRegistrations() const {
return registrations_;
}
/**
* @brief
*/
void clear() {
registrations_.clear();
}
private:
ServiceRegistry() = default;
~ServiceRegistry() = default;
std::vector<ServiceRegistration> registrations_;
};
/**
* @brief
* 使
*/
template<typename Interface, typename Implementation>
class AutoServiceRegistrar {
public:
AutoServiceRegistrar(const std::string& name, ServicePriority priority) {
ServiceRegistry::instance().registerService<Interface, Implementation>(
name, priority);
}
};
}
#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \
namespace { \
static ::extra2d::AutoServiceRegistrar<Interface, Implementation> \
E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \
}

View File

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

View File

@ -1,172 +0,0 @@
#pragma once
#include <cstdint>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <variant>
namespace extra2d {
// ============================================================================
// 事件类型枚举
// ============================================================================
enum class EventType {
None = 0,
// 窗口事件
WindowClose,
WindowResize,
WindowFocus,
WindowLostFocus,
WindowMoved,
// 键盘事件
KeyPressed,
KeyReleased,
KeyRepeat,
// 鼠标事件
MouseButtonPressed,
MouseButtonReleased,
MouseMoved,
MouseScrolled,
// UI 事件
UIHoverEnter,
UIHoverExit,
UIPressed,
UIReleased,
UIClicked,
// 游戏手柄事件
GamepadConnected,
GamepadDisconnected,
GamepadButtonPressed,
GamepadButtonReleased,
GamepadAxisMoved,
// 触摸事件 (移动端)
TouchBegan,
TouchMoved,
TouchEnded,
TouchCancelled,
// 自定义事件
Custom
};
// ============================================================================
// 键盘事件数据
// ============================================================================
struct KeyEvent {
int keyCode;
int scancode;
int mods; // 修饰键 (Shift, Ctrl, Alt, etc.)
};
// ============================================================================
// 鼠标事件数据
// ============================================================================
struct MouseButtonEvent {
int button;
int mods;
Vec2 position;
};
struct MouseMoveEvent {
Vec2 position;
Vec2 delta;
};
struct MouseScrollEvent {
Vec2 offset;
Vec2 position;
};
// ============================================================================
// 窗口事件数据
// ============================================================================
struct WindowResizeEvent {
int width;
int height;
};
struct WindowMoveEvent {
int x;
int y;
};
// ============================================================================
// 游戏手柄事件数据
// ============================================================================
struct GamepadButtonEvent {
int gamepadId;
int button;
};
struct GamepadAxisEvent {
int gamepadId;
int axis;
float value;
};
// ============================================================================
// 触摸事件数据
// ============================================================================
struct TouchEvent {
int touchId;
Vec2 position;
};
// ============================================================================
// 自定义事件数据
// ============================================================================
struct CustomEvent {
uint32_t id;
void *data;
};
// ============================================================================
// 事件结构
// ============================================================================
struct Event {
EventType type = EventType::None;
double timestamp = 0.0;
bool handled = false;
// 事件数据联合体
std::variant<std::monostate, KeyEvent, MouseButtonEvent, MouseMoveEvent,
MouseScrollEvent, WindowResizeEvent, WindowMoveEvent,
GamepadButtonEvent, GamepadAxisEvent, TouchEvent, CustomEvent>
data;
// 便捷访问方法
bool isWindowEvent() const {
return type == EventType::WindowClose || type == EventType::WindowResize ||
type == EventType::WindowFocus ||
type == EventType::WindowLostFocus || type == EventType::WindowMoved;
}
bool isKeyboardEvent() const {
return type == EventType::KeyPressed || type == EventType::KeyReleased ||
type == EventType::KeyRepeat;
}
bool isMouseEvent() const {
return type == EventType::MouseButtonPressed ||
type == EventType::MouseButtonReleased ||
type == EventType::MouseMoved || type == EventType::MouseScrolled;
}
// 静态工厂方法
static Event createWindowResize(int width, int height);
static Event createWindowClose();
static Event createKeyPress(int keyCode, int scancode, int mods);
static Event createKeyRelease(int keyCode, int scancode, int mods);
static Event createMouseButtonPress(int button, int mods, const Vec2 &pos);
static Event createMouseButtonRelease(int button, int mods, const Vec2 &pos);
static Event createMouseMove(const Vec2 &pos, const Vec2 &delta);
static Event createMouseScroll(const Vec2 &offset, const Vec2 &pos);
};
} // namespace extra2d

View File

@ -1,56 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/event/event.h>
#include <functional>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// 事件监听器 ID
// ============================================================================
using ListenerId = uint64_t;
// ============================================================================
// 事件分发器
// ============================================================================
class EventDispatcher {
public:
using EventCallback = std::function<void(Event &)>;
EventDispatcher();
~EventDispatcher() = default;
// 添加监听器
ListenerId addListener(EventType type, EventCallback callback);
// 移除监听器
void removeListener(ListenerId id);
void removeAllListeners(EventType type);
void removeAllListeners();
// 分发事件
void dispatch(Event &event);
void dispatch(const Event &event);
// 处理事件队列
void processQueue(class EventQueue &queue);
// 统计
size_t getListenerCount(EventType type) const;
size_t getTotalListenerCount() const;
private:
struct Listener {
ListenerId id;
EventType type;
EventCallback callback;
};
std::unordered_map<EventType, std::vector<Listener>> listeners_;
ListenerId nextId_;
};
} // namespace extra2d

View File

@ -1,40 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/event/event.h>
#include <mutex>
#include <queue>
namespace extra2d {
// ============================================================================
// 事件队列 - 线程安全的事件队列
// ============================================================================
class EventQueue {
public:
EventQueue();
~EventQueue() = default;
// 添加事件到队列
void push(const Event &event);
void push(Event &&event);
// 从队列取出事件
bool poll(Event &event);
// 查看队列头部事件(不移除)
bool peek(Event &event) const;
// 清空队列
void clear();
// 队列状态
bool empty() const;
size_t size() const;
private:
std::queue<Event> queue_;
mutable std::mutex mutex_;
};
} // namespace extra2d

View File

@ -1,63 +0,0 @@
#pragma once
// Extra2D - 统一入口头文件
// 包含所有公共 API
// Core
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/core/module.h>
#include <extra2d/core/registry.h>
// Config removed - app info now in Application class
// Platform
#include <extra2d/platform/iinput.h>
#include <extra2d/platform/iwindow.h>
#include <extra2d/platform/keys.h>
#include <extra2d/platform/input_module.h>
#include <extra2d/platform/backend_factory.h>
#include <extra2d/platform/window_module.h>
// Graphics
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/texture/font.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/graphics/core/render_target.h>
#include <extra2d/graphics/camera/viewport_adapter.h>
#include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/graphics/texture/texture_pool.h>
// Scene
#include <extra2d/scene/node.h>
#include <extra2d/scene/scene.h>
#include <extra2d/scene/scene_manager.h>
#include <extra2d/scene/shape_node.h>
#include <extra2d/scene/sprite.h>
// Event
#include <extra2d/event/event.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/event_queue.h>
// Utils
#include <extra2d/utils/random.h>
#include <extra2d/utils/timer.h>
// Services
#include <extra2d/services/event_service.h>
#include <extra2d/services/scene_service.h>
#include <extra2d/services/timer_service.h>
#include <extra2d/services/camera_service.h>
#include <extra2d/services/logger_service.h>
// Application
#include <extra2d/app/application.h>
#ifdef __SWITCH__
#include <switch.h>
#endif

View File

@ -1,79 +0,0 @@
#pragma once
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/core/smart_ptr.h>
namespace extra2d {
/**
* @brief
*/
enum class BackendType {
OpenGL, // OpenGL 4.x
Vulkan, // Vulkan 1.x
Metal, // Metal (macOS/iOS)
D3D11, // Direct3D 11
D3D12, // Direct3D 12
OpenGLES, // OpenGL ES (移动平台)
Count
};
/**
* @brief
*/
class BackendFactory {
public:
/**
* @brief
* @return
*/
static BackendFactory& getInstance();
/**
* @brief
* @param type
* @return
*/
UniquePtr<RenderBackend> createBackend(BackendType type);
/**
* @brief
* @return
*/
UniquePtr<RenderBackend> createDefaultBackend();
/**
* @brief
* @param type
* @return truefalse
*/
bool isBackendAvailable(BackendType type) const;
/**
* @brief
* @return
*/
BackendType getRecommendedBackend() const;
/**
* @brief
* @param type
* @return
*/
const char* getBackendName(BackendType type) const;
/**
* @brief
* @param name
* @return OpenGL
*/
BackendType parseBackendType(const char* name) const;
private:
BackendFactory() = default;
~BackendFactory() = default;
BackendFactory(const BackendFactory&) = delete;
BackendFactory& operator=(const BackendFactory&) = delete;
};
} // namespace extra2d

View File

@ -1,83 +0,0 @@
#pragma once
#include <extra2d/graphics/resources/buffer.h>
#include <glad/glad.h>
#include <cstddef>
#include <cstdint>
namespace extra2d {
// ============================================================================
// OpenGL 缓冲区实现
// ============================================================================
class GLBuffer : public Buffer {
public:
/**
* @brief
*/
GLBuffer();
/**
* @brief
*/
~GLBuffer() override;
/**
* @brief
* @param desc
* @return true
*/
bool init(const BufferDesc& desc);
/**
* @brief
*/
void shutdown();
// Buffer 接口实现
void bind() override;
void unbind() override;
void setData(const void* data, size_t size) override;
void updateData(const void* data, size_t offset, size_t size) override;
void* map() override;
void unmap() override;
size_t getSize() const override { return size_; }
BufferType getType() const override { return type_; }
BufferUsage getUsage() const override { return usage_; }
bool isValid() const override { return bufferID_ != 0; }
uintptr_t getNativeHandle() const override { return static_cast<uintptr_t>(bufferID_); }
/**
* @brief OpenGL ID
* @return ID
*/
GLuint getBufferID() const { return bufferID_; }
/**
* @brief OpenGL
* @return
*/
GLenum getTarget() const { return target_; }
private:
GLuint bufferID_ = 0;
GLenum target_ = GL_ARRAY_BUFFER;
size_t size_ = 0;
BufferType type_ = BufferType::Vertex;
BufferUsage usage_ = BufferUsage::Static;
GLenum glUsage_ = GL_STATIC_DRAW;
bool mapped_ = false;
void* mappedPtr_ = nullptr;
/**
* @brief 使 OpenGL
*/
static GLenum convertUsage(BufferUsage usage);
/**
* @brief OpenGL
*/
static GLenum convertType(BufferType type);
};
} // namespace extra2d

View File

@ -1,139 +0,0 @@
#pragma once
#include <glad/glad.h>
#include <cstdint>
#include <string>
namespace extra2d {
// ============================================================================
// OpenGL 版本信息
// ============================================================================
struct GLVersion {
int major = 0;
int minor = 0;
bool es = false; // 是否为 ES 版本
};
// ============================================================================
// OpenGL 上下文管理类
// ============================================================================
class GLContext {
public:
/**
* @brief GLContext
*/
static GLContext& get();
/**
* @brief OpenGL
* @return true
*/
bool init();
/**
* @brief OpenGL
*/
void shutdown();
/**
* @brief
* @return true
*/
bool isValid() const { return initialized_; }
/**
* @brief OpenGL
*/
const GLVersion& getVersion() const { return version_; }
/**
* @brief OpenGL
*/
std::string getVersionString() const;
/**
* @brief GPU
*/
std::string getVendor() const;
/**
* @brief GPU
*/
std::string getRenderer() const;
/**
* @brief
* @param extension
* @return true
*/
bool hasExtension(const std::string& extension) const;
/**
* @brief
*/
int getMaxTextureSize() const;
/**
* @brief
*/
int getMaxTextureUnits() const;
/**
* @brief
*/
int getMaxVertexAttribs() const;
/**
* @brief uniform
*/
int getMaxUniformBufferBindings() const;
/**
* @brief OpenGL ES
*/
bool isGLES() const { return version_.es; }
/**
* @brief VAO
*/
bool hasVAO() const;
/**
* @brief FBO
*/
bool hasFBO() const;
/**
* @brief Shader
*/
bool hasShader() const;
private:
GLContext() = default;
~GLContext() = default;
GLContext(const GLContext&) = delete;
GLContext& operator=(const GLContext&) = delete;
bool initialized_ = false;
GLVersion version_;
// 缓存的限制值
mutable int maxTextureSize_ = -1;
mutable int maxTextureUnits_ = -1;
mutable int maxVertexAttribs_ = -1;
mutable int maxUniformBufferBindings_ = -1;
/**
* @brief OpenGL
*/
void parseVersion();
/**
* @brief OpenGL
*/
bool loadExtensions();
};
} // namespace extra2d

View File

@ -1,84 +0,0 @@
#pragma once
#include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/graphics/texture/font.h>
#include <stb/stb_truetype.h>
#include <stb/stb_rect_pack.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// OpenGL 字体图集实现 (使用 STB 库)
// 使用 stb_rect_pack 进行动态矩形打包,支持动态缓存字形
// ============================================================================
class GLFontAtlas : public FontAtlas {
public:
GLFontAtlas(const std::string& filepath, int fontSize, bool useSDF = false);
~GLFontAtlas() override;
// FontAtlas 接口实现
const Glyph* getGlyph(char32_t codepoint) const override;
Texture* getTexture() const override { return texture_.get(); }
int getFontSize() const override { return fontSize_; }
float getAscent() const override { return ascent_; }
float getDescent() const override { return descent_; }
float getLineGap() const override { return lineGap_; }
float getLineHeight() const override { return lineHeight_; }
bool isSDF() const override { return useSDF_; }
Vec2 measureText(const std::string& text) override;
private:
// 字形数据内部结构
struct GlyphData {
float width;
float height;
float bearingX;
float bearingY;
float advance;
float u0, v0, u1, v1;
};
// 图集配置 - 增大尺寸以支持更多字符
static constexpr int ATLAS_WIDTH = 1024;
static constexpr int ATLAS_HEIGHT = 1024;
static constexpr int PADDING = 2; // 字形之间的间距
bool useSDF_;
int fontSize_;
Ptr<GLTexture> texture_;
std::unordered_map<char32_t, GlyphData> glyphs_;
float lineHeight_;
float ascent_;
float descent_;
float lineGap_;
// 字体数据
std::vector<unsigned char> fontData_;
stbtt_fontinfo fontInfo_;
float scale_;
// stb_rect_pack 上下文 - 持久化以支持增量打包
mutable stbrp_context packContext_;
mutable std::vector<stbrp_node> packNodes_;
// 预分配缓冲区,避免每次动态分配
mutable std::vector<uint8_t> glyphBitmapCache_;
mutable std::vector<uint8_t> glyphRgbaCache_;
// 初始化字体
bool initFont(const std::string& filepath);
// 创建空白图集纹理
void createAtlas();
// 缓存字形到图集
void cacheGlyph(char32_t codepoint);
// 更新图集纹理区域
void updateAtlas(int x, int y, int width, int height,
const std::vector<uint8_t>& data);
};
} // namespace extra2d

View File

@ -1,105 +0,0 @@
#pragma once
#include <extra2d/graphics/resources/framebuffer.h>
#include <glad/glad.h>
#include <array>
#include <cstdint>
namespace extra2d {
// ============================================================================
// OpenGL 帧缓冲实现
// ============================================================================
class GLFramebuffer : public Framebuffer {
public:
// 最大颜色附件数
static constexpr int MAX_COLOR_ATTACHMENTS = 8;
/**
* @brief
*/
GLFramebuffer();
/**
* @brief
*/
~GLFramebuffer() override;
/**
* @brief
* @param desc
* @return true
*/
bool init(const FramebufferDesc& desc);
/**
* @brief
*/
void shutdown();
// Framebuffer 接口实现
void bind() override;
void unbind() override;
void attachColorTexture(Ptr<Texture> texture, int attachment = 0) override;
void attachDepthTexture(Ptr<Texture> texture) override;
void attachDepthStencilTexture(Ptr<Texture> texture) override;
bool isComplete() override;
Ptr<Texture> getColorTexture(int attachment = 0) const override;
Ptr<Texture> getDepthTexture() const override;
int getWidth() const override { return width_; }
int getHeight() const override { return height_; }
Size getSize() const override { return Size(static_cast<float>(width_), static_cast<float>(height_)); }
bool isValid() const override { return fboID_ != 0; }
uintptr_t getNativeHandle() const override { return static_cast<uintptr_t>(fboID_); }
void clear(const Color& color, bool clearColor = true,
bool clearDepth = true, bool clearStencil = false) override;
void setViewport(int x, int y, int width, int height) override;
bool readPixels(int x, int y, int width, int height,
std::vector<uint8_t>& outData) override;
/**
* @brief OpenGL FBO ID
* @return FBO ID
*/
GLuint getFboID() const { return fboID_; }
/**
* @brief 便
* @param width
* @param height
* @param colorFormat
* @param depthFormat
* @return true
*/
bool createWithTextures(int width, int height,
PixelFormat colorFormat = PixelFormat::RGBA8,
PixelFormat depthFormat = PixelFormat::Depth24);
private:
GLuint fboID_ = 0;
int width_ = 0;
int height_ = 0;
int numColorAttachments_ = 1;
bool hasDepth_ = false;
bool hasStencil_ = false;
// 附件纹理
std::array<Ptr<Texture>, MAX_COLOR_ATTACHMENTS> colorTextures_;
Ptr<Texture> depthTexture_;
Ptr<Texture> depthStencilTexture_;
// 是否为内置纹理(需要自动清理)
bool hasInternalTextures_ = false;
/**
* @brief
*/
bool checkStatus();
/**
* @brief OpenGL
*/
static GLenum getColorAttachment(int index);
};
} // namespace extra2d

View File

@ -1,131 +0,0 @@
#pragma once
#include <extra2d/graphics/resources/pipeline.h>
#include <glad/glad.h>
#include <cstdint>
namespace extra2d {
// ============================================================================
// OpenGL 管线状态实现
// ============================================================================
class GLPipeline : public Pipeline {
public:
/**
* @brief
*/
GLPipeline();
/**
* @brief
*/
~GLPipeline() override;
/**
* @brief 线
* @param desc 线
* @return true
*/
bool init(const PipelineDesc& desc);
/**
* @brief 线
*/
void shutdown();
// Pipeline 接口实现
void bind() override;
void unbind() override;
void setBlendMode(BlendMode mode) override;
BlendMode getBlendMode() const override { return blendMode_; }
void setDepthTest(bool enabled) override;
void setDepthWrite(bool enabled) override;
void setDepthFunc(DepthFunc func) override;
void setCullMode(CullMode mode) override;
bool isValid() const override { return initialized_; }
uintptr_t getNativeHandle() const override { return 0; } // OpenGL 管线没有单一句柄
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
*/
void setViewport(int x, int y, int width, int height);
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
*/
void getViewport(int& x, int& y, int& width, int& height) const;
/**
* @brief
*/
void applyAllStates();
private:
bool initialized_ = false;
// 当前状态
BlendMode blendMode_ = BlendMode::Alpha;
bool blendEnabled_ = true;
bool depthTest_ = false;
bool depthWrite_ = false;
DepthFunc depthFunc_ = DepthFunc::Less;
CullMode cullMode_ = CullMode::None;
// 视口
int viewportX_ = 0;
int viewportY_ = 0;
int viewportWidth_ = 0;
int viewportHeight_ = 0;
// 状态缓存(避免冗余 GL 调用)
BlendMode cachedBlendMode_ = BlendMode::None;
bool cachedBlendEnabled_ = false;
bool cachedDepthTest_ = false;
bool cachedDepthWrite_ = false;
DepthFunc cachedDepthFunc_ = DepthFunc::Less;
CullMode cachedCullMode_ = CullMode::None;
int cachedViewportX_ = -1;
int cachedViewportY_ = -1;
int cachedViewportWidth_ = -1;
int cachedViewportHeight_ = -1;
/**
* @brief
*/
void applyBlendState();
/**
* @brief
*/
void applyDepthState();
/**
* @brief
*/
void applyCullState();
/**
* @brief OpenGL
*/
static void getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstFactor);
/**
* @brief OpenGL
*/
static GLenum convertDepthFunc(DepthFunc func);
/**
* @brief OpenGL
*/
static GLenum convertCullMode(CullMode mode);
};
} // namespace extra2d

View File

@ -1,182 +0,0 @@
#pragma once
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
#include <extra2d/graphics/backends/opengl/gl_pipeline.h>
#include <extra2d/graphics/backends/opengl/gl_sprite_batch.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/shader/shader_interface.h>
#include <array>
#include <glad/glad.h>
#include <vector>
namespace extra2d {
// 前向声明
class IWindow;
class GLContext;
class GLFramebuffer;
// ============================================================================
// OpenGL 渲染器实现
// ============================================================================
class GLRenderer : public RenderBackend {
public:
GLRenderer();
~GLRenderer() override;
// RenderBackend 接口实现
bool init(IWindow* window) override;
void shutdown() override;
void beginFrame(const Color &clearColor) override;
void endFrame() override;
void setViewport(int x, int y, int width, int height) override;
void setVSync(bool enabled) override;
void setBlendMode(BlendMode mode) override;
void setViewProjection(const glm::mat4 &matrix) override;
// 变换矩阵栈
void pushTransform(const glm::mat4 &transform) override;
void popTransform() override;
glm::mat4 getCurrentTransform() const override;
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels) override;
Ptr<Texture> loadTexture(const std::string &filepath) override;
void beginSpriteBatch() override;
void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, float rotation,
const Vec2 &anchor) override;
void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) override;
void endSpriteBatch() override;
void flush() override;
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width) override;
void drawRect(const Rect &rect, const Color &color, float width) override;
void fillRect(const Rect &rect, const Color &color) override;
void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments, float width) override;
void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments) override;
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width) override;
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) override;
void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width) override;
void fillPolygon(const std::vector<Vec2> &points,
const Color &color) override;
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
bool useSDF = false) override;
void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) override;
void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color) override;
Stats getStats() const override { return stats_; }
void resetStats() override;
// GLFramebuffer 相关方法
/**
* @brief
* @param desc
* @return
*/
Ptr<GLFramebuffer> createFramebuffer(const FramebufferDesc& desc);
/**
* @brief
* @param framebuffer nullptr
*/
void bindFramebuffer(GLFramebuffer* framebuffer);
/**
* @brief
*/
void unbindFramebuffer();
/**
* @brief
* @return
*/
Ptr<GLFramebuffer> getDefaultFramebuffer() const;
/**
* @brief
* @param color
* @param clearColor
* @param clearDepth
* @param clearStencil
*/
void clearFramebuffer(const Color& color, bool clearColor = true,
bool clearDepth = true, bool clearStencil = false);
private:
// 形状批处理常量
static constexpr size_t MAX_CIRCLE_SEGMENTS = 128;
static constexpr size_t MAX_SHAPE_VERTICES = 8192; // 最大形状顶点数
static constexpr size_t MAX_LINE_VERTICES = 16384; // 最大线条顶点数
// 形状顶点结构(包含颜色)
struct ShapeVertex {
float x, y;
float r, g, b, a;
};
IWindow* window_;
GLSpriteBatch spriteBatch_;
Ptr<IShader> shapeShader_;
GLuint shapeVao_; // 形状 VAO手动管理用于顶点属性配置
GLBuffer shapeBuffer_; // 形状 VBO使用 GLBuffer 管理)
GLuint lineVao_; // 线条 VAO手动管理用于顶点属性配置
GLBuffer lineBuffer_; // 线条 VBO使用 GLBuffer 管理)
glm::mat4 viewProjection_;
std::vector<glm::mat4> transformStack_;
Stats stats_;
bool vsync_;
// 形状批处理缓冲区(预分配,避免每帧内存分配)
std::array<ShapeVertex, MAX_SHAPE_VERTICES> shapeVertexCache_;
size_t shapeVertexCount_ = 0;
GLenum currentShapeMode_ = GL_TRIANGLES;
// 线条批处理缓冲区
std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_;
size_t lineVertexCount_ = 0;
float currentLineWidth_ = 1.0f;
// OpenGL 管线状态管理
GLPipeline pipeline_;
// 自动批处理状态
bool batchActive_ = false; // 批处理是否激活
bool autoBatchEnabled_ = true; // 是否启用自动批处理
const Texture* currentBatchTexture_ = nullptr; // 当前批处理的纹理
std::vector<SpriteData> pendingSprites_; // 待提交的精灵
static constexpr size_t MAX_BATCH_SPRITES = 1000; // 最大批处理精灵数
// 帧缓冲管理
mutable Ptr<GLFramebuffer> defaultFramebuffer_; // 默认帧缓冲(延迟创建)
GLFramebuffer* currentFramebuffer_ = nullptr; // 当前绑定的帧缓冲
void initShapeRendering();
void ensureBatchActive(); // 确保批处理已激活
void submitPendingSprites(); // 提交待处理的精灵
void flushShapeBatch();
void flushLineBatch();
void addShapeVertex(float x, float y, const Color &color);
void addLineVertex(float x, float y, const Color &color);
void submitShapeBatch(GLenum mode);
};
} // namespace extra2d

View File

@ -1,196 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/graphics/shader/shader_interface.h>
#include <glad/glad.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
class GLShader : public IShader {
public:
/**
* @brief
*/
GLShader();
/**
* @brief
*/
~GLShader() override;
/**
* @brief Shader程序
*/
void bind() const override;
/**
* @brief Shader程序
*/
void unbind() const override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setBool(const std::string& name, bool value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setInt(const std::string& name, int value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setFloat(const std::string& name, float value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec2(const std::string& name, const glm::vec2& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec3(const std::string& name, const glm::vec3& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec4(const std::string& name, const glm::vec4& value) override;
/**
* @brief 4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
void setMat4(const std::string& name, const glm::mat4& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
void setColor(const std::string& name, const Color& color) override;
/**
* @brief Shader是否有效
* @return truefalse
*/
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 truefalse
*/
bool compileFromSource(const char* vertexSource, const char* fragmentSource);
/**
* @brief Shader
* @param binary
* @return truefalse
*/
bool compileFromBinary(const std::vector<uint8_t>& binary);
/**
* @brief Shader二进制数据
* @param outBinary
* @return truefalse
*/
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 ID0
*/
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 truefalse
*/
bool getShaderBinary(const IShader& shader,
std::vector<uint8_t>& outBinary) override;
};
} // namespace extra2d

View File

@ -1,68 +0,0 @@
#pragma once
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/graphics/batch/sprite_batch.h>
#include <extra2d/graphics/shader/shader_interface.h>
#include <array>
#include <glad/glad.h>
#include <vector>
namespace extra2d {
// ============================================================================
// OpenGL 精灵批处理渲染器
// 使用 batch/sprite_batch 作为后端无关的批处理层
// ============================================================================
class GLSpriteBatch {
public:
GLSpriteBatch();
~GLSpriteBatch();
// 初始化/关闭
bool init();
void shutdown();
// 批处理生命周期
void begin(const glm::mat4& viewProjection);
void end();
// 绘制单个精灵
void draw(const Texture& texture, const SpriteData& data);
// 批量绘制(用于文本渲染优化)
void drawBatch(const Texture& texture, const std::vector<SpriteData>& sprites);
// 获取绘制调用次数
uint32_t getDrawCallCount() const { return drawCallCount_; }
private:
// OpenGL 对象
GLuint vao_;
GLBuffer vbo_; // 顶点缓冲区(动态)
GLBuffer ebo_; // 索引缓冲区(静态)
// 后端无关的批处理层
SpriteBatch batch_;
// 批次管理
struct Batch {
const GLTexture* texture;
size_t startVertex;
size_t vertexCount;
};
std::vector<Batch> batches_;
const GLTexture* currentTexture_;
// 着色器和矩阵
Ptr<IShader> shader_;
uint32_t drawCallCount_;
glm::mat4 viewProjection_;
// 内部方法
void flush();
void submitBatch();
};
} // namespace extra2d

View File

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

View File

@ -1,78 +0,0 @@
#pragma once
#include <extra2d/graphics/core/render_backend.h>
namespace extra2d {
/**
* @brief Vulkan
*
* Vulkan后端应该包含的内容
* Vulkan上下文线
*/
class VulkanRenderer : public RenderBackend {
public:
VulkanRenderer();
~VulkanRenderer() override;
// RenderBackend 接口实现
bool init(IWindow* window) override;
void shutdown() override;
void beginFrame(const Color &clearColor) override;
void endFrame() override;
void setViewport(int x, int y, int width, int height) override;
void setVSync(bool enabled) override;
void setBlendMode(BlendMode mode) override;
void setViewProjection(const glm::mat4 &matrix) override;
void pushTransform(const glm::mat4 &transform) override;
void popTransform() override;
glm::mat4 getCurrentTransform() const override;
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels) override;
Ptr<Texture> loadTexture(const std::string &filepath) override;
void beginSpriteBatch() override;
void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, float rotation,
const Vec2 &anchor) override;
void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) override;
void endSpriteBatch() override;
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width) override;
void drawRect(const Rect &rect, const Color &color, float width) override;
void fillRect(const Rect &rect, const Color &color) override;
void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments, float width) override;
void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments) override;
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width) override;
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) override;
void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width) override;
void fillPolygon(const std::vector<Vec2> &points,
const Color &color) override;
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
bool useSDF = false) override;
void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) override;
void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color) override;
Stats getStats() const override { return stats_; }
void resetStats() override;
private:
Stats stats_;
bool initialized_ = false;
};
} // namespace extra2d

View File

@ -1,157 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <glm/mat4x4.hpp>
#include <cstdint>
#include <vector>
namespace extra2d {
// ============================================================================
// 形状顶点结构
// ============================================================================
struct ShapeVertex {
float x, y; // 位置
float r, g, b, a; // 颜色
ShapeVertex() = default;
ShapeVertex(float px, float py, const Color& c)
: x(px), y(py), r(c.r), g(c.g), b(c.b), a(c.a) {}
};
// ============================================================================
// 形状批处理抽象接口 - 后端无关
// ============================================================================
class ShapeBatch {
public:
virtual ~ShapeBatch() = default;
/**
* @brief
* @return true
*/
virtual bool init() = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
* @param viewProjection
*/
virtual void begin(const glm::mat4& viewProjection) = 0;
/**
* @brief
*/
virtual void end() = 0;
/**
* @brief 线
* @param start
* @param end
* @param color
* @param width 线
*/
virtual void drawLine(const Vec2& start, const Vec2& end,
const Color& color, float width = 1.0f) = 0;
/**
* @brief
* @param rect
* @param color
* @param width
*/
virtual void drawRect(const Rect& rect, const Color& color,
float width = 1.0f) = 0;
/**
* @brief
* @param rect
* @param color
*/
virtual void fillRect(const Rect& rect, const Color& color) = 0;
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
* @param width
*/
virtual void drawCircle(const Vec2& center, float radius,
const Color& color, int segments = 32,
float width = 1.0f) = 0;
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
*/
virtual void fillCircle(const Vec2& center, float radius,
const Color& color, int segments = 32) = 0;
/**
* @brief
* @param p1 1
* @param p2 2
* @param p3 3
* @param color
* @param width
*/
virtual void drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
const Color& color, float width = 1.0f) = 0;
/**
* @brief
* @param p1 1
* @param p2 2
* @param p3 3
* @param color
*/
virtual void fillTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
const Color& color) = 0;
/**
* @brief
* @param points
* @param color
* @param width
*/
virtual void drawPolygon(const std::vector<Vec2>& points,
const Color& color, float width = 1.0f) = 0;
/**
* @brief
* @param points
* @param color
*/
virtual void fillPolygon(const std::vector<Vec2>& points,
const Color& color) = 0;
/**
* @brief
* @return
*/
virtual uint32_t getDrawCallCount() const = 0;
/**
* @brief
*/
virtual void resetDrawCallCount() = 0;
/**
* @brief
* @return true
*/
virtual bool isValid() const = 0;
};
} // namespace extra2d

View File

@ -1,121 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/color.h>
#include <extra2d/graphics/texture/texture.h>
#include <glm/mat4x4.hpp>
#include <array>
#include <vector>
#include <cstdint>
namespace extra2d {
// ============================================================================
// 三角函数查表 - 避免每帧计算 sin/cos
// ============================================================================
class TrigLookup {
public:
TrigLookup();
// 通过角度(0-360)获取 sin/cos
float sin(int angle) const;
float cos(int angle) const;
// 通过弧度获取 sin/cos
float sinRad(float rad) const;
float cosRad(float rad) const;
private:
static constexpr int TABLE_SIZE = 360 * 4; // 0.25度精度
std::array<float, TABLE_SIZE> sinTable_;
std::array<float, TABLE_SIZE> cosTable_;
};
// ============================================================================
// 精灵批次数据 - 后端无关
// ============================================================================
struct SpriteVertex {
Vec2 position;
Vec2 texCoord;
Color color;
};
struct SpriteData {
Vec2 position;
Vec2 size;
float rotation;
Vec2 pivot;
Color color;
const Texture* texture;
Rect uvRect;
};
// ============================================================================
// 通用精灵批处理 - 后端无关
// 负责:顶点生成、批次管理、三角函数查表
// ============================================================================
class SpriteBatch {
public:
static constexpr size_t MAX_SPRITES = 10000;
static constexpr size_t VERTICES_PER_SPRITE = 4;
static constexpr size_t INDICES_PER_SPRITE = 6;
static constexpr size_t MAX_VERTICES = MAX_SPRITES * VERTICES_PER_SPRITE;
static constexpr size_t MAX_INDICES = MAX_SPRITES * INDICES_PER_SPRITE;
SpriteBatch();
~SpriteBatch() = default;
// 开始批次
void begin(const glm::mat4& viewProjection);
// 结束批次 - 返回需要绘制的批次列表
void end();
// 绘制单个精灵
void draw(const SpriteData& sprite);
// 批量绘制 - 一次性处理多个精灵
void drawBatch(const std::vector<SpriteData>& sprites);
// 立即绘制 - 不缓存,直接提交
void drawImmediate(const SpriteData& sprite);
// 获取当前批次数据
const std::vector<SpriteVertex>& getVertices() const { return vertices_; }
const std::vector<uint16_t>& getIndices() const { return indices_; }
size_t getSpriteCount() const { return spriteCount_; }
// 检查是否需要刷新
bool needsFlush() const { return spriteCount_ >= MAX_SPRITES; }
// 清空批次
void clear();
private:
// 三角函数查表
TrigLookup trigLookup_;
// 顶点数据 - 使用固定大小数组避免动态分配
std::vector<SpriteVertex> vertices_;
std::vector<uint16_t> indices_;
size_t spriteCount_;
// 变换矩阵
glm::mat4 viewProjection_;
glm::mat4 cachedVP_;
bool vpDirty_;
// 生成索引
void generateIndices();
// 生成顶点
void generateVertices(const SpriteData& sprite, size_t vertexOffset);
// 刷新批次
void flush();
};
} // namespace extra2d

View File

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

View File

@ -1,332 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <glm/mat4x4.hpp>
namespace extra2d {
// ============================================================================
// 视口适配模式枚举
// ============================================================================
enum class ViewportMode {
AspectRatio,
Stretch,
Center,
Custom
};
// ============================================================================
// 黑边位置枚举
// ============================================================================
enum class LetterboxPosition {
Center,
LeftTop,
RightTop,
LeftBottom,
RightBottom
};
// ============================================================================
// 视口配置结构体
// ============================================================================
struct ViewportConfig {
float logicWidth = 1920.0f;
float logicHeight = 1080.0f;
ViewportMode mode = ViewportMode::AspectRatio;
LetterboxPosition letterboxPosition = LetterboxPosition::Center;
Color letterboxColor = Colors::Black;
bool autoScaleInCenterMode = true;
float customScale = 1.0f;
Vec2 customOffset = Vec2::Zero();
Rect customViewport = Rect::Zero();
};
// ============================================================================
// 视口计算结果结构体
// ============================================================================
struct ViewportResult {
Rect viewport;
float scaleX = 1.0f;
float scaleY = 1.0f;
float uniformScale = 1.0f;
Vec2 offset;
bool hasLetterbox = false;
struct Letterbox {
Rect top;
Rect bottom;
Rect left;
Rect right;
} letterbox;
};
// ============================================================================
// 视口适配器类
// ============================================================================
class ViewportAdapter {
public:
ViewportAdapter();
ViewportAdapter(float logicWidth, float logicHeight);
~ViewportAdapter() = default;
// ------------------------------------------------------------------------
// 配置设置
// ------------------------------------------------------------------------
/**
* @brief
* @param config
*/
void setConfig(const ViewportConfig &config);
/**
* @brief
* @return
*/
const ViewportConfig &getConfig() const { return config_; }
/**
* @brief
* @param width
* @param height
*/
void setLogicSize(float width, float height);
/**
* @brief
* @param mode
*/
void setMode(ViewportMode mode);
/**
* @brief
* @param position
*/
void setLetterboxPosition(LetterboxPosition position);
/**
* @brief
* @param color
*/
void setLetterboxColor(const Color &color);
// ------------------------------------------------------------------------
// 更新和计算
// ------------------------------------------------------------------------
/**
* @brief
* @param screenWidth
* @param screenHeight
*/
void update(int screenWidth, int screenHeight);
/**
* @brief
* @return
*/
const ViewportResult &getResult() const { return result_; }
// ------------------------------------------------------------------------
// 坐标转换
// ------------------------------------------------------------------------
/**
* @brief
* @param screenPos
* @return
*/
Vec2 screenToLogic(const Vec2 &screenPos) const;
/**
* @brief
* @param logicPos
* @return
*/
Vec2 logicToScreen(const Vec2 &logicPos) const;
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 screenToLogic(float x, float y) const;
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 logicToScreen(float x, float y) const;
// ------------------------------------------------------------------------
// 矩阵获取
// ------------------------------------------------------------------------
/**
* @brief
* @return
*/
glm::mat4 getMatrix() const;
/**
* @brief
* @return
*/
glm::mat4 getInvMatrix() const;
// ------------------------------------------------------------------------
// 区域检测
// ------------------------------------------------------------------------
/**
* @brief
* @param screenPos
* @return true
*/
bool isInViewport(const Vec2 &screenPos) const;
/**
* @brief
* @param screenPos
* @return true
*/
bool isInLetterbox(const Vec2 &screenPos) const;
// ------------------------------------------------------------------------
// Getter 方法
// ------------------------------------------------------------------------
/**
* @brief
* @return
*/
float getLogicWidth() const { return config_.logicWidth; }
/**
* @brief
* @return
*/
float getLogicHeight() const { return config_.logicHeight; }
/**
* @brief
* @return
*/
Size getLogicSize() const {
return Size(config_.logicWidth, config_.logicHeight);
}
/**
* @brief
* @return
*/
int getScreenWidth() const { return screenWidth_; }
/**
* @brief
* @return
*/
int getScreenHeight() const { return screenHeight_; }
/**
* @brief
* @return
*/
Size getScreenSize() const {
return Size(static_cast<float>(screenWidth_),
static_cast<float>(screenHeight_));
}
/**
* @brief X方向缩放比例
* @return X方向缩放比例
*/
float getScaleX() const { return result_.scaleX; }
/**
* @brief Y方向缩放比例
* @return Y方向缩放比例
*/
float getScaleY() const { return result_.scaleY; }
/**
* @brief
* @return
*/
float getUniformScale() const { return result_.uniformScale; }
/**
* @brief
* @return
*/
Vec2 getOffset() const { return result_.offset; }
/**
* @brief
* @return
*/
Rect getViewport() const { return result_.viewport; }
/**
* @brief
* @return true
*/
bool hasLetterbox() const { return result_.hasLetterbox; }
/**
* @brief
* @return
*/
const ViewportResult::Letterbox &getLetterbox() const {
return result_.letterbox;
}
private:
/**
* @brief
*/
void calculateAspectRatio();
/**
* @brief
*/
void calculateStretch();
/**
* @brief
*/
void calculateCenter();
/**
* @brief
*/
void calculateCustom();
/**
* @brief
*/
void calculateLetterbox();
/**
* @brief
* @param extraWidth
* @param extraHeight
*/
void applyLetterboxPosition(float extraWidth, float extraHeight);
ViewportConfig config_;
ViewportResult result_;
int screenWidth_ = 0;
int screenHeight_ = 0;
mutable glm::mat4 viewportMatrix_;
mutable glm::mat4 inverseViewportMatrix_;
mutable bool matrixDirty_ = true;
};
} // namespace extra2d

View File

@ -1,141 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/resources/pipeline.h>
#include <glm/mat4x4.hpp>
namespace extra2d {
// 前向声明
class IWindow;
class Texture;
class FontAtlas;
class Shader;
// ============================================================================
// 渲染后端类型
// ============================================================================
enum class BackendType {
OpenGL,
// Vulkan,
// Metal,
// D3D11,
// D3D12
};
// BlendMode 定义在 pipeline.h 中
// ============================================================================
// 渲染后端抽象接口
// ============================================================================
class RenderBackend {
public:
virtual ~RenderBackend() = default;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
virtual bool init(IWindow* window) = 0;
virtual void shutdown() = 0;
// ------------------------------------------------------------------------
// 帧管理
// ------------------------------------------------------------------------
virtual void beginFrame(const Color &clearColor) = 0;
virtual void endFrame() = 0;
virtual void setViewport(int x, int y, int width, int height) = 0;
virtual void setVSync(bool enabled) = 0;
// ------------------------------------------------------------------------
// 状态设置
// ------------------------------------------------------------------------
virtual void setBlendMode(BlendMode mode) = 0;
virtual void setViewProjection(const glm::mat4 &matrix) = 0;
// ------------------------------------------------------------------------
// 变换矩阵栈
// ------------------------------------------------------------------------
virtual void pushTransform(const glm::mat4 &transform) = 0;
virtual void popTransform() = 0;
virtual glm::mat4 getCurrentTransform() const = 0;
// ------------------------------------------------------------------------
// 纹理
// ------------------------------------------------------------------------
virtual Ptr<Texture> createTexture(int width, int height,
const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0;
// ------------------------------------------------------------------------
// 精灵批渲染
// ------------------------------------------------------------------------
/**
* @brief
* @note drawSprite/drawText
*/
virtual void beginSpriteBatch() = 0;
virtual void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint,
float rotation, const Vec2 &anchor) = 0;
virtual void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) = 0;
virtual void endSpriteBatch() = 0;
/**
* @brief
* @note
*/
virtual void flush() = 0;
// ------------------------------------------------------------------------
// 形状渲染
// ------------------------------------------------------------------------
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width = 1.0f) = 0;
virtual void drawRect(const Rect &rect, const Color &color,
float width = 1.0f) = 0;
virtual void fillRect(const Rect &rect, const Color &color) = 0;
virtual void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments = 32, float width = 1.0f) = 0;
virtual void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments = 32) = 0;
virtual void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width = 1.0f) = 0;
virtual void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) = 0;
virtual void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width = 1.0f) = 0;
virtual void fillPolygon(const std::vector<Vec2> &points,
const Color &color) = 0;
// ------------------------------------------------------------------------
// 文字渲染
// ------------------------------------------------------------------------
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF = false) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color) = 0;
// ------------------------------------------------------------------------
// 统计信息
// ------------------------------------------------------------------------
struct Stats {
uint32_t drawCalls = 0;
uint32_t triangleCount = 0;
uint32_t textureBinds = 0;
uint32_t shaderBinds = 0;
};
virtual Stats getStats() const = 0;
virtual void resetStats() = 0;
// ------------------------------------------------------------------------
// 工厂方法
// ------------------------------------------------------------------------
static UniquePtr<RenderBackend> create(BackendType type);
};
} // namespace extra2d

View File

@ -1,223 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <glm/mat4x4.hpp>
#include <cstdint>
#include <variant>
namespace extra2d {
// 前向声明
class Texture;
class FontAtlas;
/**
* @brief
*/
enum class RenderCommandType : uint8_t {
None = 0,
Sprite, // 精灵绘制
Line, // 线条绘制
Rect, // 矩形绘制
FilledRect, // 填充矩形
Circle, // 圆形绘制
FilledCircle, // 填充圆形
Triangle, // 三角形绘制
FilledTriangle, // 填充三角形
Polygon, // 多边形绘制
FilledPolygon, // 填充多边形
Text, // 文本绘制
Custom // 自定义绘制
};
/**
* @brief
*/
struct SpriteCommandData {
const Texture* texture;
Rect destRect;
Rect srcRect;
Color tint;
float rotation;
Vec2 anchor;
uint32_t sortKey; // 用于自动排序的键值
SpriteCommandData()
: texture(nullptr), destRect(), srcRect(), tint(Colors::White),
rotation(0.0f), anchor(0.0f, 0.0f), sortKey(0) {}
SpriteCommandData(const Texture* tex, const Rect& dest, const Rect& src,
const Color& t, float rot, const Vec2& anc, uint32_t key)
: texture(tex), destRect(dest), srcRect(src), tint(t),
rotation(rot), anchor(anc), sortKey(key) {}
};
/**
* @brief 线
*/
struct LineCommandData {
Vec2 start;
Vec2 end;
Color color;
float width;
LineCommandData() : start(), end(), color(Colors::White), width(1.0f) {}
LineCommandData(const Vec2& s, const Vec2& e, const Color& c, float w)
: start(s), end(e), color(c), width(w) {}
};
/**
* @brief
*/
struct RectCommandData {
Rect rect;
Color color;
float width;
bool filled;
RectCommandData() : rect(), color(Colors::White), width(1.0f), filled(false) {}
RectCommandData(const Rect& r, const Color& c, float w, bool f)
: rect(r), color(c), width(w), filled(f) {}
};
/**
* @brief
*/
struct CircleCommandData {
Vec2 center;
float radius;
Color color;
int segments;
float width;
bool filled;
CircleCommandData() : center(), radius(0.0f), color(Colors::White),
segments(32), width(1.0f), filled(false) {}
CircleCommandData(const Vec2& c, float r, const Color& col, int seg, float w, bool f)
: center(c), radius(r), color(col), segments(seg), width(w), filled(f) {}
};
/**
* @brief
*/
struct TriangleCommandData {
Vec2 p1, p2, p3;
Color color;
float width;
bool filled;
TriangleCommandData() : p1(), p2(), p3(), color(Colors::White),
width(1.0f), filled(false) {}
TriangleCommandData(const Vec2& a, const Vec2& b, const Vec2& c, const Color& col, float w, bool f)
: p1(a), p2(b), p3(c), color(col), width(w), filled(f) {}
};
/**
* @brief
*/
struct PolygonCommandData {
std::vector<Vec2> points;
Color color;
float width;
bool filled;
PolygonCommandData() : color(Colors::White), width(1.0f), filled(false) {}
PolygonCommandData(std::vector<Vec2> pts, const Color& col, float w, bool f)
: points(std::move(pts)), color(col), width(w), filled(f) {}
};
/**
* @brief
*/
struct TextCommandData {
const FontAtlas* font;
std::string text;
Vec2 position;
Color color;
TextCommandData() : font(nullptr), text(), position(), color(Colors::White) {}
};
/**
* @brief
* 使 variant
*/
struct RenderCommand {
RenderCommandType type;
uint32_t layer; // 渲染层级,用于排序
uint32_t order; // 提交顺序,保证同层级内稳定排序
glm::mat4 transform; // 变换矩阵
// 使用 variant 存储具体数据
std::variant<
SpriteCommandData,
LineCommandData,
RectCommandData,
CircleCommandData,
TriangleCommandData,
PolygonCommandData,
TextCommandData
> data;
RenderCommand() : type(RenderCommandType::None), layer(0), order(0),
transform(1.0f) {}
// 便捷构造函数
static RenderCommand makeSprite(const Texture* tex, const Rect& dest,
const Rect& src, const Color& tint,
float rot = 0.0f, const Vec2& anc = Vec2(0, 0),
uint32_t lyr = 0);
static RenderCommand makeLine(const Vec2& s, const Vec2& e, const Color& c,
float w = 1.0f, uint32_t lyr = 0);
static RenderCommand makeRect(const Rect& r, const Color& c,
float w = 1.0f, bool fill = false, uint32_t lyr = 0);
};
/**
* @brief
*
*/
class RenderCommandBuffer {
public:
static constexpr size_t INITIAL_CAPACITY = 1024;
static constexpr size_t MAX_CAPACITY = 65536;
RenderCommandBuffer();
~RenderCommandBuffer();
// 添加渲染命令
void addCommand(const RenderCommand& cmd);
void addCommand(RenderCommand&& cmd);
// 批量添加(预留空间后使用)
RenderCommand& emplaceCommand();
// 排序命令(按纹理、层级等)
void sortCommands();
// 清空缓冲区
void clear();
// 获取命令列表
const std::vector<RenderCommand>& getCommands() const { return commands_; }
std::vector<RenderCommand>& getCommands() { return commands_; }
// 统计
size_t size() const { return commands_.size(); }
bool empty() const { return commands_.empty(); }
size_t capacity() const { return commands_.capacity(); }
// 预分配空间
void reserve(size_t capacity);
private:
std::vector<RenderCommand> commands_;
uint32_t nextOrder_;
// 排序比较函数
static bool compareCommands(const RenderCommand& a, const RenderCommand& b);
};
} // namespace extra2d

View File

@ -1,73 +0,0 @@
#pragma once
#include <extra2d/core/module.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/platform/window_module.h>
#include <functional>
#include <typeindex>
namespace extra2d {
/**
* @brief
*/
struct RenderCfg {
BackendType backend;
int targetFPS;
bool vsync;
int multisamples;
int priority;
RenderCfg()
: backend(BackendType::OpenGL)
, targetFPS(60)
, vsync(true)
, multisamples(0)
, priority(10)
{}
};
/**
* @brief
*
*/
class RenderModule : public Module {
public:
/**
* @brief Lambda
* @param configFn
*/
explicit RenderModule(std::function<void(RenderCfg&)> configFn);
/**
* @brief
*/
~RenderModule() override;
bool init() override;
void shutdown() override;
bool ok() const override { return initialized_; }
const char* name() const override { return "render"; }
int priority() const override { return cfg_.priority; }
/**
* @brief
* @return
*/
std::vector<std::type_index> deps() const override {
return {std::type_index(typeid(WindowModule))};
}
/**
* @brief
* @return
*/
RenderBackend* renderer() const { return renderer_.get(); }
private:
RenderCfg cfg_;
UniquePtr<RenderBackend> renderer_;
bool initialized_ = false;
};
} // namespace extra2d

View File

@ -1,313 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/graphics/texture/texture.h>
#include <mutex>
namespace extra2d {
// ============================================================================
// 渲染目标配置
// ============================================================================
struct RenderTargetConfig {
int width = 800; // 宽度
int height = 600; // 高度
PixelFormat colorFormat = PixelFormat::RGBA8; // 颜色格式
bool hasDepth = true; // 是否包含深度缓冲
bool hasStencil = false; // 是否包含模板缓冲
int samples = 1; // 多重采样数 (1 = 无MSAA)
bool autoResize = true; // 是否自动调整大小
};
// ============================================================================
// 渲染目标 - 基于FBO的离屏渲染
// ============================================================================
class RenderTarget {
public:
RenderTarget();
~RenderTarget();
// 禁止拷贝
RenderTarget(const RenderTarget &) = delete;
RenderTarget &operator=(const RenderTarget &) = delete;
// 允许移动
RenderTarget(RenderTarget &&other) noexcept;
RenderTarget &operator=(RenderTarget &&other) noexcept;
// ------------------------------------------------------------------------
// 创建和销毁
// ------------------------------------------------------------------------
/**
* @brief
*/
bool create(const RenderTargetConfig &config);
/**
* @brief
*/
bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false);
/**
* @brief
*/
void destroy();
/**
* @brief
*/
bool isValid() const { return fbo_ != 0; }
// ------------------------------------------------------------------------
// 尺寸和格式
// ------------------------------------------------------------------------
int getWidth() const { return width_; }
int getHeight() const { return height_; }
Vec2 getSize() const {
return Vec2(static_cast<float>(width_), static_cast<float>(height_));
}
PixelFormat getColorFormat() const { return colorFormat_; }
// ------------------------------------------------------------------------
// 绑定和解绑
// ------------------------------------------------------------------------
/**
* @brief
*/
void bind();
/**
* @brief
*/
void unbind();
/**
* @brief
*/
void clear(const Color &color = Colors::Transparent);
// ------------------------------------------------------------------------
// 纹理访问
// ------------------------------------------------------------------------
/**
* @brief
*/
Ptr<Texture> getColorTexture() const { return colorTexture_; }
/**
* @brief
*/
Ptr<Texture> getDepthTexture() const { return depthTexture_; }
// ------------------------------------------------------------------------
// 视口和裁剪
// ------------------------------------------------------------------------
/**
* @brief
*/
void setViewport(int x, int y, int width, int height);
/**
* @brief
*/
void getFullViewport(int &x, int &y, int &width, int &height) const;
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/**
* @brief
*/
bool resize(int width, int height);
/**
* @brief
*/
void copyTo(RenderTarget &target);
/**
* @brief
*/
void copyToScreen(int screenWidth, int screenHeight);
/**
* @brief
*/
bool saveToFile(const std::string &filepath);
// ------------------------------------------------------------------------
// 静态方法
// ------------------------------------------------------------------------
/**
* @brief
*/
static Ptr<RenderTarget> createFromConfig(const RenderTargetConfig &config);
/**
* @brief ID
*/
static GLuint getCurrentFBO();
/**
* @brief
*/
static void bindDefault();
/**
* @brief FBO ID使
*/
GLuint getFBO() const { return fbo_; }
protected:
GLuint fbo_ = 0; // 帧缓冲对象
GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板)
Ptr<Texture> colorTexture_; // 颜色纹理
Ptr<Texture> depthTexture_; // 深度纹理(可选)
int width_ = 0;
int height_ = 0;
PixelFormat colorFormat_ = PixelFormat::RGBA8;
bool hasDepth_ = false;
bool hasStencil_ = false;
int samples_ = 1;
bool createFBO();
void deleteFBO();
};
// ============================================================================
// 多重采样渲染目标用于MSAA
// ============================================================================
class MultisampleRenderTarget : public RenderTarget {
public:
/**
* @brief
*/
bool create(int width, int height, int samples = 4);
/**
* @brief
*/
void resolveTo(RenderTarget &target);
/**
* @brief
*/
void destroy();
private:
GLuint colorRBO_ = 0; // 多重采样颜色渲染缓冲
};
// ============================================================================
// 渲染目标栈(用于嵌套渲染)
// ============================================================================
class RenderTargetStack {
public:
static RenderTargetStack &get();
/**
* @brief
*/
void push(RenderTarget *target);
/**
* @brief
*/
void pop();
/**
* @brief
*/
RenderTarget *getCurrent() const;
/**
* @brief
*/
size_t size() const;
/**
* @brief
*/
void clear();
private:
RenderTargetStack() = default;
~RenderTargetStack() = default;
std::vector<RenderTarget *> stack_;
mutable std::mutex mutex_;
};
// ============================================================================
// 渲染目标管理器 - 全局渲染目标管理
// ============================================================================
class RenderTargetMgr {
public:
/**
* @brief
*/
static RenderTargetMgr& get();
/**
* @brief
* @param width
* @param height
*/
bool init(int width, int height);
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
Ptr<RenderTarget> createRenderTarget(const RenderTargetConfig &config);
/**
* @brief
*/
RenderTarget *getDefaultRenderTarget() const {
return defaultRenderTarget_.get();
}
/**
* @brief
*/
void resize(int width, int height);
/**
* @brief
*/
bool isInitialized() const { return initialized_; }
private:
RenderTargetMgr() = default;
~RenderTargetMgr() = default;
RenderTargetMgr(const RenderTargetMgr &) = delete;
RenderTargetMgr &operator=(const RenderTargetMgr &) = delete;
Ptr<RenderTarget> defaultRenderTarget_;
std::vector<Ptr<RenderTarget>> renderTargets_;
bool initialized_ = false;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::get()
#define E2D_RENDER_TARGET_MGR() ::extra2d::RenderTargetMgr::get()
} // namespace extra2d

View File

@ -1,36 +0,0 @@
#pragma once
#include <atomic>
namespace extra2d {
// ============================================================================
// GPU 上下文状态管理器
// 用于跟踪 OpenGL/Vulkan 等 GPU 上下文的生命周期状态
// 确保在 GPU 资源析构时能安全地检查上下文是否有效
// ============================================================================
class GPUContext {
public:
/// 获取单例实例
static GPUContext& get();
/// 标记 GPU 上下文为有效(在初始化完成后调用)
void markValid();
/// 标记 GPU 上下文为无效(在销毁前调用)
void markInvalid();
/// 检查 GPU 上下文是否有效
bool isValid() const;
private:
GPUContext() = default;
~GPUContext() = default;
GPUContext(const GPUContext&) = delete;
GPUContext& operator=(const GPUContext&) = delete;
std::atomic<bool> valid_{false};
};
} // namespace extra2d

View File

@ -1,62 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <mutex>
namespace extra2d {
// ============================================================================
// VRAM 管理器 - 跟踪显存使用情况
// ============================================================================
class VRAMMgr {
public:
static VRAMMgr& get();
// 纹理显存跟踪
void allocTexture(size_t size);
void freeTexture(size_t size);
// VBO/FBO 显存跟踪
void allocBuffer(size_t size);
void freeBuffer(size_t size);
// 查询显存使用情况
size_t getUsedVRAM() const;
size_t getTextureVRAM() const;
size_t getBufferVRAM() const;
size_t getAvailableVRAM() const;
// 显存预算管理
void setVRAMBudget(size_t budget);
size_t getVRAMBudget() const;
bool isOverBudget() const;
// 统计信息
void printStats() const;
// 重置计数器
void reset();
private:
VRAMMgr();
~VRAMMgr() = default;
VRAMMgr(const VRAMMgr&) = delete;
VRAMMgr& operator=(const VRAMMgr&) = delete;
mutable std::mutex mutex_;
size_t textureVRAM_;
size_t bufferVRAM_;
size_t vramBudget_;
// 统计
uint32_t textureAllocCount_;
uint32_t textureFreeCount_;
uint32_t bufferAllocCount_;
uint32_t bufferFreeCount_;
size_t peakTextureVRAM_;
size_t peakBufferVRAM_;
};
} // namespace extra2d

View File

@ -1,111 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <cstddef>
#include <cstdint>
namespace extra2d {
// ============================================================================
// 缓冲区类型枚举
// ============================================================================
enum class BufferType {
Vertex, // 顶点缓冲
Index, // 索引缓冲
Uniform // 统一缓冲
};
// ============================================================================
// 缓冲区使用模式枚举
// ============================================================================
enum class BufferUsage {
Static, // 静态数据,很少更新
Dynamic, // 动态数据,频繁更新
Stream // 流式数据,每帧更新
};
// ============================================================================
// 缓冲区描述结构
// ============================================================================
struct BufferDesc {
BufferType type = BufferType::Vertex;
BufferUsage usage = BufferUsage::Static;
size_t size = 0; // 缓冲区大小(字节)
const void* initialData = nullptr; // 初始数据
};
// ============================================================================
// 缓冲区抽象接口 - 渲染后端无关
// ============================================================================
class Buffer {
public:
virtual ~Buffer() = default;
/**
* @brief
*/
virtual void bind() = 0;
/**
* @brief
*/
virtual void unbind() = 0;
/**
* @brief
* @param data
* @param size
*/
virtual void setData(const void* data, size_t size) = 0;
/**
* @brief
* @param data
* @param offset
* @param size
*/
virtual void updateData(const void* data, size_t offset, size_t size) = 0;
/**
* @brief
* @return nullptr
*/
virtual void* map() = 0;
/**
* @brief
*/
virtual void unmap() = 0;
/**
* @brief
* @return
*/
virtual size_t getSize() const = 0;
/**
* @brief
* @return
*/
virtual BufferType getType() const = 0;
/**
* @brief 使
* @return 使
*/
virtual BufferUsage getUsage() const = 0;
/**
* @brief
* @return true
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual uintptr_t getNativeHandle() const = 0;
};
} // namespace extra2d

View File

@ -1,131 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <string>
#include <unordered_map>
namespace extra2d {
// ============================================================================
// 字形信息结构
// ============================================================================
struct Glyph {
float width = 0; // 字形宽度
float height = 0; // 字形高度
float bearingX = 0; // 水平偏移
float bearingY = 0; // 垂直偏移(从基线到字形顶部)
float advance = 0; // 水平步进
float u0 = 0, v0 = 0; // 纹理坐标左下角
float u1 = 0, v1 = 0; // 纹理坐标右上角
};
// ============================================================================
// 字体图集描述结构
// ============================================================================
struct FontAtlasDesc {
std::string filepath; // 字体文件路径
int fontSize = 16; // 字体大小
bool useSDF = false; // 是否使用SDF渲染
int atlasSize = 512; // 图集大小
int padding = 2; // 字形间距
};
// ============================================================================
// 字体图集抽象接口 - 渲染后端无关
// ============================================================================
class FontAtlas {
public:
virtual ~FontAtlas() = default;
/**
* @brief
* @param desc
* @return true
*/
virtual bool init(const FontAtlasDesc& desc) = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
* @param codepoint Unicode
* @return nullptr
*/
virtual const Glyph* getGlyph(char32_t codepoint) const = 0;
/**
* @brief
* @return
*/
virtual Ptr<Texture> getTexture() const = 0;
/**
* @brief
* @return
*/
virtual int getFontSize() const = 0;
/**
* @brief
* @return
*/
virtual float getLineHeight() const = 0;
/**
* @brief 线
* @return
*/
virtual float getAscent() const = 0;
/**
* @brief 线
* @return
*/
virtual float getDescent() const = 0;
/**
* @brief
* @param text
* @return
*/
virtual float measureText(const std::string& text) const = 0;
/**
* @brief
* @param text
* @return
*/
virtual Size measureTextSize(const std::string& text) const = 0;
/**
* @brief 使SDF渲染
* @return 使SDF返回 true
*/
virtual bool isSDF() const = 0;
/**
* @brief
* @return true
*/
virtual bool isValid() const = 0;
/**
* @brief
* @param text
* @return
*/
virtual int preloadGlyphs(const std::string& text) = 0;
/**
* @brief
*/
virtual void clearCache() = 0;
};
} // namespace extra2d

View File

@ -1,140 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <cstdint>
namespace extra2d {
// ============================================================================
// 帧缓冲描述结构
// ============================================================================
struct FramebufferDesc {
int width = 0; // 帧缓冲宽度
int height = 0; // 帧缓冲高度
int colorAttachments = 1; // 颜色附件数量
bool hasDepth = false; // 是否有深度附件
bool hasStencil = false; // 是否有模板附件
bool multisample = false; // 是否多重采样
int samples = 4; // 采样数(多重采样时有效)
};
// ============================================================================
// 帧缓冲抽象接口 - 渲染后端无关
// ============================================================================
class Framebuffer {
public:
virtual ~Framebuffer() = default;
/**
* @brief
*/
virtual void bind() = 0;
/**
* @brief
*/
virtual void unbind() = 0;
/**
* @brief
* @param texture
* @param attachment 0-7
*/
virtual void attachColorTexture(Ptr<Texture> texture, int attachment = 0) = 0;
/**
* @brief
* @param texture
*/
virtual void attachDepthTexture(Ptr<Texture> texture) = 0;
/**
* @brief
* @param texture
*/
virtual void attachDepthStencilTexture(Ptr<Texture> texture) = 0;
/**
* @brief
* @return true
*/
virtual bool isComplete() = 0;
/**
* @brief
* @param attachment
* @return
*/
virtual Ptr<Texture> getColorTexture(int attachment = 0) const = 0;
/**
* @brief
* @return
*/
virtual Ptr<Texture> getDepthTexture() const = 0;
/**
* @brief
* @return
*/
virtual int getWidth() const = 0;
/**
* @brief
* @return
*/
virtual int getHeight() const = 0;
/**
* @brief
* @return
*/
virtual Size getSize() const = 0;
/**
* @brief
* @return true
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual uintptr_t getNativeHandle() const = 0;
/**
* @brief
* @param color
* @param clearColor
* @param clearDepth
* @param clearStencil
*/
virtual void clear(const Color& color, bool clearColor = true,
bool clearDepth = true, bool clearStencil = false) = 0;
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
*/
virtual void setViewport(int x, int y, int width, int height) = 0;
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
* @param outData
* @return true
*/
virtual bool readPixels(int x, int y, int width, int height,
std::vector<uint8_t>& outData) = 0;
};
} // namespace extra2d

View File

@ -1,162 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <cstdint>
namespace extra2d {
// ============================================================================
// 混合模式枚举
// ============================================================================
enum class BlendMode {
None, // 不混合
Alpha, // 标准 Alpha 混合
Additive, // 加法混合
Multiply // 乘法混合
};
// ============================================================================
// 深度测试函数枚举
// ============================================================================
enum class DepthFunc {
Never, // 永不通过
Less, // 小于
Equal, // 等于
LessEqual, // 小于等于
Greater, // 大于
NotEqual, // 不等于
GreaterEqual,// 大于等于
Always // 总是通过
};
// ============================================================================
// 裁剪模式枚举
// ============================================================================
enum class CullMode {
None, // 不裁剪
Front, // 裁剪正面
Back, // 裁剪背面
Both // 裁剪双面
};
// ============================================================================
// 顶点属性格式枚举
// ============================================================================
enum class VertexFormat {
Float1, // 1个float
Float2, // 2个float
Float3, // 3个float
Float4, // 4个float
Byte4, // 4个byte
UByte4, // 4个ubyte
Short2, // 2个short
Short4 // 4个short
};
// ============================================================================
// 顶点属性描述
// ============================================================================
struct VertexAttribute {
uint32_t location = 0; // 属性位置
VertexFormat format = VertexFormat::Float3; // 数据格式
uint32_t offset = 0; // 在顶点结构中的偏移
uint32_t stride = 0; // 顶点结构大小
bool normalized = false; // 是否归一化
VertexAttribute() = default;
VertexAttribute(uint32_t loc, VertexFormat fmt, uint32_t off, uint32_t str, bool norm = false)
: location(loc), format(fmt), offset(off), stride(str), normalized(norm) {}
};
// ============================================================================
// 管线描述结构
// ============================================================================
struct PipelineDesc {
// 混合状态
BlendMode blendMode = BlendMode::Alpha;
bool blendEnabled = true;
// 深度状态
bool depthTest = false;
bool depthWrite = false;
DepthFunc depthFunc = DepthFunc::Less;
// 裁剪状态
CullMode cullMode = CullMode::None;
// 顶点布局
std::vector<VertexAttribute> vertexAttributes;
// 着色器(由后端特定实现设置)
void* vertexShader = nullptr;
void* fragmentShader = nullptr;
};
// ============================================================================
// 渲染管线抽象接口 - 渲染后端无关
// ============================================================================
class Pipeline {
public:
virtual ~Pipeline() = default;
/**
* @brief 线
*/
virtual void bind() = 0;
/**
* @brief 线
*/
virtual void unbind() = 0;
/**
* @brief
* @param mode
*/
virtual void setBlendMode(BlendMode mode) = 0;
/**
* @brief
* @return
*/
virtual BlendMode getBlendMode() const = 0;
/**
* @brief
* @param enabled
*/
virtual void setDepthTest(bool enabled) = 0;
/**
* @brief
* @param enabled
*/
virtual void setDepthWrite(bool enabled) = 0;
/**
* @brief
* @param func
*/
virtual void setDepthFunc(DepthFunc func) = 0;
/**
* @brief
* @param mode
*/
virtual void setCullMode(CullMode mode) = 0;
/**
* @brief 线
* @return true
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual uintptr_t getNativeHandle() const = 0;
};
} // namespace extra2d

View File

@ -1,134 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// 着色器类型枚举
// ============================================================================
enum class ShaderType {
Vertex, // 顶点着色器
Fragment, // 片段着色器
Geometry, // 几何着色器
Compute // 计算着色器
};
// ============================================================================
// 着色器描述结构
// ============================================================================
struct ShaderDesc {
std::string name; // 着色器名称
std::string vertexSource; // 顶点着色器源码
std::string fragmentSource; // 片段着色器源码
std::string geometrySource; // 几何着色器源码(可选)
std::vector<uint8_t> binaryData; // 预编译二进制数据(可选)
};
// ============================================================================
// 着色器抽象接口 - 渲染后端无关
// ============================================================================
class Shader {
public:
virtual ~Shader() = default;
/**
* @brief
*/
virtual void bind() = 0;
/**
* @brief
*/
virtual void unbind() = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setBool(const std::string& name, bool value) = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setInt(const std::string& name, int value) = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setFloat(const std::string& name, float value) = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setVec2(const std::string& name, const glm::vec2& value) = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setVec3(const std::string& name, const glm::vec3& value) = 0;
/**
* @brief uniform
* @param name uniform
* @param value
*/
virtual void setVec4(const std::string& name, const glm::vec4& value) = 0;
/**
* @brief 4x4 uniform
* @param name uniform
* @param value 4x4
*/
virtual void setMat4(const std::string& name, const glm::mat4& value) = 0;
/**
* @brief uniform
* @param name uniform
* @param color
*/
virtual void setColor(const std::string& name, const Color& color) = 0;
/**
* @brief
* @param name uniform
* @param slot
*/
virtual void setTexture(const std::string& name, int slot) = 0;
/**
* @brief
* @return
*/
virtual const std::string& getName() const = 0;
/**
* @brief
* @return true
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual uintptr_t getNativeHandle() const = 0;
};
} // namespace extra2d

View File

@ -1,131 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// Shader缓存条目
// ============================================================================
struct ShaderCacheEntry {
std::string name;
std::string sourceHash;
uint64_t compileTime = 0;
std::vector<uint8_t> binary;
std::vector<std::string> dependencies;
};
// ============================================================================
// Shader缓存管理器
// ============================================================================
class ShaderCache {
public:
/**
* @brief
* @return
*/
static ShaderCache& getInstance();
/**
* @brief
* @param cacheDir
* @return truefalse
*/
bool init(const std::string& cacheDir);
/**
* @brief
*/
void shutdown();
/**
* @brief
* @param name Shader名称
* @param sourceHash
* @return truefalse
*/
bool hasValidCache(const std::string& name, const std::string& sourceHash);
/**
* @brief
* @param name Shader名称
* @return nullptr
*/
Ptr<ShaderCacheEntry> loadCache(const std::string& name);
/**
* @brief
* @param entry
* @return truefalse
*/
bool saveCache(const ShaderCacheEntry& entry);
/**
* @brief 使
* @param name Shader名称
*/
void invalidate(const std::string& name);
/**
* @brief
*/
void clearAll();
/**
* @brief
* @param vertSource
* @param fragSource
* @return
*/
static std::string computeHash(const std::string& vertSource,
const std::string& fragSource);
/**
* @brief
* @return truefalse
*/
bool isInitialized() const { return initialized_; }
private:
ShaderCache() = default;
~ShaderCache() = default;
ShaderCache(const ShaderCache&) = delete;
ShaderCache& operator=(const ShaderCache&) = delete;
std::string cacheDir_;
std::unordered_map<std::string, ShaderCacheEntry> cacheMap_;
bool initialized_ = false;
/**
* @brief
* @return truefalse
*/
bool loadCacheIndex();
/**
* @brief
* @return truefalse
*/
bool saveCacheIndex();
/**
* @brief
* @param name Shader名称
* @return
*/
std::string getCachePath(const std::string& name) const;
/**
* @brief
* @return truefalse
*/
bool ensureCacheDirectory();
};
// 便捷宏
#define E2D_SHADER_CACHE() ::extra2d::ShaderCache::getInstance()
} // namespace extra2d

View File

@ -1,131 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#endif
namespace extra2d {
// ============================================================================
// 文件变化事件
// ============================================================================
struct FileChangeEvent {
std::string filepath;
enum class Type { Created, Modified, Deleted, Renamed } type;
uint64_t timestamp = 0;
};
// ============================================================================
// 文件变化回调
// ============================================================================
using FileChangeCallback = std::function<void(const FileChangeEvent &)>;
// ============================================================================
// Shader热重载管理器
// ============================================================================
class ShaderHotReloader {
public:
/**
* @brief
* @return
*/
static ShaderHotReloader &getInstance();
/**
* @brief
* @return truefalse
*/
bool init();
/**
* @brief
*/
void shutdown();
/**
* @brief Shader文件监视
* @param shaderName Shader名称
* @param filePaths
* @param callback
*/
void watch(const std::string &shaderName,
const std::vector<std::string> &filePaths,
FileChangeCallback callback);
/**
* @brief
* @param shaderName Shader名称
*/
void unwatch(const std::string &shaderName);
/**
* @brief
*/
void update();
/**
* @brief /
* @param enabled
*/
void setEnabled(bool enabled);
/**
* @brief
* @return truefalse
*/
bool isEnabled() const { return enabled_; }
/**
* @brief
* @return truefalse
*/
bool isInitialized() const { return initialized_; }
private:
ShaderHotReloader() = default;
~ShaderHotReloader() = default;
ShaderHotReloader(const ShaderHotReloader &) = delete;
ShaderHotReloader &operator=(const ShaderHotReloader &) = delete;
bool enabled_ = false;
bool initialized_ = false;
struct WatchInfo {
std::vector<std::string> filePaths;
FileChangeCallback callback;
std::unordered_map<std::string, uint64_t> modifiedTimes;
};
std::unordered_map<std::string, WatchInfo> watchMap_;
#ifdef _WIN32
HANDLE watchHandle_ = nullptr;
std::vector<uint8_t> buffer_;
std::string watchDir_;
bool watching_ = false;
#endif
/**
* @brief
*/
void pollChanges();
/**
* @brief
* @param filepath
* @return
*/
static uint64_t getFileModifiedTime(const std::string &filepath);
};
// 便捷宏
#define E2D_SHADER_HOT_RELOADER() ::extra2d::ShaderHotReloader::getInstance()
} // namespace extra2d

View File

@ -1,152 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <string>
#include <vector>
namespace extra2d {
class Color;
// ============================================================================
// Shader抽象接口 - 渲染后端无关
// ============================================================================
class IShader {
public:
virtual ~IShader() = default;
/**
* @brief Shader程序
*/
virtual void bind() const = 0;
/**
* @brief Shader程序
*/
virtual void unbind() const = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setBool(const std::string& name, bool value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setInt(const std::string& name, int value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setFloat(const std::string& name, float value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setVec2(const std::string& name, const glm::vec2& value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setVec3(const std::string& name, const glm::vec3& value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
virtual void setVec4(const std::string& name, const glm::vec4& value) = 0;
/**
* @brief 4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
virtual void setMat4(const std::string& name, const glm::mat4& value) = 0;
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
virtual void setColor(const std::string& name, const Color& color) = 0;
/**
* @brief Shader是否有效
* @return truefalse
*/
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 truefalse
*/
virtual bool getShaderBinary(const IShader& shader,
std::vector<uint8_t>& outBinary) = 0;
};
} // namespace extra2d

View File

@ -1,227 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// Shader加载结果
// ============================================================================
struct ShaderLoadResult {
bool success = false;
std::string errorMessage;
std::string vertSource;
std::string fragSource;
std::vector<std::string> dependencies;
};
// ============================================================================
// Shader元数据
// ============================================================================
struct ShaderMetadata {
std::string name;
std::string vertPath;
std::string fragPath;
std::string combinedPath;
uint64_t lastModified = 0;
std::vector<std::string> defines;
std::unordered_map<std::string, std::string> uniforms;
};
// ============================================================================
// ShaderLoader接口 - 支持多种文件格式加载
// ============================================================================
class IShaderLoader {
public:
virtual ~IShaderLoader() = default;
/**
* @brief Shader (.vert + .frag)
* @param name Shader名称
* @param vertPath
* @param fragPath
* @return
*/
virtual ShaderLoadResult loadFromSeparateFiles(
const std::string& name,
const std::string& vertPath,
const std::string& fragPath) = 0;
/**
* @brief Shader (.shader)
* @param path Shader文件路径
* @return
*/
virtual ShaderLoadResult loadFromCombinedFile(const std::string& path) = 0;
/**
* @brief Shader
* @param vertSource
* @param fragSource
* @return
*/
virtual ShaderLoadResult loadFromSource(
const std::string& vertSource,
const std::string& fragSource) = 0;
/**
* @brief Shader源码中的#include指令
* @param source
* @param baseDir
* @param outDependencies
* @return
*/
virtual std::string processIncludes(
const std::string& source,
const std::string& baseDir,
std::vector<std::string>& outDependencies) = 0;
/**
* @brief
* @param source
* @param defines
* @return
*/
virtual std::string applyDefines(
const std::string& source,
const std::vector<std::string>& defines) = 0;
/**
* @brief Shader元数据
* @param path Shader文件路径
* @return
*/
virtual ShaderMetadata getMetadata(const std::string& path) = 0;
};
// ============================================================================
// 默认ShaderLoader实现
// ============================================================================
class ShaderLoader : public IShaderLoader {
public:
ShaderLoader();
~ShaderLoader() override = default;
/**
* @brief Shader (.vert + .frag)
* @param name Shader名称
* @param vertPath
* @param fragPath
* @return
*/
ShaderLoadResult loadFromSeparateFiles(
const std::string& name,
const std::string& vertPath,
const std::string& fragPath) override;
/**
* @brief Shader (.shader)
* @param path Shader文件路径
* @return
*/
ShaderLoadResult loadFromCombinedFile(const std::string& path) override;
/**
* @brief Shader
* @param vertSource
* @param fragSource
* @return
*/
ShaderLoadResult loadFromSource(
const std::string& vertSource,
const std::string& fragSource) override;
/**
* @brief Shader源码中的#include指令
* @param source
* @param baseDir
* @param outDependencies
* @return
*/
std::string processIncludes(
const std::string& source,
const std::string& baseDir,
std::vector<std::string>& outDependencies) override;
/**
* @brief
* @param source
* @param defines
* @return
*/
std::string applyDefines(
const std::string& source,
const std::vector<std::string>& defines) override;
/**
* @brief Shader元数据
* @param path Shader文件路径
* @return
*/
ShaderMetadata getMetadata(const std::string& path) override;
/**
* @brief include搜索路径
* @param path
*/
void addIncludePath(const std::string& path);
/**
* @brief
* @param filepath
* @return
*/
static std::string readFile(const std::string& filepath);
/**
* @brief
* @param filepath
* @return
*/
static uint64_t getFileModifiedTime(const std::string& filepath);
/**
* @brief
* @param filepath
* @return truefalse
*/
static bool fileExists(const std::string& filepath);
private:
std::vector<std::string> includePaths_;
std::unordered_map<std::string, std::string> includeCache_;
/**
* @brief Shader文件
* @param content
* @param outVert
* @param outFrag
* @param outMetadata
* @return truefalse
*/
bool parseCombinedFile(const std::string& content,
std::string& outVert,
std::string& outFrag,
ShaderMetadata& outMetadata);
/**
* @brief JSON块
* @param jsonContent JSON内容
* @param outMetadata
* @return truefalse
*/
bool parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata);
/**
* @brief include文件路径
* @param includeName include文件名
* @param baseDir
* @return
*/
std::string findIncludeFile(const std::string& includeName, const std::string& baseDir);
};
} // namespace extra2d

View File

@ -1,258 +0,0 @@
#pragma once
#include <extra2d/graphics/shader/shader_cache.h>
#include <extra2d/graphics/shader/shader_hot_reloader.h>
#include <extra2d/graphics/shader/shader_interface.h>
#include <extra2d/graphics/shader/shader_loader.h>
#include <functional>
#include <unordered_map>
namespace extra2d {
// ============================================================================
// Shader重载回调
// ============================================================================
using ShaderReloadCallback = std::function<void(Ptr<IShader> newShader)>;
// ============================================================================
// Shader管理器 - 统一入口
// ============================================================================
class ShaderManager {
public:
/**
* @brief
* @return Shader管理器实例引用
*/
static ShaderManager& getInstance();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
/**
* @brief 使Shader系统
* 使romfs/sdmc/
* @param factory Shader工厂
* @param appName
* @return truefalse
*/
bool init(Ptr<IShaderFactory> factory, const std::string& appName = "extra2d");
/**
* @brief Shader系统
* @param shaderDir Shader文件目录
* @param cacheDir
* @param factory Shader工厂
* @return truefalse
*/
bool init(const std::string& shaderDir,
const std::string& cacheDir,
Ptr<IShaderFactory> factory);
/**
* @brief Shader系统
*/
void shutdown();
/**
* @brief
* @return truefalse
*/
bool isInitialized() const { return initialized_; }
/**
* @brief
* Switch平台使用romfs
* @return true
*/
bool isHotReloadSupported() const { return hotReloadSupported_; }
// ------------------------------------------------------------------------
// Shader加载
// ------------------------------------------------------------------------
/**
* @brief Shader
* @param name Shader名称
* @param vertPath
* @param fragPath
* @return Shader实例
*/
Ptr<IShader> loadFromFiles(const std::string& name,
const std::string& vertPath,
const std::string& fragPath);
/**
* @brief Shader
* @param path Shader文件路径
* @return Shader实例
*/
Ptr<IShader> loadFromCombinedFile(const std::string& path);
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> loadFromSource(const std::string& name,
const std::string& vertSource,
const std::string& fragSource);
/**
* @brief Shader
* @param name Shader名称
* @return Shader实例nullptr
*/
Ptr<IShader> get(const std::string& name) const;
/**
* @brief Shader是否存在
* @param name Shader名称
* @return truefalse
*/
bool has(const std::string& name) const;
/**
* @brief Shader
* @param name Shader名称
*/
void remove(const std::string& name);
/**
* @brief Shader
*/
void clear();
// ------------------------------------------------------------------------
// 热重载
// ------------------------------------------------------------------------
/**
* @brief
* @param name Shader名称
* @param callback
*/
void setReloadCallback(const std::string& name, ShaderReloadCallback callback);
/**
* @brief /
* @param enabled
*/
void setHotReloadEnabled(bool enabled);
/**
* @brief
* @return truefalse
*/
bool isHotReloadEnabled() const;
/**
* @brief
*/
void update();
/**
* @brief Shader
* @param name Shader名称
* @return truefalse
*/
bool reload(const std::string& name);
// ------------------------------------------------------------------------
// 内置Shader
// ------------------------------------------------------------------------
/**
* @brief Shader
* @param name Shader名称
* @return Shader实例
*/
Ptr<IShader> getBuiltin(const std::string& name);
/**
* @brief Shader
* @return truefalse
*/
bool loadBuiltinShaders();
/**
* @brief JSON元数据文件加载Shader
* @param jsonPath JSON元数据文件路径
* @param name Shader名称
* @return Shader实例
*/
Ptr<IShader> loadFromMetadata(const std::string& jsonPath, const std::string& name);
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/**
* @brief Shader目录
* @return Shader目录路径
*/
const std::string& getShaderDir() const { return shaderDir_; }
/**
* @brief ShaderLoader
* @return ShaderLoader引用
*/
ShaderLoader& getLoader() { return loader_; }
private:
ShaderManager() = default;
~ShaderManager() = default;
ShaderManager(const ShaderManager&) = delete;
ShaderManager& operator=(const ShaderManager&) = delete;
std::string shaderDir_;
std::string cacheDir_;
Ptr<IShaderFactory> factory_;
ShaderLoader loader_;
struct ShaderInfo {
Ptr<IShader> shader;
ShaderMetadata metadata;
ShaderReloadCallback reloadCallback;
std::string vertSource;
std::string fragSource;
std::vector<std::string> filePaths;
};
std::unordered_map<std::string, ShaderInfo> shaders_;
bool initialized_ = false;
bool hotReloadEnabled_ = false;
bool hotReloadSupported_ = true;
/**
* @brief Shader
* @param name Shader名称
* @param sourceHash
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> loadFromCache(const std::string& name,
const std::string& sourceHash,
const std::string& vertSource,
const std::string& fragSource);
/**
* @brief Shader源码
*/
void createBuiltinShaderSources();
/**
* @brief
* @param shaderName Shader名称
* @param event
*/
void handleFileChange(const std::string& shaderName, const FileChangeEvent& event);
};
// 便捷宏
#define E2D_SHADER_MANAGER() ::extra2d::ShaderManager::getInstance()
} // namespace extra2d

View File

@ -1,112 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/shader/shader_interface.h>
#include <glm/vec4.hpp>
namespace extra2d {
struct WaterParams {
float waveSpeed = 1.0f;
float waveAmplitude = 0.02f;
float waveFrequency = 4.0f;
};
struct OutlineParams {
Color color = Colors::Black;
float thickness = 2.0f;
};
struct DistortionParams {
float distortionAmount = 0.02f;
float timeScale = 1.0f;
};
struct PixelateParams {
float pixelSize = 8.0f;
};
struct InvertParams {
float strength = 1.0f;
};
struct GrayscaleParams {
float intensity = 1.0f;
};
struct BlurParams {
float radius = 5.0f;
};
class ShaderPreset {
public:
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Water(const WaterParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Outline(const OutlineParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Distortion(const DistortionParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Pixelate(const PixelateParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Invert(const InvertParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Grayscale(const GrayscaleParams& params = {});
/**
* @brief
* @param params
* @return
*/
static Ptr<IShader> Blur(const BlurParams& params = {});
/**
* @brief +
* @param grayParams
* @param outlineParams
* @return
*/
static Ptr<IShader> GrayscaleOutline(const GrayscaleParams& grayParams,
const OutlineParams& outlineParams);
/**
* @brief +
* @param pixParams
* @param invParams
* @return
*/
static Ptr<IShader> PixelateInvert(const PixelateParams& pixParams,
const InvertParams& invParams);
};
} // namespace extra2d

View File

@ -1,49 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <vector>
namespace extra2d {
// ============================================================================
// Alpha 遮罩 - 存储图片的非透明区域信息
// ============================================================================
class AlphaMask {
public:
AlphaMask() = default;
AlphaMask(int width, int height);
/// 从像素数据创建遮罩
static AlphaMask createFromPixels(const uint8_t *pixels, int width,
int height, int channels);
/// 获取指定位置的透明度0-255
uint8_t getAlpha(int x, int y) const;
/// 检查指定位置是否不透明
bool isOpaque(int x, int y, uint8_t threshold = 128) const;
/// 检查指定位置是否在遮罩范围内
bool isValid(int x, int y) const;
/// 获取遮罩尺寸
int getWidth() const { return width_; }
int getHeight() const { return height_; }
Size getSize() const {
return Size(static_cast<float>(width_), static_cast<float>(height_));
}
/// 获取原始数据
const std::vector<uint8_t> &getData() const { return data_; }
/// 检查遮罩是否有效
bool isValid() const { return !data_.empty() && width_ > 0 && height_ > 0; }
private:
int width_ = 0;
int height_ = 0;
std::vector<uint8_t> data_; // Alpha值数组
};
} // namespace extra2d

View File

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

View File

@ -1,64 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/core/math_types.h>
namespace extra2d {
// ============================================================================
// 像素格式枚举
// ============================================================================
enum class PixelFormat {
R8, // 单通道灰度
RG8, // 双通道
RGB8, // RGB 24位
RGBA8, // RGBA 32位默认
RGB16F, // RGB 半精度浮点
RGBA16F, // RGBA 半精度浮点
RGB32F, // RGB 全精度浮点
RGBA32F, // RGBA 全精度浮点
Depth16, // 16位深度
Depth24, // 24位深度
Depth32F, // 32位浮点深度
Depth24Stencil8, // 24位深度 + 8位模板
// 压缩纹理格式
ETC2_RGB8, // ETC2 RGB 压缩
ETC2_RGBA8, // ETC2 RGBA 压缩
ASTC_4x4, // ASTC 4x4 压缩
ASTC_6x6, // ASTC 6x6 压缩
ASTC_8x8 // ASTC 8x8 压缩
};
// ============================================================================
// 纹理接口
// ============================================================================
class Texture {
public:
virtual ~Texture() = default;
// 获取尺寸
virtual int getWidth() const = 0;
virtual int getHeight() const = 0;
virtual Size getSize() const = 0;
// 获取通道数
virtual int getChannels() const = 0;
// 获取像素格式
virtual PixelFormat getFormat() const = 0;
// 获取原始句柄(用于底层渲染)
virtual void* getNativeHandle() const = 0;
// 是否有效
virtual bool isValid() const = 0;
// 设置过滤模式
virtual void setFilter(bool linear) = 0;
// 设置环绕模式
virtual void setWrap(bool repeat) = 0;
};
} // namespace extra2d

View File

@ -1,184 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
namespace extra2d {
// ============================================================================
// 纹理图集 - 自动将小纹理合并到大图集以减少 DrawCall
// ============================================================================
/**
* @brief
*/
struct AtlasEntry {
std::string name; // 原始纹理名称/路径
Rect uvRect; // 在图集中的 UV 坐标范围
Vec2 originalSize; // 原始纹理尺寸
uint32_t padding; // 边距(用于避免纹理 bleeding
AtlasEntry() : uvRect(), originalSize(), padding(2) {}
};
/**
* @brief
*
*/
class TextureAtlasPage {
public:
static constexpr int DEFAULT_SIZE = 2048;
static constexpr int MAX_SIZE = 4096;
static constexpr int MIN_TEXTURE_SIZE = 32; // 小于此大小的纹理才考虑合并
static constexpr int PADDING = 2; // 纹理间边距
TextureAtlasPage(int width = DEFAULT_SIZE, int height = DEFAULT_SIZE);
~TextureAtlasPage();
// 尝试添加纹理到图集
// 返回是否成功,如果成功则输出 uvRect
bool tryAddTexture(const std::string& name, int texWidth, int texHeight,
const uint8_t* pixels, Rect& outUvRect);
// 获取图集纹理
Ptr<Texture> getTexture() const { return texture_; }
// 获取条目
const AtlasEntry* getEntry(const std::string& name) const;
// 获取使用率
float getUsageRatio() const;
// 获取尺寸
int getWidth() const { return width_; }
int getHeight() const { return height_; }
// 是否已满
bool isFull() const { return isFull_; }
private:
int width_, height_;
Ptr<Texture> texture_;
std::unordered_map<std::string, AtlasEntry> entries_;
// 矩形打包数据
struct PackNode {
int x, y, width, height;
bool used;
std::unique_ptr<PackNode> left;
std::unique_ptr<PackNode> right;
PackNode(int x_, int y_, int w, int h)
: x(x_), y(y_), width(w), height(h), used(false) {}
};
std::unique_ptr<PackNode> root_;
bool isFull_;
int usedArea_;
// 递归插入
PackNode* insert(PackNode* node, int width, int height);
void writePixels(int x, int y, int w, int h, const uint8_t* pixels);
};
/**
* @brief
*
*/
class TextureAtlas {
public:
TextureAtlas();
~TextureAtlas();
// 初始化
void init(int pageSize = TextureAtlasPage::DEFAULT_SIZE);
// 添加纹理到图集
// 如果纹理太大,返回 false应该作为独立纹理加载
bool addTexture(const std::string& name, int width, int height,
const uint8_t* pixels);
// 查询纹理是否在图集中
bool contains(const std::string& name) const;
// 获取纹理在图集中的信息
// 返回图集纹理和 UV 坐标
const Texture* getAtlasTexture(const std::string& name) const;
Rect getUVRect(const std::string& name) const;
// 获取原始纹理尺寸
Vec2 getOriginalSize(const std::string& name) const;
// 获取所有图集页面
const std::vector<std::unique_ptr<TextureAtlasPage>>& getPages() const { return pages_; }
// 获取总使用率
float getTotalUsageRatio() const;
// 清空所有图集
void clear();
// 设置是否启用自动图集
void setEnabled(bool enabled) { enabled_ = enabled; }
bool isEnabled() const { return enabled_; }
// 设置纹理大小阈值(小于此大小的纹理才进入图集)
void setSizeThreshold(int threshold) { sizeThreshold_ = threshold; }
int getSizeThreshold() const { return sizeThreshold_; }
private:
std::vector<std::unique_ptr<TextureAtlasPage>> pages_;
std::unordered_map<std::string, TextureAtlasPage*> entryToPage_;
int pageSize_;
int sizeThreshold_;
bool enabled_;
bool initialized_;
};
/**
* @brief
*/
class TextureAtlasMgr {
public:
static TextureAtlasMgr& get();
// 获取主图集
TextureAtlas& getAtlas() { return atlas_; }
// 快捷方法
bool addTexture(const std::string& name, int width, int height,
const uint8_t* pixels) {
return atlas_.addTexture(name, width, height, pixels);
}
bool contains(const std::string& name) const {
return atlas_.contains(name);
}
const Texture* getAtlasTexture(const std::string& name) const {
return atlas_.getAtlasTexture(name);
}
Rect getUVRect(const std::string& name) const {
return atlas_.getUVRect(name);
}
private:
TextureAtlasMgr() = default;
~TextureAtlasMgr() = default;
TextureAtlasMgr(const TextureAtlasMgr&) = delete;
TextureAtlasMgr& operator=(const TextureAtlasMgr&) = delete;
TextureAtlas atlas_;
};
} // namespace extra2d

View File

@ -1,561 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/utils/logger.h>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
namespace extra2d {
// 前向声明
class Scene;
class RenderBackend;
// ============================================================================
// 纹理加载选项
// ============================================================================
struct TextureLoadOptions {
bool generateMipmaps = true; // 是否生成 mipmaps
bool sRGB = true; // 是否使用 sRGB 色彩空间
bool premultiplyAlpha = false; // 是否预乘 Alpha
PixelFormat preferredFormat = PixelFormat::RGBA8; // 首选像素格式
};
// ============================================================================
// 纹理键 - 用于唯一标识纹理缓存条目
// ============================================================================
struct TextureKey {
std::string path; // 纹理文件路径
Rect region; // 纹理区域(用于纹理图集)
/**
* @brief
*/
TextureKey() = default;
/**
* @brief
* @param p
*/
explicit TextureKey(const std::string &p) : path(p), region(Rect::Zero()) {}
/**
* @brief +
* @param p
* @param r
*/
TextureKey(const std::string &p, const Rect &r) : path(p), region(r) {}
/**
* @brief
* @param other TextureKey
* @return
*/
bool operator==(const TextureKey &other) const {
return path == other.path && region == other.region;
}
/**
* @brief
* @param other TextureKey
* @return
*/
bool operator!=(const TextureKey &other) const { return !(*this == other); }
};
// ============================================================================
// TextureKey 哈希函子
// ============================================================================
struct TextureKeyHash {
/**
* @brief TextureKey
* @param key
* @return
*/
size_t operator()(const TextureKey &key) const {
size_t h1 = std::hash<std::string>{}(key.path);
size_t h2 = std::hash<float>{}(key.region.origin.x);
size_t h3 = std::hash<float>{}(key.region.origin.y);
size_t h4 = std::hash<float>{}(key.region.size.width);
size_t h5 = std::hash<float>{}(key.region.size.height);
// 组合哈希值
size_t result = h1;
result ^= h2 + 0x9e3779b9 + (result << 6) + (result >> 2);
result ^= h3 + 0x9e3779b9 + (result << 6) + (result >> 2);
result ^= h4 + 0x9e3779b9 + (result << 6) + (result >> 2);
result ^= h5 + 0x9e3779b9 + (result << 6) + (result >> 2);
return result;
}
};
// ============================================================================
// 纹理池条目
// ============================================================================
struct TexturePoolEntry {
Ptr<Texture> texture; // 纹理对象
mutable std::atomic<uint32_t> refCount; // 引用计数
TextureKey key; // 纹理键
size_t memorySize; // 内存占用(字节)
mutable uint64_t lastAccessTime; // 最后访问时间戳
/**
* @brief
*/
TexturePoolEntry()
: texture(nullptr), refCount(0), key(), memorySize(0), lastAccessTime(0) {
}
/**
* @brief
* @param tex
* @param k
* @param memSize
*/
TexturePoolEntry(Ptr<Texture> tex, const TextureKey &k, size_t memSize)
: texture(tex), refCount(1), key(k), memorySize(memSize),
lastAccessTime(getCurrentTime()) {}
/**
* @brief
* @param other
*/
TexturePoolEntry(TexturePoolEntry &&other) noexcept
: texture(std::move(other.texture)),
refCount(other.refCount.load(std::memory_order_relaxed)),
key(std::move(other.key)), memorySize(other.memorySize),
lastAccessTime(other.lastAccessTime) {}
/**
* @brief
* @param other
* @return
*/
TexturePoolEntry &operator=(TexturePoolEntry &&other) noexcept {
if (this != &other) {
texture = std::move(other.texture);
refCount.store(other.refCount.load(std::memory_order_relaxed),
std::memory_order_relaxed);
key = std::move(other.key);
memorySize = other.memorySize;
lastAccessTime = other.lastAccessTime;
}
return *this;
}
// 禁止拷贝
TexturePoolEntry(const TexturePoolEntry &) = delete;
TexturePoolEntry &operator=(const TexturePoolEntry &) = delete;
/**
* @brief 访
*/
void touch() const { lastAccessTime = getCurrentTime(); }
/**
* @brief
* @return
*/
static uint64_t getCurrentTime() {
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch());
return static_cast<uint64_t>(duration.count());
}
};
// ============================================================================
// 纹理引用智能指针 - 自动管理纹理池引用计数
// ============================================================================
class TextureRef {
public:
/**
* @brief
*/
TextureRef() : texture_(nullptr), entry_(nullptr), mutex_(nullptr) {}
/**
* @brief
* @param texture
* @param entry
* @param mutex
*/
TextureRef(Ptr<Texture> texture, TexturePoolEntry *entry, std::mutex *mutex)
: texture_(texture), entry_(entry), mutex_(mutex) {}
/**
* @brief
* @param texture
* @return
*/
static TextureRef fromTexture(Ptr<Texture> texture) {
return TextureRef(texture, nullptr, nullptr);
}
/**
* @brief
* @param other TextureRef
*/
TextureRef(const TextureRef &other)
: texture_(other.texture_), entry_(other.entry_), mutex_(other.mutex_) {
if (entry_ && entry_->refCount.load(std::memory_order_relaxed) > 0) {
entry_->refCount.fetch_add(1, std::memory_order_relaxed);
}
}
/**
* @brief
* @param other TextureRef
*/
TextureRef(TextureRef &&other) noexcept
: texture_(std::move(other.texture_)), entry_(other.entry_),
mutex_(other.mutex_) {
other.entry_ = nullptr;
other.mutex_ = nullptr;
}
/**
* @brief
*/
~TextureRef() { reset(); }
/**
* @brief
* @param other TextureRef
* @return
*/
TextureRef &operator=(const TextureRef &other) {
if (this != &other) {
reset();
texture_ = other.texture_;
entry_ = other.entry_;
mutex_ = other.mutex_;
if (entry_ && entry_->refCount.load(std::memory_order_relaxed) > 0) {
entry_->refCount.fetch_add(1, std::memory_order_relaxed);
}
}
return *this;
}
/**
* @brief
* @param other TextureRef
* @return
*/
TextureRef &operator=(TextureRef &&other) noexcept {
if (this != &other) {
reset();
texture_ = std::move(other.texture_);
entry_ = other.entry_;
mutex_ = other.mutex_;
other.entry_ = nullptr;
other.mutex_ = nullptr;
}
return *this;
}
/**
* @brief
*/
void reset() {
if (entry_ && mutex_) {
std::lock_guard<std::mutex> lock(*mutex_);
if (entry_->refCount.load(std::memory_order_relaxed) > 0) {
entry_->refCount.fetch_sub(1, std::memory_order_relaxed);
}
}
texture_.reset();
entry_ = nullptr;
mutex_ = nullptr;
}
/**
* @brief
* @return
*/
Texture *get() const { return texture_.get(); }
/**
* @brief
* @return
*/
Ptr<Texture> getPtr() const { return texture_; }
/**
* @brief
* @return
*/
bool valid() const { return texture_ != nullptr; }
/**
* @brief
*/
explicit operator bool() const { return valid(); }
/**
* @brief
*/
Texture *operator->() const { return texture_.get(); }
/**
* @brief
*/
Texture &operator*() const { return *texture_; }
private:
Ptr<Texture> texture_;
TexturePoolEntry *entry_;
std::mutex *mutex_;
};
// ============================================================================
// 纹理池 - 纹理缓存和内存管理系统
// 特性:
// - 纹理缓存和复用
// - 引用计数管理
// - 内存使用限制
// - LRU 淘汰策略
// - 线程安全
// ============================================================================
class TexturePool {
public:
// ========================================================================
// 统计信息
// ========================================================================
struct Stats {
size_t textureCount = 0; // 纹理数量
size_t memoryUsage = 0; // 内存使用量(字节)
size_t maxMemoryUsage = 0; // 最大内存使用量
size_t cacheHits = 0; // 缓存命中次数
size_t cacheMisses = 0; // 缓存未命中次数
size_t evictionCount = 0; // 淘汰次数
};
// ========================================================================
// 构造和析构
// ========================================================================
/**
* @brief
*/
TexturePool();
/**
* @brief
* @param scene
* @param maxMemoryUsage 使0
*/
explicit TexturePool(Scene *scene, size_t maxMemoryUsage = 0);
/**
* @brief
*/
~TexturePool();
// 禁止拷贝
TexturePool(const TexturePool &) = delete;
TexturePool &operator=(const TexturePool &) = delete;
/**
* @brief
* @param scene
* @param maxMemoryUsage 使0
*/
void init(Scene *scene, size_t maxMemoryUsage = 0);
// ========================================================================
// 纹理加载
// ========================================================================
/**
* @brief
* @param path
* @param options
* @return
*/
TextureRef load(const std::string &path,
const TextureLoadOptions &options = TextureLoadOptions());
/**
* @brief
* @param path
* @param region
* @param options
* @return
*/
TextureRef load(const std::string &path, const Rect &region,
const TextureLoadOptions &options = TextureLoadOptions());
/**
* @brief
* @param data
* @param width
* @param height
* @param channels
* @param key
* @return
*/
TextureRef loadFromMemory(const uint8_t *data, int width, int height,
int channels, const std::string &key);
/**
* @brief
* @param path
* @param options
* @return
*/
TextureRef
getOrLoad(const std::string &path,
const TextureLoadOptions &options = TextureLoadOptions());
/**
* @brief
* @param path
* @param region
* @param options
* @return
*/
TextureRef
getOrLoad(const std::string &path, const Rect &region,
const TextureLoadOptions &options = TextureLoadOptions());
// ========================================================================
// 引用计数管理
// ========================================================================
/**
* @brief
* @param key
* @return
*/
bool addRef(const TextureKey &key);
/**
* @brief
* @param key
* @return
*/
uint32_t release(const TextureKey &key);
/**
* @brief
* @param key
* @return
*/
uint32_t getRefCount(const TextureKey &key) const;
// ========================================================================
// 缓存管理
// ========================================================================
/**
* @brief
* @param key
* @return
*/
bool isCached(const TextureKey &key) const;
/**
* @brief
* @param key
* @return
*/
bool removeFromCache(const TextureKey &key);
/**
* @brief 0
* @return
*/
size_t collectGarbage();
/**
* @brief
*/
void clear();
// ========================================================================
// 内存管理
// ========================================================================
/**
* @brief 使
* @return 使
*/
size_t getMemoryUsage() const;
/**
* @brief 使
* @param maxMemory 使0
*/
void setMaxMemoryUsage(size_t maxMemory);
/**
* @brief 使
* @return 使
*/
size_t getMaxMemoryUsage() const { return maxMemoryUsage_; }
/**
* @brief LRU
* @param targetMemory 使
* @return
*/
size_t evictLRU(size_t targetMemory = 0);
// ========================================================================
// 统计信息
// ========================================================================
/**
* @brief
* @return
*/
Stats getStats() const;
/**
* @brief
*/
void resetStats();
private:
/**
* @brief
* @param texture
* @return
*/
static size_t calculateTextureMemory(const Texture *texture);
/**
* @brief
* @return
*/
bool needsEviction() const;
/**
* @brief
*/
void tryAutoEvict();
Scene *scene_; // 场景指针
mutable std::mutex mutex_; // 互斥锁
std::unordered_map<TextureKey, TexturePoolEntry, TextureKeyHash>
cache_; // 纹理缓存
size_t maxMemoryUsage_; // 最大内存使用量
size_t currentMemoryUsage_; // 当前内存使用量
// 统计信息
mutable std::atomic<size_t> cacheHits_;
mutable std::atomic<size_t> cacheMisses_;
mutable std::atomic<size_t> evictionCount_;
};
} // namespace extra2d

View File

@ -1,88 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/platform/iwindow.h>
#include <extra2d/platform/iinput.h>
#include <functional>
#include <unordered_map>
#include <vector>
#include <string>
namespace extra2d {
/**
* @brief
*
*/
class BackendFactory {
public:
using WindowFn = std::function<UniquePtr<IWindow>()>;
using InputFn = std::function<UniquePtr<IInput>()>;
/**
* @brief
* @param name
* @param win
* @param in
*/
static void reg(const std::string& name, WindowFn win, InputFn in);
/**
* @brief
* @param name
* @return nullptr
*/
static UniquePtr<IWindow> createWindow(const std::string& name);
/**
* @brief
* @param name
* @return nullptr
*/
static UniquePtr<IInput> createInput(const std::string& name);
/**
* @brief
*/
static std::vector<std::string> backends();
/**
* @brief
*/
static bool has(const std::string& name);
private:
struct BackendEntry {
WindowFn windowFn;
InputFn inputFn;
};
static std::unordered_map<std::string, BackendEntry>& registry();
};
/**
* @brief
* 使
*
* @example
* E2D_REG_BACKEND(sdl2, SDL2Window, SDL2Input)
*/
#define E2D_REG_BACKEND(name, WinClass, InClass) \
namespace { \
__attribute__((used)) \
static struct E2D_BACKEND_REG_##name { \
E2D_BACKEND_REG_##name() { \
::extra2d::BackendFactory::reg( \
#name, \
[]() -> ::extra2d::UniquePtr<::extra2d::IWindow> { \
return ::extra2d::makeUnique<WinClass>(); \
}, \
[]() -> ::extra2d::UniquePtr<::extra2d::IInput> { \
return ::extra2d::makeUnique<InClass>(); \
} \
); \
} \
} e2d_backend_reg_##name; \
}
} // namespace extra2d

View File

@ -1,175 +0,0 @@
#pragma once
#include <extra2d/platform/keys.h>
#include <extra2d/core/math_types.h>
namespace extra2d {
/**
* @brief
*/
struct TouchPoint {
int id = 0;
Vec2 position;
Vec2 delta;
bool pressed = false;
bool released = false;
};
/**
* @brief
*
*/
class IInput {
public:
virtual ~IInput() = default;
/**
* @brief
*/
virtual void init() = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
*/
virtual void update() = 0;
// ========== 键盘 ==========
/**
* @brief
*/
virtual bool down(Key key) const = 0;
/**
* @brief
*/
virtual bool pressed(Key key) const = 0;
/**
* @brief
*/
virtual bool released(Key key) const = 0;
// ========== 鼠标 ==========
/**
* @brief
*/
virtual bool down(Mouse btn) const = 0;
/**
* @brief
*/
virtual bool pressed(Mouse btn) const = 0;
/**
* @brief
*/
virtual bool released(Mouse btn) const = 0;
/**
* @brief
*/
virtual Vec2 mouse() const = 0;
/**
* @brief
*/
virtual Vec2 mouseDelta() const = 0;
/**
* @brief
*/
virtual float scroll() const = 0;
/**
* @brief
*/
virtual float scrollDelta() const = 0;
/**
* @brief
*/
virtual void setMouse(const Vec2& pos) = 0;
// ========== 手柄 ==========
/**
* @brief
*/
virtual bool gamepad() const = 0;
/**
* @brief
*/
virtual bool down(Gamepad btn) const = 0;
/**
* @brief
*/
virtual bool pressed(Gamepad btn) const = 0;
/**
* @brief
*/
virtual bool released(Gamepad btn) const = 0;
/**
* @brief
*/
virtual Vec2 leftStick() const = 0;
/**
* @brief
*/
virtual Vec2 rightStick() const = 0;
/**
* @brief
*/
virtual float leftTrigger() const = 0;
/**
* @brief
*/
virtual float rightTrigger() const = 0;
/**
* @brief
* @param left [0, 1]
* @param right [0, 1]
*/
virtual void vibrate(float left, float right) = 0;
// ========== 触摸 ==========
/**
* @brief
*/
virtual bool touching() const = 0;
/**
* @brief
*/
virtual int touchCount() const = 0;
/**
* @brief
* @param index
*/
virtual Vec2 touch(int index) const = 0;
/**
* @brief
* @param index
*/
virtual TouchPoint touchPoint(int index) const = 0;
};
} // namespace extra2d

View File

@ -1,78 +0,0 @@
#pragma once
#include <extra2d/core/module.h>
#include <extra2d/platform/iinput.h>
#include <extra2d/platform/window_module.h>
#include <functional>
#include <typeindex>
namespace extra2d {
/**
* @brief
*/
struct InputCfg {
float deadzone;
float mouseSensitivity;
bool enableVibration;
int maxGamepads;
int priority;
InputCfg()
: deadzone(0.15f)
, mouseSensitivity(1.0f)
, enableVibration(true)
, maxGamepads(4)
, priority(20)
{}
};
/**
* @brief
*
*/
class InputModule : public Module {
public:
/**
* @brief Lambda
* @param configFn
*/
explicit InputModule(std::function<void(InputCfg&)> configFn);
/**
* @brief
*/
~InputModule() override;
bool init() override;
void shutdown() override;
bool ok() const override { return initialized_; }
const char* name() const override { return "input"; }
int priority() const override { return cfg_.priority; }
/**
* @brief
* @return
*/
std::vector<std::type_index> deps() const override {
return {std::type_index(typeid(WindowModule))};
}
/**
* @brief
* @return
*/
IInput* input() const { return input_; }
/**
* @brief
*/
void update();
private:
InputCfg cfg_;
IInput* input_ = nullptr;
bool initialized_ = false;
};
} // namespace extra2d

View File

@ -1,202 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/core/math_types.h>
#include <extra2d/platform/window_config.h>
#include <functional>
#include <string>
namespace extra2d {
class IInput;
/**
* @brief
*/
enum class Cursor {
Arrow,
IBeam,
Crosshair,
Hand,
HResize,
VResize,
Hidden
};
/**
* @brief
*
*/
class IWindow {
public:
virtual ~IWindow() = default;
/**
* @brief
* @param cfg
* @return
*/
virtual bool create(const WindowConfigData& cfg) = 0;
/**
* @brief
*/
virtual void destroy() = 0;
/**
* @brief
*/
virtual void poll() = 0;
/**
* @brief
*/
virtual void swap() = 0;
/**
* @brief
*/
virtual bool shouldClose() const = 0;
/**
* @brief
*/
virtual void close() = 0;
/**
* @brief
*/
virtual void setTitle(const std::string& title) = 0;
/**
* @brief
*/
virtual void setSize(int w, int h) = 0;
/**
* @brief
*/
virtual void setPos(int x, int y) = 0;
/**
* @brief
*/
virtual void setFullscreen(bool fs) = 0;
/**
* @brief
*/
virtual void setVSync(bool vsync) = 0;
/**
* @brief
*/
virtual void setVisible(bool visible) = 0;
/**
* @brief
*/
virtual int width() const = 0;
/**
* @brief
*/
virtual int height() const = 0;
/**
* @brief
*/
virtual Size size() const = 0;
/**
* @brief
*/
virtual Vec2 pos() const = 0;
/**
* @brief
*/
virtual bool fullscreen() const = 0;
/**
* @brief
*/
virtual bool vsync() const = 0;
/**
* @brief
*/
virtual bool focused() const = 0;
/**
* @brief
*/
virtual bool minimized() const = 0;
/**
* @brief X
*/
virtual float scaleX() const = 0;
/**
* @brief Y
*/
virtual float scaleY() const = 0;
/**
* @brief
*/
virtual void setCursor(Cursor cursor) = 0;
/**
* @brief /
*/
virtual void showCursor(bool show) = 0;
/**
* @brief /
*/
virtual void lockCursor(bool lock) = 0;
/**
* @brief
*/
virtual IInput* input() const = 0;
/**
* @brief
*/
using ResizeCb = std::function<void(int, int)>;
/**
* @brief
*/
using CloseCb = std::function<void()>;
/**
* @brief
*/
using FocusCb = std::function<void(bool)>;
/**
* @brief
*/
virtual void onResize(ResizeCb cb) = 0;
/**
* @brief
*/
virtual void onClose(CloseCb cb) = 0;
/**
* @brief
*/
virtual void onFocus(FocusCb cb) = 0;
/**
* @brief
*/
virtual void* native() const = 0;
};
} // namespace extra2d

View File

@ -1,72 +0,0 @@
#pragma once
namespace extra2d {
/**
* @brief
*/
enum class Key : int {
None = 0,
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
Num0, Num1, Num2, Num3, Num4,
Num5, Num6, Num7, Num8, Num9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
Space, Enter, Escape, Tab, Backspace,
Insert, Delete, Home, End, PageUp, PageDown,
Up, Down, Left, Right,
LShift, RShift, LCtrl, RCtrl, LAlt, RAlt,
CapsLock, NumLock, ScrollLock,
Count
};
/**
* @brief
*/
enum class Mouse : int {
Left = 0,
Right,
Middle,
X1,
X2,
Count
};
/**
* @brief
*/
enum class Gamepad : int {
A = 0,
B,
X,
Y,
LB,
RB,
LT,
RT,
Back,
Start,
Guide,
LStick,
RStick,
DUp,
DDown,
DLeft,
DRight,
Count
};
/**
* @brief
*/
enum class GamepadAxis : int {
LeftX = 0,
LeftY,
RightX,
RightY,
LeftTrigger,
RightTrigger,
Count
};
} // namespace extra2d

View File

@ -1,84 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <string>
namespace extra2d {
/**
* @file window_config.h
* @brief
*
* WindowModule
*/
/**
* @brief
*/
enum class WindowMode {
Windowed,
Fullscreen,
Borderless
};
/**
* @brief
*/
struct WindowConfigData {
std::string title = "Extra2D Application";
int width = 1280;
int height = 720;
int minWidth = 320;
int minHeight = 240;
int maxWidth = 0;
int maxHeight = 0;
WindowMode mode = WindowMode::Windowed;
bool resizable = true;
bool borderless = false;
bool alwaysOnTop = false;
bool centered = true;
int posX = -1;
int posY = -1;
bool hideOnClose = false;
bool minimizeOnClose = true;
float opacity = 1.0f;
bool transparentFramebuffer = false;
bool highDPI = true;
float contentScale = 1.0f;
bool vsync = true;
int multisamples = 0;
bool visible = true;
bool decorated = true;
/**
* @brief
* @return 0 true
*/
bool isSizeValid() const { return width > 0 && height > 0; }
/**
* @brief
* @return true
*/
bool hasPosition() const { return posX >= 0 && posY >= 0; }
/**
* @brief
* @return
*/
float aspectRatio() const { return static_cast<float>(width) / static_cast<float>(height); }
/**
* @brief
* @return true
*/
bool isFullscreen() const { return mode == WindowMode::Fullscreen; }
/**
* @brief
* @return true
*/
bool isBorderless() const { return mode == WindowMode::Borderless || borderless; }
};
}

View File

@ -1,64 +0,0 @@
#pragma once
#include <extra2d/core/module.h>
#include <extra2d/platform/iwindow.h>
#include <extra2d/platform/window_config.h>
#include <functional>
#include <string>
namespace extra2d {
/**
* @brief
*/
struct WindowCfg {
std::string title;
int w;
int h;
WindowMode mode;
bool vsync;
int priority;
std::string backend;
WindowCfg()
: title("Extra2D"), w(1280), h(720), mode(WindowMode::Windowed),
vsync(true), priority(0), backend("sdl2") {}
};
/**
* @brief
*
*/
class WindowModule : public Module {
public:
/**
* @brief Lambda
* @param configFn
*/
explicit WindowModule(std::function<void(WindowCfg &)> configFn);
/**
* @brief
*/
~WindowModule() override;
bool init() override;
void shutdown() override;
bool ok() const override { return initialized_; }
const char *name() const override { return "window"; }
int priority() const override { return cfg_.priority; }
/**
* @brief
* @return
*/
IWindow *win() const { return win_.get(); }
private:
WindowCfg cfg_;
UniquePtr<IWindow> win_;
bool initialized_ = false;
bool sdlInited_ = false;
};
} // namespace extra2d

View File

@ -1,239 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/graphics/core/render_backend.h>
#include <memory>
#include <string>
#include <vector>
namespace extra2d {
// 前向声明
class Scene;
class RenderBackend;
struct RenderCommand;
// ============================================================================
// 节点基类 - 场景图的基础
// ============================================================================
class Node : public std::enable_shared_from_this<Node> {
public:
Node();
virtual ~Node();
// ------------------------------------------------------------------------
// 层级管理
// ------------------------------------------------------------------------
void addChild(Ptr<Node> child);
/**
* @brief
* @param children
*/
void addChildren(std::vector<Ptr<Node>> &&children);
void removeChild(Ptr<Node> child);
void removeChildByName(const std::string &name);
void detach();
void clearChildren();
Ptr<Node> getParent() const { return parent_.lock(); }
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
Ptr<Node> findChild(const std::string &name) const;
Ptr<Node> findChildByTag(int tag) const;
// ------------------------------------------------------------------------
// 变换属性
// ------------------------------------------------------------------------
void setPos(const Vec2 &pos);
void setPos(float x, float y);
Vec2 getPosition() const { return position_; }
void setRotation(float degrees);
float getRotation() const { return rotation_; }
void setScale(const Vec2 &scale);
void setScale(float scale);
void setScale(float x, float y);
Vec2 getScale() const { return scale_; }
void setAnchor(const Vec2 &anchor);
void setAnchor(float x, float y);
Vec2 getAnchor() const { return anchor_; }
void setSkew(const Vec2 &skew);
void setSkew(float x, float y);
Vec2 getSkew() const { return skew_; }
void setOpacity(float opacity);
float getOpacity() const { return opacity_; }
void setVisible(bool visible);
bool isVisible() const { return visible_; }
/**
* @brief
* @param color RGB颜色
*/
void setColor(const Color3B &color);
Color3B getColor() const { return color_; }
/**
* @brief X轴翻转
*/
void setFlipX(bool flipX);
bool isFlipX() const { return flipX_; }
/**
* @brief Y轴翻转
*/
void setFlipY(bool flipY);
bool isFlipY() const { return flipY_; }
void setZOrder(int zOrder);
int getZOrder() const { return zOrder_; }
// ------------------------------------------------------------------------
// 世界变换
// ------------------------------------------------------------------------
Vec2 toWorld(const Vec2 &localPos) const;
Vec2 toLocal(const Vec2 &worldPos) const;
glm::mat4 getLocalTransform() const;
glm::mat4 getWorldTransform() const;
/**
* @brief
*/
void markTransformDirty();
/**
* @brief
*
*/
void batchTransforms();
/**
* @brief
*/
bool isTransformDirty() const { return transformDirty_; }
bool isWorldTransformDirty() const { return worldTransformDirty_; }
// ------------------------------------------------------------------------
// 名称和标签
// ------------------------------------------------------------------------
void setName(const std::string &name) { name_ = name; }
const std::string &getName() const { return name_; }
void setTag(int tag) { tag_ = tag; }
int getTag() const { return tag_; }
// ------------------------------------------------------------------------
// 生命周期回调
// ------------------------------------------------------------------------
virtual void onEnter();
virtual void onExit();
virtual void onUpdate(float dt);
virtual void onRender(RenderBackend &renderer);
virtual void onAttachToScene(Scene *scene);
virtual void onDetachFromScene();
// ------------------------------------------------------------------------
// 边界框
// ------------------------------------------------------------------------
virtual Rect getBounds() const;
// ------------------------------------------------------------------------
// 事件系统
// ------------------------------------------------------------------------
EventDispatcher &getEventDispatcher() { return eventDispatcher_; }
// ------------------------------------------------------------------------
// 内部方法
// ------------------------------------------------------------------------
void update(float dt);
void render(RenderBackend &renderer);
void sortChildren();
bool isRunning() const { return running_; }
Scene *getScene() const { return scene_; }
// 多线程渲染命令收集
virtual void collectRenderCommands(std::vector<RenderCommand> &commands,
int parentZOrder = 0);
protected:
// 子类重写
virtual void onDraw(RenderBackend &renderer) {}
virtual void onUpdateNode(float dt) {}
virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) {};
// 供子类访问的内部状态
Vec2 &getPositionRef() { return position_; }
Vec2 &getScaleRef() { return scale_; }
Vec2 &getAnchorRef() { return anchor_; }
float getRotationRef() { return rotation_; }
float getOpacityRef() { return opacity_; }
private:
// ==========================================================================
// 成员变量按类型大小降序排列,减少内存对齐填充
// 64位系统对齐std::string(32) > glm::mat4(64) > std::vector(24) >
// double(8) > float(4) > int(4) > bool(1)
// ==========================================================================
// 1. 大块内存64字节
mutable glm::mat4 localTransform_; // 64 bytes
mutable glm::mat4 worldTransform_; // 64 bytes
// 2. 字符串和容器24-32字节
std::string name_; // 32 bytes
std::vector<Ptr<Node>> children_; // 24 bytes
// 3. 子节点索引(加速查找)
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_; // 56 bytes
std::unordered_map<int, WeakPtr<Node>> tagIndex_; // 56 bytes
// 4. 事件分发器
EventDispatcher eventDispatcher_; // 大小取决于实现
// 5. 父节点引用
WeakPtr<Node> parent_; // 16 bytes
// 7. 变换属性(按访问频率分组)
Vec2 position_ = Vec2::Zero(); // 8 bytes
Vec2 scale_ = Vec2(1.0f, 1.0f); // 8 bytes
Vec2 anchor_ = Vec2(0.5f, 0.5f); // 8 bytes
Vec2 skew_ = Vec2::Zero(); // 8 bytes
// 8. 浮点属性
float rotation_ = 0.0f; // 4 bytes
float opacity_ = 1.0f; // 4 bytes
// 10. 颜色属性
Color3B color_ = Color3B(255, 255, 255); // 3 bytes
// 11. 整数属性
int zOrder_ = 0; // 4 bytes
int tag_ = -1; // 4 bytes
// 12. 布尔属性
bool flipX_ = false; // 1 byte
bool flipY_ = false; // 1 byte
// 13. 场景指针
Scene *scene_ = nullptr; // 8 bytes
// 14. 布尔标志(打包在一起)
mutable bool transformDirty_ = true; // 1 byte
mutable bool worldTransformDirty_ = true; // 1 byte
bool childrenOrderDirty_ = false; // 1 byte
bool visible_ = true; // 1 byte
bool running_ = false; // 1 byte
};
} // namespace extra2d

View File

@ -1,89 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/scene/node.h>
#include <vector>
namespace extra2d {
// 前向声明
struct RenderCommand;
// ============================================================================
// 场景类 - 节点容器,管理整个场景图
// ============================================================================
class Scene : public Node {
public:
Scene();
~Scene() override = default;
// ------------------------------------------------------------------------
// 场景属性
// ------------------------------------------------------------------------
void setBackgroundColor(const Color &color) { backgroundColor_ = color; }
Color getBackgroundColor() const { return backgroundColor_; }
// ------------------------------------------------------------------------
// 摄像机
// ------------------------------------------------------------------------
void setCamera(Ptr<Camera> camera);
Ptr<Camera> getCamera() const { return camera_; }
Camera *getActiveCamera() const {
return camera_ ? camera_.get() : defaultCamera_.get();
}
// ------------------------------------------------------------------------
// 视口和尺寸
// ------------------------------------------------------------------------
void setViewportSize(float width, float height);
void setViewportSize(const Size &size);
Size getViewportSize() const { return viewportSize_; }
float getWidth() const { return viewportSize_.width; }
float getHeight() const { return viewportSize_.height; }
// ------------------------------------------------------------------------
// 场景状态
// ------------------------------------------------------------------------
bool isPaused() const { return paused_; }
void pause() { paused_ = true; }
void resume() { paused_ = false; }
// ------------------------------------------------------------------------
// 渲染和更新
// ------------------------------------------------------------------------
void renderScene(RenderBackend &renderer);
virtual void renderContent(RenderBackend &renderer);
void updateScene(float dt);
void collectRenderCommands(std::vector<RenderCommand> &commands,
int parentZOrder = 0) override;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<Scene> create();
protected:
void onEnter() override;
void onExit() override;
// 过渡场景生命周期回调(供 TransitionScene 使用)
virtual void onExitTransitionDidStart() {}
virtual void onEnterTransitionDidFinish() {}
friend class SceneManager;
friend class TransitionScene;
private:
Color backgroundColor_ = Colors::Black;
Size viewportSize_ = Size::Zero();
Ptr<Camera> camera_;
Ptr<Camera> defaultCamera_;
bool paused_ = false;
};
} // namespace extra2d

View File

@ -1,175 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/scene/scene.h>
#include <functional>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
struct RenderCommand;
class TransitionScene;
enum class TransitionType;
/**
* @brief -
*/
class SceneManager {
public:
using TransitionCallback = std::function<void()>;
static SceneManager &get();
// ------------------------------------------------------------------------
// 基本场景操作(无过渡效果)
// ------------------------------------------------------------------------
void runWithScene(Ptr<Scene> scene);
void replaceScene(Ptr<Scene> scene);
void pushScene(Ptr<Scene> scene);
void popScene();
void popToRootScene();
void popToScene(const std::string &name);
// ------------------------------------------------------------------------
// 带过渡效果的场景操作
// ------------------------------------------------------------------------
/**
* @brief
* @param scene
* @param transition
* @param duration
*/
void replaceScene(Ptr<Scene> scene, TransitionType transition,
float duration = 0.5f);
/**
* @brief
* @param scene
* @param transition
* @param duration
*/
void pushScene(Ptr<Scene> scene, TransitionType transition,
float duration = 0.5f);
/**
* @brief
* @param transition
* @param duration
*/
void popScene(TransitionType transition, float duration = 0.5f);
/**
* @brief
* @param transition
* @param duration
*/
void popToRootScene(TransitionType transition, float duration = 0.5f);
/**
* @brief
* @param name
* @param transition
* @param duration
*/
void popToScene(const std::string &name, TransitionType transition,
float duration = 0.5f);
/**
* @brief 使
* @param scene
* @param transitionScene
*/
void enterScene(Ptr<Scene> scene, Ptr<TransitionScene> transitionScene);
// ------------------------------------------------------------------------
// 场景查询
// ------------------------------------------------------------------------
Ptr<Scene> getCurrentScene() const;
Ptr<Scene> getPreviousScene() const;
Ptr<Scene> getRootScene() const;
Ptr<Scene> getSceneByName(const std::string &name) const;
size_t getSceneCount() const { return sceneStack_.size(); }
bool isEmpty() const { return sceneStack_.empty(); }
bool hasScene(const std::string &name) const;
// ------------------------------------------------------------------------
// 更新和渲染
// ------------------------------------------------------------------------
void update(float dt);
void render(RenderBackend &renderer);
void collectRenderCommands(std::vector<RenderCommand> &commands);
// ------------------------------------------------------------------------
// 过渡状态
// ------------------------------------------------------------------------
bool isTransitioning() const { return isTransitioning_; }
void setTransitionCallback(TransitionCallback callback) {
transitionCallback_ = callback;
}
void end();
void purgeCachedScenes();
public:
SceneManager() = default;
~SceneManager() = default;
SceneManager(const SceneManager &) = delete;
SceneManager &operator=(const SceneManager &) = delete;
void enterScene(Ptr<Scene> scene);
private:
/**
* @brief
* @param from
* @param to
* @param type
* @param duration
* @param stackAction
*/
void startTransition(Ptr<Scene> from, Ptr<Scene> to, TransitionType type,
float duration, std::function<void()> stackAction);
/**
* @brief
* @param type
* @param duration
* @param inScene
* @return
*/
Ptr<TransitionScene> createTransitionScene(TransitionType type, float duration,
Ptr<Scene> inScene);
/**
* @brief
*/
void finishTransition();
void doSceneSwitch();
void dispatchPointerEvents(Scene &scene);
std::stack<Ptr<Scene>> sceneStack_;
std::unordered_map<std::string, Ptr<Scene>> namedScenes_;
bool isTransitioning_ = false;
TransitionCallback transitionCallback_;
Ptr<Scene> nextScene_;
bool sendCleanupToScene_ = false;
Ptr<TransitionScene> activeTransitionScene_;
std::function<void()> transitionStackAction_;
Node *hoverTarget_ = nullptr;
Node *captureTarget_ = nullptr;
Vec2 lastPointerWorld_ = Vec2::Zero();
bool hasLastPointerWorld_ = false;
};
} // namespace extra2d

View File

@ -1,104 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/scene/node.h>
#include <vector>
namespace extra2d {
// ============================================================================
// 形状类型
// ============================================================================
enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon };
// ============================================================================
// 形状节点 - 用于绘制几何形状
// ============================================================================
class ShapeNode : public Node {
public:
ShapeNode();
~ShapeNode() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<ShapeNode> create();
// 点
static Ptr<ShapeNode> createPoint(const Vec2 &pos, const Color &color);
// 线
static Ptr<ShapeNode> createLine(const Vec2 &start, const Vec2 &end,
const Color &color, float width = 1.0f);
// 矩形
static Ptr<ShapeNode> createRect(const Rect &rect, const Color &color,
float width = 1.0f);
static Ptr<ShapeNode> createFilledRect(const Rect &rect, const Color &color);
// 圆形
static Ptr<ShapeNode> createCircle(const Vec2 &center, float radius,
const Color &color, int segments = 32,
float width = 1.0f);
static Ptr<ShapeNode> createFilledCircle(const Vec2 &center, float radius,
const Color &color,
int segments = 32);
// 三角形
static Ptr<ShapeNode> createTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Color &color,
float width = 1.0f);
static Ptr<ShapeNode> createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3,
const Color &color);
// 多边形
static Ptr<ShapeNode> createPolygon(const std::vector<Vec2> &points,
const Color &color, float width = 1.0f);
static Ptr<ShapeNode> createFilledPolygon(const std::vector<Vec2> &points,
const Color &color);
// ------------------------------------------------------------------------
// 属性设置
// ------------------------------------------------------------------------
void setShapeType(ShapeType type) { shapeType_ = type; }
ShapeType getShapeType() const { return shapeType_; }
void setColor(const Color &color) { color_ = color; }
Color getColor() const { return color_; }
void setFilled(bool filled) { filled_ = filled; }
bool isFilled() const { return filled_; }
void setLineWidth(float width) { lineWidth_ = width; }
float getLineWidth() const { return lineWidth_; }
void setSegments(int segments) { segments_ = segments; }
int getSegments() const { return segments_; }
// ------------------------------------------------------------------------
// 点设置
// ------------------------------------------------------------------------
void setPoints(const std::vector<Vec2> &points);
const std::vector<Vec2> &getPoints() const { return points_; }
void addPoint(const Vec2 &point);
void clearPoints();
Rect getBounds() const override;
protected:
void onDraw(RenderBackend &renderer) override;
void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) override;
private:
ShapeType shapeType_ = ShapeType::Rect;
Color color_ = Colors::White;
bool filled_ = false;
float lineWidth_ = 1.0f;
int segments_ = 32;
std::vector<Vec2> points_;
};
} // namespace extra2d

View File

@ -1,55 +0,0 @@
#pragma once
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/scene/node.h>
namespace extra2d {
// ============================================================================
// 精灵节点
// ============================================================================
class Sprite : public Node {
public:
Sprite();
explicit Sprite(Ptr<Texture> texture);
~Sprite() override = default;
// 纹理
void setTexture(Ptr<Texture> texture);
Ptr<Texture> getTexture() const { return texture_; }
// 纹理矩形 (用于图集)
void setTextureRect(const Rect &rect);
Rect getTextureRect() const { return textureRect_; }
// 颜色混合
void setColor(const Color &color);
Color getColor() const { return color_; }
// 翻转
void setFlipX(bool flip);
void setFlipY(bool flip);
bool isFlipX() const { return flipX_; }
bool isFlipY() const { return flipY_; }
// 静态创建方法
static Ptr<Sprite> create();
static Ptr<Sprite> create(Ptr<Texture> texture);
static Ptr<Sprite> create(Ptr<Texture> texture, const Rect &rect);
Rect getBounds() const override;
protected:
void onDraw(RenderBackend &renderer) override;
void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) override;
private:
Ptr<Texture> texture_;
Rect textureRect_;
Color color_ = Colors::White;
bool flipX_ = false;
bool flipY_ = false;
};
} // namespace extra2d

View File

@ -1,35 +0,0 @@
#pragma once
#include <extra2d/scene/transition_scene.h>
namespace extra2d {
// ============================================================================
// 方块/马赛克过渡场景
// 实现原理:
// 1. 将屏幕分成多个方块
// 2. 方块逐个消失,显示新场景
// ============================================================================
class TransitionBoxScene : public TransitionScene {
public:
/**
* @brief
* @param duration
* @param inScene
* @param divisions 8 8x8
*/
TransitionBoxScene(float duration, Ptr<Scene> inScene, int divisions = 8);
static Ptr<TransitionBoxScene> create(float duration, Ptr<Scene> inScene,
int divisions = 8);
protected:
void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override;
void updateTransition(float dt) override;
private:
int divisions_;
};
} // namespace extra2d

View File

@ -1,59 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/scene/transition_scene.h>
namespace extra2d {
// ============================================================================
// 淡入淡出过渡场景
// 实现原理:
// 1. 创建一个纯色精灵作为遮罩层
// 2. 第一阶段:遮罩从透明淡入到不透明(黑屏),同时显示旧场景
// 3. 切换显示新场景
// 4. 第二阶段:遮罩从不透明淡出到透明,显示新场景
// ============================================================================
class TransitionFadeScene : public TransitionScene {
public:
/**
* @brief
* @param duration
* @param inScene
* @param color
*/
TransitionFadeScene(float duration, Ptr<Scene> inScene,
const Color &color = Colors::Black);
static Ptr<TransitionFadeScene> create(float duration, Ptr<Scene> inScene,
const Color &color = Colors::Black);
protected:
/**
* @brief
*
*/
void onTransitionStart() override;
/**
* @brief
* @param dt
*/
void updateTransition(float dt) override;
/**
* @brief
*
*/
void renderContent(RenderBackend &renderer) override;
private:
/**
* @brief 退
*/
void hideOutShowIn();
Color maskColor_; // 遮罩颜色
bool hasSwitched_ = false; // 是否已经切换场景
};
} // namespace extra2d

View File

@ -1,38 +0,0 @@
#pragma once
#include <extra2d/scene/transition_scene.h>
namespace extra2d {
// ============================================================================
// 翻页过渡场景
// 实现原理:
// 1. 前半段:旧场景翻转消失
// 2. 后半段:新场景翻转出现
// ============================================================================
class TransitionFlipScene : public TransitionScene {
public:
enum class Axis { Horizontal, Vertical };
/**
* @brief
* @param duration
* @param inScene
* @param axis
*/
TransitionFlipScene(float duration, Ptr<Scene> inScene,
Axis axis = Axis::Horizontal);
static Ptr<TransitionFlipScene> create(float duration, Ptr<Scene> inScene,
Axis axis = Axis::Horizontal);
protected:
void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override;
void updateTransition(float dt) override;
private:
Axis axis_;
};
} // namespace extra2d

View File

@ -1,30 +0,0 @@
#pragma once
#include <extra2d/scene/transition_scene.h>
namespace extra2d {
// ============================================================================
// 缩放过渡场景
// 实现原理:
// 1. 旧场景缩小消失
// 2. 新场景放大出现
// ============================================================================
class TransitionScaleScene : public TransitionScene {
public:
/**
* @brief
* @param duration
* @param inScene
*/
TransitionScaleScene(float duration, Ptr<Scene> inScene);
static Ptr<TransitionScaleScene> create(float duration, Ptr<Scene> inScene);
protected:
void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override;
void updateTransition(float dt) override;
};
} // namespace extra2d

View File

@ -1,148 +0,0 @@
#pragma once
#include <extra2d/scene/scene.h>
#include <functional>
namespace extra2d {
// ============================================================================
// 过渡方向
// ============================================================================
enum class TransitionDirection { Left, Right, Up, Down };
// ============================================================================
// 过渡效果类型
// ============================================================================
enum class TransitionType {
None,
Fade,
SlideLeft,
SlideRight,
SlideUp,
SlideDown,
Scale,
Flip,
Box
};
// ============================================================================
// 过渡场景基类 - 继承自 Scene作为中介场景管理过渡效果
// 设计参考 Cocos2d-x 的 TransitionScene
// ============================================================================
class TransitionScene : public Scene {
public:
using FinishCallback = std::function<void()>;
/**
* @brief
* @param duration
* @param inScene
*/
TransitionScene(float duration, Ptr<Scene> inScene);
~TransitionScene() override = default;
// ------------------------------------------------------------------------
// 场景管理
// ------------------------------------------------------------------------
/**
* @brief
*/
Ptr<Scene> getInScene() const { return inScene_; }
/**
* @brief 退
*/
Ptr<Scene> getOutScene() const { return outScene_; }
/**
* @brief 退 SceneManager
*/
void setOutScene(Ptr<Scene> outScene) { outScene_ = outScene; }
/**
* @brief
*/
void setFinishCallback(FinishCallback callback) { finishCallback_ = callback; }
/**
* @brief
*/
float getDuration() const { return duration_; }
/**
* @brief [0, 1]
*/
float getProgress() const { return progress_; }
/**
* @brief
*/
bool isFinished() const { return isFinished_; }
/**
* @brief
*/
bool isCancelled() const { return isCancelled_; }
/**
* @brief SceneManager
*/
void finish();
/**
* @brief
* @param immediate false则回滚到原场景
*/
void cancel(bool immediate = false);
// ------------------------------------------------------------------------
// 渲染 - 在 TransitionScene 上渲染新旧两个子场景
// ------------------------------------------------------------------------
void renderContent(RenderBackend &renderer) override;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
void onEnter() override;
void onExit() override;
protected:
/**
* @brief
* onEnter finish()
*/
virtual void onTransitionStart() = 0;
/**
* @brief
*/
virtual void drawOutScene(RenderBackend &renderer);
/**
* @brief
*/
virtual void drawInScene(RenderBackend &renderer);
/**
* @brief
* @param dt
*/
virtual void updateTransition(float dt);
float duration_;
float elapsed_ = 0.0f;
float progress_ = 0.0f;
bool isFinished_ = false;
bool isCancelled_ = false;
Ptr<Scene> inScene_; // 要进入的场景
Ptr<Scene> outScene_; // 要退出的场景
FinishCallback finishCallback_;
FinishCallback cancelCallback_; // 取消回调
friend class SceneManager;
};
} // namespace extra2d

View File

@ -1,36 +0,0 @@
#pragma once
#include <extra2d/scene/transition_scene.h>
namespace extra2d {
// ============================================================================
// 滑动过渡场景
// 实现原理:
// 1. 旧场景向指定方向滑出
// 2. 新场景从相反方向滑入
// ============================================================================
class TransitionSlideScene : public TransitionScene {
public:
/**
* @brief
* @param duration
* @param inScene
* @param direction
*/
TransitionSlideScene(float duration, Ptr<Scene> inScene,
TransitionDirection direction);
static Ptr<TransitionSlideScene> create(float duration, Ptr<Scene> inScene,
TransitionDirection direction);
protected:
void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override;
void updateTransition(float dt) override;
private:
TransitionDirection direction_;
};
} // namespace extra2d

View File

@ -1,115 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/camera/viewport_adapter.h>
namespace extra2d {
/**
* @brief
*/
class ICameraService : public IService {
public:
virtual ~ICameraService() = default;
virtual void setPosition(const Vec2& position) = 0;
virtual void setPosition(float x, float y) = 0;
virtual Vec2 getPosition() const = 0;
virtual void setRotation(float degrees) = 0;
virtual float getRotation() const = 0;
virtual void setZoom(float zoom) = 0;
virtual float getZoom() const = 0;
virtual void setViewport(float left, float right, float bottom, float top) = 0;
virtual Rect getViewport() const = 0;
virtual glm::mat4 getViewMatrix() const = 0;
virtual glm::mat4 getProjectionMatrix() const = 0;
virtual glm::mat4 getViewProjectionMatrix() const = 0;
virtual Vec2 screenToWorld(const Vec2& screenPos) const = 0;
virtual Vec2 worldToScreen(const Vec2& worldPos) const = 0;
virtual void move(const Vec2& offset) = 0;
virtual void move(float x, float y) = 0;
virtual void setBounds(const Rect& bounds) = 0;
virtual void clearBounds() = 0;
virtual void lookAt(const Vec2& target) = 0;
virtual void setViewportConfig(const ViewportConfig& config) = 0;
virtual const ViewportConfig& getViewportConfig() const = 0;
virtual void updateViewport(int screenWidth, int screenHeight) = 0;
virtual const ViewportResult& getViewportResult() const = 0;
virtual void applyViewportAdapter() = 0;
};
/**
* @brief
*/
class CameraService : public ICameraService {
public:
CameraService();
explicit CameraService(float left, float right, float bottom, float top);
~CameraService() override = default;
ServiceInfo getServiceInfo() const override;
bool initialize() override;
void shutdown() override;
void setPosition(const Vec2& position) override;
void setPosition(float x, float y) override;
Vec2 getPosition() const override;
void setRotation(float degrees) override;
float getRotation() const override;
void setZoom(float zoom) override;
float getZoom() const override;
void setViewport(float left, float right, float bottom, float top) override;
Rect getViewport() const override;
glm::mat4 getViewMatrix() const override;
glm::mat4 getProjectionMatrix() const override;
glm::mat4 getViewProjectionMatrix() const override;
Vec2 screenToWorld(const Vec2& screenPos) const override;
Vec2 worldToScreen(const Vec2& worldPos) const override;
void move(const Vec2& offset) override;
void move(float x, float y) override;
void setBounds(const Rect& bounds) override;
void clearBounds() override;
void lookAt(const Vec2& target) override;
void setViewportConfig(const ViewportConfig& config) override;
const ViewportConfig& getViewportConfig() const override;
void updateViewport(int screenWidth, int screenHeight) override;
const ViewportResult& getViewportResult() const override;
void applyViewportAdapter() override;
Camera& getCamera() { return camera_; }
const Camera& getCamera() const { return camera_; }
ViewportAdapter& getViewportAdapter() { return viewportAdapter_; }
const ViewportAdapter& getViewportAdapter() const { return viewportAdapter_; }
private:
Camera camera_;
ViewportAdapter viewportAdapter_;
// 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(ICameraService, CameraService);
};
}

View File

@ -1,77 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/event_queue.h>
namespace extra2d {
/**
* @brief
*/
class IEventService : public IService {
public:
virtual ~IEventService() = default;
virtual void pushEvent(const Event& event) = 0;
virtual void pushEvent(Event&& event) = 0;
virtual bool pollEvent(Event& event) = 0;
virtual ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) = 0;
virtual void removeListener(ListenerId id) = 0;
virtual void removeAllListeners(EventType type) = 0;
virtual void removeAllListeners() = 0;
virtual void dispatch(Event& event) = 0;
virtual void processQueue() = 0;
virtual size_t getListenerCount(EventType type) const = 0;
virtual size_t getTotalListenerCount() const = 0;
virtual size_t getQueueSize() const = 0;
};
/**
* @brief
*/
class EventService : public IEventService {
public:
EventService();
~EventService() override = default;
ServiceInfo getServiceInfo() const override;
bool initialize() override;
void shutdown() override;
void update(float deltaTime) override;
void pushEvent(const Event& event) override;
void pushEvent(Event&& event) override;
bool pollEvent(Event& event) override;
ListenerId addListener(EventType type, EventDispatcher::EventCallback callback) override;
void removeListener(ListenerId id) override;
void removeAllListeners(EventType type) override;
void removeAllListeners() override;
void dispatch(Event& event) override;
void processQueue() override;
size_t getListenerCount(EventType type) const override;
size_t getTotalListenerCount() const override;
size_t getQueueSize() const override;
EventQueue& getQueue() { return queue_; }
const EventQueue& getQueue() const { return queue_; }
EventDispatcher& getDispatcher() { return dispatcher_; }
const EventDispatcher& getDispatcher() const { return dispatcher_; }
private:
EventQueue queue_;
EventDispatcher dispatcher_;
// 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(IEventService, EventService);
};
}

View File

@ -1,232 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/core/types.h>
#include <cstdarg>
#include <string>
#include <type_traits>
namespace extra2d {
/**
* @brief
*/
enum class LogLevel {
Trace = 0,
Debug = 1,
Info = 2,
Warn = 3,
Error = 4,
Fatal = 5,
Off = 6
};
/**
* @brief
*/
class ILogger : public IService {
public:
virtual ~ILogger() = default;
/**
* @brief
*/
virtual void setLevel(LogLevel level) = 0;
/**
* @brief
*/
virtual LogLevel getLevel() const = 0;
/**
* @brief
*/
virtual bool isEnabled(LogLevel level) const = 0;
/**
* @brief
*/
virtual void log(LogLevel level, const char* fmt, ...) = 0;
/**
* @brief
*/
virtual void log(LogLevel level, const std::string& msg) = 0;
/**
* @brief Trace级别日志
*/
virtual void trace(const char* fmt, ...) = 0;
/**
* @brief Debug级别日志
*/
virtual void debug(const char* fmt, ...) = 0;
/**
* @brief Info级别日志
*/
virtual void info(const char* fmt, ...) = 0;
/**
* @brief Warn级别日志
*/
virtual void warn(const char* fmt, ...) = 0;
/**
* @brief Error级别日志
*/
virtual void error(const char* fmt, ...) = 0;
/**
* @brief Fatal级别日志
*/
virtual void fatal(const char* fmt, ...) = 0;
ServiceInfo getServiceInfo() const override {
ServiceInfo info;
info.name = "Logger";
info.priority = ServicePriority::Core;
info.enabled = true;
return info;
}
};
/**
* @brief
*/
class ConsoleLogger : public ILogger {
public:
ConsoleLogger();
~ConsoleLogger() override;
bool initialize() override;
void shutdown() override;
void setLevel(LogLevel level) override;
LogLevel getLevel() const override;
bool isEnabled(LogLevel level) const override;
void log(LogLevel level, const char* fmt, ...) override;
void log(LogLevel level, const std::string& msg) override;
void trace(const char* fmt, ...) override;
void debug(const char* fmt, ...) override;
void info(const char* fmt, ...) override;
void warn(const char* fmt, ...) override;
void error(const char* fmt, ...) override;
void fatal(const char* fmt, ...) override;
private:
void output(LogLevel level, const char* msg);
const char* getLevelString(LogLevel level);
LogLevel level_;
class Impl;
UniquePtr<Impl> impl_;
// 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger);
};
} // namespace extra2d
// 格式化辅助函数 - 将参数转换为字符串
namespace extra2d {
namespace detail {
template<typename T>
std::string to_string(T&& value) {
using Decayed = std::decay_t<T>;
if constexpr (std::is_same_v<Decayed, std::string>) {
return value;
} else if constexpr (std::is_same_v<Decayed, const char*>) {
return value ? value : "(null)";
} else if constexpr (std::is_arithmetic_v<Decayed>) {
if constexpr (std::is_same_v<Decayed, bool>) {
return value ? "true" : "false";
} else if constexpr (std::is_floating_point_v<Decayed>) {
return std::to_string(value);
} else {
return std::to_string(value);
}
} else {
return "<?>";
}
}
inline void format_impl(std::string& result, const char* fmt) {
result += fmt;
}
template<typename T, typename... Args>
void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) {
const char* p = fmt;
while (*p) {
if (*p == '{' && *(p + 1) == '}') {
result += to_string(std::forward<T>(value));
format_impl(result, p + 2, std::forward<Args>(args)...);
return;
}
result += *p++;
}
// 没有更多的 {},追加剩余参数(不应该发生)
result += " ";
result += to_string(std::forward<T>(value));
format_impl(result, p, std::forward<Args>(args)...);
}
}
template<typename... Args>
std::string format_str(const char* fmt, Args&&... args) {
if constexpr (sizeof...(args) == 0) {
return std::string(fmt);
} else {
std::string result;
detail::format_impl(result, fmt, std::forward<Args>(args)...);
return result;
}
}
}
// 便捷宏 - 自动获取日志服务
#define E2D_LOG(level, ...) \
do { \
if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \
if (logService->isEnabled(level)) { \
logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \
} \
} \
} while(0)
#define E2D_LOG_TRACE(...) \
E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
#define E2D_LOG_DEBUG(...) \
E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
#define E2D_LOG_INFO(...) \
E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
#define E2D_LOG_WARN(...) \
E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
#define E2D_LOG_ERROR(...) \
E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
#define E2D_LOG_FATAL(...) \
E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
// 简写宏
#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__)
#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__)
#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__)
#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__)
#ifdef E2D_DEBUG
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
#else
#define E2D_DEBUG_LOG(...)
#define E2D_TRACE(...)
#endif

View File

@ -1,95 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/scene/scene_manager.h>
namespace extra2d {
/**
* @brief
* 便Mock
*/
class ISceneService : public IService {
public:
virtual ~ISceneService() = default;
virtual void runWithScene(Ptr<Scene> scene) = 0;
virtual void replaceScene(Ptr<Scene> scene) = 0;
virtual void pushScene(Ptr<Scene> scene) = 0;
virtual void popScene() = 0;
virtual void popToRootScene() = 0;
virtual void popToScene(const std::string& name) = 0;
virtual Ptr<Scene> getCurrentScene() const = 0;
virtual Ptr<Scene> getPreviousScene() const = 0;
virtual Ptr<Scene> getRootScene() const = 0;
virtual Ptr<Scene> getSceneByName(const std::string& name) const = 0;
virtual size_t getSceneCount() const = 0;
virtual bool isEmpty() const = 0;
virtual bool hasScene(const std::string& name) const = 0;
virtual void render(RenderBackend& renderer) = 0;
virtual void collectRenderCommands(std::vector<RenderCommand>& commands) = 0;
virtual bool isTransitioning() const = 0;
virtual void setTransitionCallback(SceneManager::TransitionCallback callback) = 0;
virtual void end() = 0;
virtual void purgeCachedScenes() = 0;
virtual void enterScene(Ptr<Scene> scene) = 0;
};
/**
* @brief
* SceneManager IService
*/
class SceneService : public ISceneService {
public:
SceneService();
~SceneService() override = default;
ServiceInfo getServiceInfo() const override;
bool initialize() override;
void shutdown() override;
void update(float deltaTime) override;
void runWithScene(Ptr<Scene> scene) override;
void replaceScene(Ptr<Scene> scene) override;
void pushScene(Ptr<Scene> scene) override;
void popScene() override;
void popToRootScene() override;
void popToScene(const std::string& name) override;
Ptr<Scene> getCurrentScene() const override;
Ptr<Scene> getPreviousScene() const override;
Ptr<Scene> getRootScene() const override;
Ptr<Scene> getSceneByName(const std::string& name) const override;
size_t getSceneCount() const override;
bool isEmpty() const override;
bool hasScene(const std::string& name) const override;
void render(RenderBackend& renderer) override;
void collectRenderCommands(std::vector<RenderCommand>& commands) override;
bool isTransitioning() const override;
void setTransitionCallback(SceneManager::TransitionCallback callback) override;
void end() override;
void purgeCachedScenes() override;
void enterScene(Ptr<Scene> scene) override;
SceneManager& getManager() { return manager_; }
const SceneManager& getManager() const { return manager_; }
private:
SceneManager manager_;
// 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(ISceneService, SceneService);
};
}

View File

@ -1,57 +0,0 @@
#pragma once
#include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/utils/timer.h>
namespace extra2d {
/**
* @brief
*/
class ITimerService : public IService {
public:
virtual ~ITimerService() = default;
virtual uint32 addTimer(float delay, Timer::Callback callback) = 0;
virtual uint32 addRepeatingTimer(float interval, Timer::Callback callback) = 0;
virtual void cancelTimer(uint32 timerId) = 0;
virtual void pauseTimer(uint32 timerId) = 0;
virtual void resumeTimer(uint32 timerId) = 0;
virtual void clear() = 0;
virtual size_t getTimerCount() const = 0;
};
/**
* @brief
*/
class TimerService : public ITimerService {
public:
TimerService();
~TimerService() override = default;
ServiceInfo getServiceInfo() const override;
bool initialize() override;
void shutdown() override;
void update(float deltaTime) override;
uint32 addTimer(float delay, Timer::Callback callback) override;
uint32 addRepeatingTimer(float interval, Timer::Callback callback) override;
void cancelTimer(uint32 timerId) override;
void pauseTimer(uint32 timerId) override;
void resumeTimer(uint32 timerId) override;
void clear() override;
size_t getTimerCount() const override;
TimerManager& getManager() { return manager_; }
const TimerManager& getManager() const { return manager_; }
private:
TimerManager manager_;
// 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(ITimerService, TimerService);
};
}

View File

@ -1,12 +0,0 @@
#pragma once
/**
* @file logger.h
* @brief
*
* 便 logger_service.h
*/
#include <extra2d/services/logger_service.h>
#include <extra2d/core/service_locator.h>

View File

@ -1,85 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <random>
namespace extra2d {
// ============================================================================
// Random 类 - 随机数生成器
// ============================================================================
class Random {
public:
/// 获取单例实例
static Random &get();
/// 设置随机种子
void setSeed(uint32 seed);
/// 使用当前时间作为种子
void randomize();
/// 获取 [0, 1) 范围内的随机浮点数
float getFloat();
/// 获取 [min, max] 范围内的随机浮点数
float getFloat(float min, float max);
/// 获取 [0, max] 范围内的随机整数
int getInt(int max);
/// 获取 [min, max] 范围内的随机整数
int getInt(int min, int max);
/// 获取随机布尔值
bool getBool();
/// 获取随机布尔值(带概率)
bool getBool(float probability);
/// 获取指定范围内的随机角度(弧度)
float getAngle();
/// 获取 [-1, 1] 范围内的随机数(用于方向)
float getSigned();
private:
Random();
~Random() = default;
Random(const Random &) = delete;
Random &operator=(const Random &) = delete;
std::mt19937 generator_;
std::uniform_real_distribution<float> floatDist_;
};
// ============================================================================
// 便捷函数
// ============================================================================
/// 获取 [0, 1) 范围内的随机浮点数
inline float randomFloat() { return Random::get().getFloat(); }
/// 获取 [min, max] 范围内的随机浮点数
inline float randomFloat(float min, float max) {
return Random::get().getFloat(min, max);
}
/// 获取 [0, max] 范围内的随机整数
inline int randomInt(int max) { return Random::get().getInt(max); }
/// 获取 [min, max] 范围内的随机整数
inline int randomInt(int min, int max) {
return Random::get().getInt(min, max);
}
/// 获取随机布尔值
inline bool randomBool() { return Random::get().getBool(); }
/// 获取随机布尔值(带概率)
inline bool randomBool(float probability) {
return Random::get().getBool(probability);
}
} // namespace extra2d

View File

@ -1,99 +0,0 @@
#pragma once
#include <chrono>
#include <extra2d/core/types.h>
#include <map>
#include <memory>
#include <vector>
namespace extra2d {
// ============================================================================
// Timer 类 - 单次/重复计时器
// ============================================================================
class Timer {
public:
using Clock = std::chrono::steady_clock;
using TimePoint = Clock::time_point;
using Duration = Clock::duration;
using Callback = Function<void()>;
Timer(float interval, bool repeat, Callback callback);
/// 更新计时器,返回 true 如果触发了回调
bool update(float deltaTime);
/// 重置计时器
void reset();
/// 暂停计时器
void pause();
/// 恢复计时器
void resume();
/// 取消计时器(标记为无效)
void cancel();
/// 是否有效
bool isValid() const { return valid_; }
/// 是否暂停
bool isPaused() const { return paused_; }
/// 获取剩余时间(秒)
float getRemaining() const;
/// 获取唯一ID
uint32 getId() const { return id_; }
private:
uint32 id_;
float interval_;
float elapsed_;
bool repeat_;
bool paused_;
bool valid_;
Callback callback_;
static uint32 nextId_;
};
// ============================================================================
// TimerManager 类 - 管理所有计时器
// ============================================================================
class TimerManager {
public:
TimerManager() = default;
~TimerManager() = default;
/// 创建单次计时器返回计时器ID
uint32 addTimer(float delay, Timer::Callback callback);
/// 创建重复计时器返回计时器ID
uint32 addRepeatingTimer(float interval, Timer::Callback callback);
/// 取消指定ID的计时器
void cancelTimer(uint32 timerId);
/// 暂停指定ID的计时器
void pauseTimer(uint32 timerId);
/// 恢复指定ID的计时器
void resumeTimer(uint32 timerId);
/// 更新所有计时器(每帧调用)
void update(float deltaTime);
/// 清除所有计时器
void clear();
/// 获取计时器数量
size_t getTimerCount() const { return timers_.size(); }
private:
std::map<uint32, std::unique_ptr<Timer>> timers_;
std::vector<uint32> timersToRemove_;
};
} // namespace extra2d

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,428 +0,0 @@
// stb_perlin.h - v0.5 - perlin noise
// public domain single-file C implementation by Sean Barrett
//
// LICENSE
//
// See end of file.
//
//
// to create the implementation,
// #define STB_PERLIN_IMPLEMENTATION
// in *one* C/CPP file that includes this file.
//
//
// Documentation:
//
// float stb_perlin_noise3( float x,
// float y,
// float z,
// int x_wrap=0,
// int y_wrap=0,
// int z_wrap=0)
//
// This function computes a random value at the coordinate (x,y,z).
// Adjacent random values are continuous but the noise fluctuates
// its randomness with period 1, i.e. takes on wholly unrelated values
// at integer points. Specifically, this implements Ken Perlin's
// revised noise function from 2002.
//
// The "wrap" parameters can be used to create wraparound noise that
// wraps at powers of two. The numbers MUST be powers of two. Specify
// 0 to mean "don't care". (The noise always wraps every 256 due
// details of the implementation, even if you ask for larger or no
// wrapping.)
//
// float stb_perlin_noise3_seed( float x,
// float y,
// float z,
// int x_wrap=0,
// int y_wrap=0,
// int z_wrap=0,
// int seed)
//
// As above, but 'seed' selects from multiple different variations of the
// noise function. The current implementation only uses the bottom 8 bits
// of 'seed', but possibly in the future more bits will be used.
//
//
// Fractal Noise:
//
// Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3
// 'octaves' times, so this parameter will affect runtime.
//
// float stb_perlin_ridge_noise3(float x, float y, float z,
// float lacunarity, float gain, float offset, int octaves)
//
// float stb_perlin_fbm_noise3(float x, float y, float z,
// float lacunarity, float gain, int octaves)
//
// float stb_perlin_turbulence_noise3(float x, float y, float z,
// float lacunarity, float gain, int octaves)
//
// Typical values to start playing with:
// octaves = 6 -- number of "octaves" of noise3() to sum
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
//
//
// Contributors:
// Jack Mott - additional noise functions
// Jordan Peck - seeded noise
//
#ifdef __cplusplus
extern "C" {
#endif
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
#ifdef __cplusplus
}
#endif
#ifdef STB_PERLIN_IMPLEMENTATION
#include <math.h> // fabs()
// not same permutation table as Perlin's reference to avoid copyright issues;
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
static unsigned char stb__perlin_randtab[512] =
{
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
// and a second copy so we don't need an extra mask or static initializer
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
};
// perlin's gradient has 12 cases so some get used 1/16th of the time
// and some 2/16ths. We reduce bias by changing those fractions
// to 5/64ths and 6/64ths
// this array is designed to match the previous implementation
// of gradient hash: indices[stb__perlin_randtab[i]&63]
static unsigned char stb__perlin_randtab_grad_idx[512] =
{
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
// and a second copy so we don't need an extra mask or static initializer
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
};
static float stb__perlin_lerp(float a, float b, float t)
{
return a + (b-a) * t;
}
static int stb__perlin_fastfloor(float a)
{
int ai = (int) a;
return (a < ai) ? ai-1 : ai;
}
// different grad function from Perlin's, but easy to modify to match reference
static float stb__perlin_grad(int grad_idx, float x, float y, float z)
{
static float basis[12][4] =
{
{ 1, 1, 0 },
{ -1, 1, 0 },
{ 1,-1, 0 },
{ -1,-1, 0 },
{ 1, 0, 1 },
{ -1, 0, 1 },
{ 1, 0,-1 },
{ -1, 0,-1 },
{ 0, 1, 1 },
{ 0,-1, 1 },
{ 0, 1,-1 },
{ 0,-1,-1 },
};
float *grad = basis[grad_idx];
return grad[0]*x + grad[1]*y + grad[2]*z;
}
float stb_perlin_noise3_internal(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
{
float u,v,w;
float n000,n001,n010,n011,n100,n101,n110,n111;
float n00,n01,n10,n11;
float n0,n1;
unsigned int x_mask = (x_wrap-1) & 255;
unsigned int y_mask = (y_wrap-1) & 255;
unsigned int z_mask = (z_wrap-1) & 255;
int px = stb__perlin_fastfloor(x);
int py = stb__perlin_fastfloor(y);
int pz = stb__perlin_fastfloor(z);
int x0 = px & x_mask, x1 = (px+1) & x_mask;
int y0 = py & y_mask, y1 = (py+1) & y_mask;
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
int r0,r1, r00,r01,r10,r11;
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
x -= px; u = stb__perlin_ease(x);
y -= py; v = stb__perlin_ease(y);
z -= pz; w = stb__perlin_ease(z);
r0 = stb__perlin_randtab[x0+seed];
r1 = stb__perlin_randtab[x1+seed];
r00 = stb__perlin_randtab[r0+y0];
r01 = stb__perlin_randtab[r0+y1];
r10 = stb__perlin_randtab[r1+y0];
r11 = stb__perlin_randtab[r1+y1];
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
n00 = stb__perlin_lerp(n000,n001,w);
n01 = stb__perlin_lerp(n010,n011,w);
n10 = stb__perlin_lerp(n100,n101,w);
n11 = stb__perlin_lerp(n110,n111,w);
n0 = stb__perlin_lerp(n00,n01,v);
n1 = stb__perlin_lerp(n10,n11,v);
return stb__perlin_lerp(n0,n1,u);
}
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
{
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap,0);
}
float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed)
{
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap, (unsigned char) seed);
}
float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves)
{
int i;
float frequency = 1.0f;
float prev = 1.0f;
float amplitude = 0.5f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i);
r = offset - (float) fabs(r);
r = r*r;
sum += r*amplitude*prev;
prev = r;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
sum += (float) fabs(r);
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
{
float u,v,w;
float n000,n001,n010,n011,n100,n101,n110,n111;
float n00,n01,n10,n11;
float n0,n1;
int px = stb__perlin_fastfloor(x);
int py = stb__perlin_fastfloor(y);
int pz = stb__perlin_fastfloor(z);
int x_wrap2 = (x_wrap ? x_wrap : 256);
int y_wrap2 = (y_wrap ? y_wrap : 256);
int z_wrap2 = (z_wrap ? z_wrap : 256);
int x0 = px % x_wrap2, x1;
int y0 = py % y_wrap2, y1;
int z0 = pz % z_wrap2, z1;
int r0,r1, r00,r01,r10,r11;
if (x0 < 0) x0 += x_wrap2;
if (y0 < 0) y0 += y_wrap2;
if (z0 < 0) z0 += z_wrap2;
x1 = (x0+1) % x_wrap2;
y1 = (y0+1) % y_wrap2;
z1 = (z0+1) % z_wrap2;
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
x -= px; u = stb__perlin_ease(x);
y -= py; v = stb__perlin_ease(y);
z -= pz; w = stb__perlin_ease(z);
r0 = stb__perlin_randtab[x0];
r0 = stb__perlin_randtab[r0+seed];
r1 = stb__perlin_randtab[x1];
r1 = stb__perlin_randtab[r1+seed];
r00 = stb__perlin_randtab[r0+y0];
r01 = stb__perlin_randtab[r0+y1];
r10 = stb__perlin_randtab[r1+y0];
r11 = stb__perlin_randtab[r1+y1];
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
n00 = stb__perlin_lerp(n000,n001,w);
n01 = stb__perlin_lerp(n010,n011,w);
n10 = stb__perlin_lerp(n100,n101,w);
n11 = stb__perlin_lerp(n110,n111,w);
n0 = stb__perlin_lerp(n00,n01,v);
n1 = stb__perlin_lerp(n10,n11,v);
return stb__perlin_lerp(n0,n1,u);
}
#endif // STB_PERLIN_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,10 +0,0 @@
#version 300 es
precision highp float;
in vec4 v_color;
out vec4 fragColor;
void main() {
fragColor = v_color;
}

View File

@ -1,14 +0,0 @@
#version 300 es
precision highp float;
layout(location = 0) in vec2 a_position;
layout(location = 1) in vec4 a_color;
uniform mat4 u_viewProjection;
out vec4 v_color;
void main() {
gl_Position = u_viewProjection * vec4(a_position, 0.0, 1.0);
v_color = a_color;
}

View File

@ -1,20 +0,0 @@
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_opacity;
out vec4 fragColor;
void main() {
vec4 texColor = texture(u_texture, v_texCoord);
fragColor = texColor * v_color;
fragColor.a *= u_opacity;
if (fragColor.a < 0.01) {
discard;
}
}

View File

@ -1,18 +0,0 @@
#version 300 es
precision highp float;
layout(location = 0) in vec2 a_position;
layout(location = 1) in vec2 a_texCoord;
layout(location = 2) in vec4 a_color;
uniform mat4 u_viewProjection;
uniform mat4 u_model;
out vec2 v_texCoord;
out vec4 v_color;
void main() {
gl_Position = u_viewProjection * u_model * vec4(a_position, 0.0, 1.0);
v_texCoord = a_texCoord;
v_color = a_color;
}

View File

@ -1,137 +0,0 @@
// ============================================
// Common Color Functions
// ============================================
#ifndef E2D_COLOR_GLSL
#define E2D_COLOR_GLSL
/**
* @brief RGB转灰度
* @param color RGB颜色
* @return 灰度值
*/
float rgbToGrayscale(vec3 color) {
return dot(color, vec3(0.299, 0.587, 0.114));
}
/**
* @brief RGB转HSV
* @param c RGB颜色
* @return HSV颜色
*/
vec3 rgbToHsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
/**
* @brief HSV转RGB
* @param c HSV颜色
* @return RGB颜色
*/
vec3 hsvToRgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
/**
* @brief 调整亮度
* @param color 原始颜色
* @param amount 亮度调整量
* @return 调整后的颜色
*/
vec3 adjustBrightness(vec3 color, float amount) {
return color + amount;
}
/**
* @brief 调整对比度
* @param color 原始颜色
* @param amount 对比度调整量
* @return 调整后的颜色
*/
vec3 adjustContrast(vec3 color, float amount) {
return (color - 0.5) * amount + 0.5;
}
/**
* @brief 调整饱和度
* @param color 原始颜色
* @param amount 饱和度调整量
* @return 调整后的颜色
*/
vec3 adjustSaturation(vec3 color, float amount) {
float gray = rgbToGrayscale(color);
return mix(vec3(gray), color, amount);
}
/**
* @brief 颜色混合(正片叠底)
* @param a 底色
* @param b 混合色
* @return 混合结果
*/
vec3 blendMultiply(vec3 a, vec3 b) {
return a * b;
}
/**
* @brief 颜色混合(滤色)
* @param a 底色
* @param b 混合色
* @return 混合结果
*/
vec3 blendScreen(vec3 a, vec3 b) {
return 1.0 - (1.0 - a) * (1.0 - b);
}
/**
* @brief 颜色混合(叠加)
* @param a 底色
* @param b 混合色
* @return 混合结果
*/
vec3 blendOverlay(vec3 a, vec3 b) {
return mix(
2.0 * a * b,
1.0 - 2.0 * (1.0 - a) * (1.0 - b),
step(0.5, a)
);
}
/**
* @brief 颜色调色
* @param color 原始颜色
* @param tintColor 色调颜色
* @param amount 色调强度
* @return 调色结果
*/
vec3 tint(vec3 color, vec3 tintColor, float amount) {
return mix(color, tintColor, amount);
}
/**
* @brief 预乘Alpha
* @param color RGBA颜色
* @return 预乘后的RGB颜色
*/
vec3 premultiplyAlpha(vec4 color) {
return color.rgb * color.a;
}
/**
* @brief 取消预乘Alpha
* @param color RGB颜色
* @param alpha Alpha值
* @return 未预乘的RGB颜色
*/
vec3 unpremultiplyAlpha(vec3 color, float alpha) {
return alpha > 0.0 ? color / alpha : color;
}
#endif // E2D_COLOR_GLSL

View File

@ -1,96 +0,0 @@
// ============================================
// Common Math Functions
// ============================================
#ifndef E2D_MATH_GLSL
#define E2D_MATH_GLSL
const float PI = 3.14159265359;
const float E = 2.71828182846;
/**
* @brief 角度转弧度
* @param deg 角度值
* @return 弧度值
*/
float degToRad(float deg) {
return deg * PI / 180.0;
}
/**
* @brief 弧度转角度
* @param rad 弧度值
* @return 角度值
*/
float radToDeg(float rad) {
return rad * 180.0 / PI;
}
/**
* @brief 线性插值
* @param a 起始值
* @param b 结束值
* @param t 插值因子 [0, 1]
* @return 插值结果
*/
float lerp(float a, float b, float t) {
return a + (b - a) * t;
}
/**
* @brief 平滑插值
* @param edge0 下边界
* @param edge1 上边界
* @param x 输入值
* @return 平滑插值结果
*/
float smoothStep(float edge0, float edge1, float x) {
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
/**
* @brief 2D向量线性插值
*/
vec2 lerpVec2(vec2 a, vec2 b, float t) {
return a + (b - a) * t;
}
/**
* @brief 计算两点之间的距离
*/
float distance2D(vec2 a, vec2 b) {
return length(b - a);
}
/**
* @brief 计算两点之间的距离平方
*/
float distance2DSquared(vec2 a, vec2 b) {
vec2 diff = b - a;
return dot(diff, diff);
}
/**
* @brief 将值限制在范围内
*/
float clamp01(float x) {
return clamp(x, 0.0, 1.0);
}
/**
* @brief 重复平铺
*/
float repeat(float x, float period) {
return mod(x, period);
}
/**
* @brief 镜像重复
*/
float mirrorRepeat(float x, float period) {
float m = mod(x, period * 2.0);
return m > period ? period * 2.0 - m : m;
}
#endif // E2D_MATH_GLSL

View File

@ -1,20 +0,0 @@
{
"name": "shape",
"category": "builtin",
"version": "1.0",
"description": "基本形状渲染Shader",
"uniforms": {
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" }
},
"samplers": {},
"backends": {
"opengl": {
"vertex": "backends/opengl/builtin/shape.vert",
"fragment": "backends/opengl/builtin/shape.frag"
},
"vulkan": {
"vertex": "backends/vulkan/builtin/shape.vert.spv",
"fragment": "backends/vulkan/builtin/shape.frag.spv"
}
}
}

View File

@ -1,24 +0,0 @@
{
"name": "sprite",
"category": "builtin",
"version": "1.0",
"description": "标准2D精灵渲染Shader",
"uniforms": {
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" },
"u_model": { "type": "mat4", "description": "模型矩阵" },
"u_opacity": { "type": "float", "default": 1.0, "description": "透明度" }
},
"samplers": {
"u_texture": { "binding": 0, "description": "纹理采样器" }
},
"backends": {
"opengl": {
"vertex": "backends/opengl/builtin/sprite.vert",
"fragment": "backends/opengl/builtin/sprite.frag"
},
"vulkan": {
"vertex": "backends/vulkan/builtin/sprite.vert.spv",
"fragment": "backends/vulkan/builtin/sprite.frag.spv"
}
}
}

View File

@ -1,248 +0,0 @@
#include <extra2d/app/application.h>
#include <extra2d/core/registry.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/platform/iinput.h>
#include <extra2d/platform/input_module.h>
#include <extra2d/platform/iwindow.h>
#include <extra2d/platform/window_module.h>
#include <extra2d/services/camera_service.h>
#include <extra2d/services/event_service.h>
#include <extra2d/services/logger_service.h>
#include <extra2d/services/scene_service.h>
#include <extra2d/services/timer_service.h>
namespace extra2d {
static double getTimeSeconds() {
#ifdef __SWITCH__
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<double>(ts.tv_sec) +
static_cast<double>(ts.tv_nsec) / 1000000000.0;
#else
using namespace std::chrono;
auto now = steady_clock::now();
auto duration = now.time_since_epoch();
return duration_cast<std::chrono::duration<double>>(duration).count();
#endif
}
Application &Application::get() {
static Application instance;
return instance;
}
Application::Application() { Registry::instance().setApp(this); }
Application::~Application() {
if (initialized_) {
shutdown();
}
}
bool Application::init() {
if (initialized_) {
return true;
}
// 初始化所有模块(拓扑排序)
// 服务通过 E2D_AUTO_REGISTER_SERVICE 宏自动注册
if (!Registry::instance().init()) {
return false;
}
// 配置相机服务(需要窗口信息)
configureCameraService();
// 初始化所有服务
ServiceLocator::instance().initializeAll();
initialized_ = true;
running_ = true;
return true;
}
void Application::configureCameraService() {
auto *winMod = get<WindowModule>();
if (!winMod || !winMod->win()) {
return;
}
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
if (!cameraService) {
return;
}
auto *win = winMod->win();
cameraService->setViewport(0, static_cast<float>(win->width()),
static_cast<float>(win->height()), 0);
ViewportConfig vpConfig;
vpConfig.logicWidth = static_cast<float>(win->width());
vpConfig.logicHeight = static_cast<float>(win->height());
vpConfig.mode = ViewportMode::AspectRatio;
cameraService->setViewportConfig(vpConfig);
cameraService->updateViewport(win->width(), win->height());
win->onResize([cameraService](int width, int height) {
cameraService->updateViewport(width, height);
cameraService->applyViewportAdapter();
});
}
void Application::shutdown() {
if (!initialized_)
return;
VRAMMgr::get().printStats();
ServiceLocator::instance().shutdownAll();
ServiceLocator::instance().clear();
Registry::instance().shutdown();
Registry::instance().clear();
initialized_ = false;
running_ = false;
}
void Application::run() {
if (!initialized_)
return;
auto *winMod = get<WindowModule>();
if (!winMod || !winMod->win())
return;
lastFrameTime_ = getTimeSeconds();
while (running_ && !winMod->win()->shouldClose()) {
mainLoop();
}
}
void Application::quit() {
shouldQuit_ = true;
running_ = false;
}
void Application::pause() {
if (!paused_) {
paused_ = true;
ServiceLocator::instance().pauseAll();
}
}
void Application::resume() {
if (paused_) {
paused_ = false;
ServiceLocator::instance().resumeAll();
lastFrameTime_ = getTimeSeconds();
}
}
void Application::mainLoop() {
double currentTime = getTimeSeconds();
deltaTime_ = static_cast<float>(currentTime - lastFrameTime_);
lastFrameTime_ = currentTime;
totalTime_ += deltaTime_;
frameCount_++;
fpsTimer_ += deltaTime_;
if (fpsTimer_ >= 1.0f) {
currentFps_ = frameCount_;
frameCount_ = 0;
fpsTimer_ -= 1.0f;
}
auto *winMod = get<WindowModule>();
if (winMod && winMod->win()) {
winMod->win()->poll();
}
auto eventService = ServiceLocator::instance().getService<IEventService>();
if (eventService) {
eventService->processQueue();
}
if (!paused_) {
update();
}
render();
// 帧率限制
auto *renderMod = get<RenderModule>();
if (renderMod && renderMod->renderer()) {
// 这里可以添加帧率限制逻辑
}
}
void Application::update() {
ServiceLocator::instance().updateAll(deltaTime_);
auto *inputMod = get<InputModule>();
if (inputMod) {
inputMod->update();
}
}
void Application::render() {
auto *renderMod = get<RenderModule>();
if (!renderMod || !renderMod->renderer())
return;
auto *renderer = renderMod->renderer();
auto *winMod = get<WindowModule>();
if (!winMod || !winMod->win())
return;
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
if (cameraService) {
const auto &vp = cameraService->getViewportResult().viewport;
renderer->setViewport(
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
renderer->setViewProjection(cameraService->getViewProjectionMatrix());
} else {
renderer->setViewport(0, 0, winMod->win()->width(),
winMod->win()->height());
}
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
if (sceneService) {
sceneService->render(*renderer);
}
winMod->win()->swap();
}
IWindow *Application::window() {
auto *winMod = get<WindowModule>();
return winMod ? winMod->win() : nullptr;
}
RenderBackend *Application::renderer() {
auto *renderMod = get<RenderModule>();
return renderMod ? renderMod->renderer() : nullptr;
}
IInput *Application::input() {
auto *winMod = get<WindowModule>();
return (winMod && winMod->win()) ? winMod->win()->input() : nullptr;
}
void Application::enterScene(Ptr<Scene> scene) {
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
auto *winMod = get<WindowModule>();
if (sceneService && scene && winMod && winMod->win()) {
scene->setViewportSize(static_cast<float>(winMod->win()->width()),
static_cast<float>(winMod->win()->height()));
sceneService->enterScene(scene);
}
}
} // namespace extra2d

View File

@ -1,96 +0,0 @@
#include <extra2d/core/registry.h>
#include <extra2d/utils/logger.h>
#include <algorithm>
#include <queue>
#include <unordered_set>
#include <iostream>
namespace extra2d {
Registry& Registry::instance() {
static Registry instance;
return instance;
}
bool Registry::init() {
auto sorted = topologicalSort();
std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl;
for (auto* module : sorted) {
std::cout << "[Registry] Initializing module: " << module->name() << std::endl;
if (!module->init()) {
std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl;
return false;
}
std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl;
}
std::cout << "[Registry] All modules initialized" << std::endl;
return true;
}
void Registry::shutdown() {
auto sorted = topologicalSort();
// 反向关闭
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) {
(*it)->shutdown();
}
}
void Registry::clear() {
shutdown();
modules_.clear();
}
std::vector<Module*> Registry::topologicalSort() {
std::vector<Module*> result;
std::unordered_map<Module*, int> inDegree;
std::unordered_map<Module*, std::vector<Module*>> adj;
// 构建图
for (auto& [typeIdx, module] : modules_) {
inDegree[module.get()] = 0;
}
for (auto& [typeIdx, module] : modules_) {
for (auto& depType : module->deps()) {
Module* dep = get(depType);
if (dep) {
adj[dep].push_back(module.get());
inDegree[module.get()]++;
}
}
}
// 优先级队列(优先级小的先处理)
auto cmp = [](Module* a, Module* b) {
return a->priority() > b->priority();
};
std::priority_queue<Module*, std::vector<Module*>, decltype(cmp)> pq(cmp);
for (auto& [mod, degree] : inDegree) {
if (degree == 0) {
pq.push(mod);
}
}
// 拓扑排序
while (!pq.empty()) {
Module* curr = pq.top();
pq.pop();
result.push_back(curr);
for (Module* next : adj[curr]) {
inDegree[next]--;
if (inDegree[next] == 0) {
pq.push(next);
}
}
}
return result;
}
} // namespace extra2d

View File

@ -1,110 +0,0 @@
#include <extra2d/core/service_locator.h>
#include <algorithm>
namespace extra2d {
ServiceLocator& ServiceLocator::instance() {
static ServiceLocator instance;
return instance;
}
bool ServiceLocator::initializeAll() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (!service) continue;
auto info = service->getServiceInfo();
if (!info.enabled) continue;
if (!service->isInitialized()) {
service->setState(ServiceState::Initializing);
if (!service->initialize()) {
service->setState(ServiceState::Stopped);
return false;
}
service->setState(ServiceState::Running);
}
}
return true;
}
void ServiceLocator::shutdownAll() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto it = orderedServices_.rbegin();
it != orderedServices_.rend(); ++it) {
if (*it && (*it)->isInitialized()) {
(*it)->setState(ServiceState::Stopping);
(*it)->shutdown();
(*it)->setState(ServiceState::Stopped);
}
}
}
void ServiceLocator::updateAll(float deltaTime) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (service && service->isInitialized()) {
auto state = service->getState();
if (state == ServiceState::Running) {
service->update(deltaTime);
}
}
}
}
void ServiceLocator::pauseAll() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (service && service->isInitialized()) {
service->pause();
}
}
}
void ServiceLocator::resumeAll() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& service : orderedServices_) {
if (service && service->isInitialized()) {
service->resume();
}
}
}
std::vector<SharedPtr<IService>> ServiceLocator::getAllServices() const {
std::lock_guard<std::mutex> lock(mutex_);
return orderedServices_;
}
void ServiceLocator::clear() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto it = orderedServices_.rbegin();
it != orderedServices_.rend(); ++it) {
if (*it && (*it)->isInitialized()) {
(*it)->setState(ServiceState::Stopping);
(*it)->shutdown();
(*it)->setState(ServiceState::Stopped);
}
}
services_.clear();
factories_.clear();
orderedServices_.clear();
}
void ServiceLocator::sortServices() {
std::stable_sort(orderedServices_.begin(), orderedServices_.end(),
[](const SharedPtr<IService>& a, const SharedPtr<IService>& b) {
if (!a || !b) return false;
return static_cast<int>(a->getServiceInfo().priority) <
static_cast<int>(b->getServiceInfo().priority);
});
}
}

View File

@ -1,37 +0,0 @@
#include <extra2d/core/service_registry.h>
namespace extra2d {
ServiceRegistry& ServiceRegistry::instance() {
static ServiceRegistry instance;
return instance;
}
void ServiceRegistry::setServiceEnabled(const std::string& name, bool enabled) {
for (auto& reg : registrations_) {
if (reg.name == name) {
reg.enabled = enabled;
break;
}
}
}
void ServiceRegistry::createAllServices() {
std::sort(registrations_.begin(), registrations_.end(),
[](const ServiceRegistration& a, const ServiceRegistration& b) {
return static_cast<int>(a.priority) < static_cast<int>(b.priority);
});
for (const auto& reg : registrations_) {
if (!reg.enabled) {
continue;
}
auto service = reg.factory();
if (service) {
ServiceLocator::instance().registerService<IService>(service);
}
}
}
}

View File

@ -1,134 +0,0 @@
#include <extra2d/event/event.h>
namespace extra2d {
/**
* @brief
*
* Event对象
*
* @param width
* @param height
* @return Event对象
*/
Event Event::createWindowResize(int width, int height) {
Event event;
event.type = EventType::WindowResize;
event.data = WindowResizeEvent{width, height};
return event;
}
/**
* @brief
*
* Event对象
*
* @return Event对象
*/
Event Event::createWindowClose() {
Event event;
event.type = EventType::WindowClose;
return event;
}
/**
* @brief
*
* Event对象
*
* @param keyCode
* @param scancode
* @param mods ShiftCtrl等
* @return Event对象
*/
Event Event::createKeyPress(int keyCode, int scancode, int mods) {
Event event;
event.type = EventType::KeyPressed;
event.data = KeyEvent{keyCode, scancode, mods};
return event;
}
/**
* @brief
*
* Event对象
*
* @param keyCode
* @param scancode
* @param mods ShiftCtrl等
* @return Event对象
*/
Event Event::createKeyRelease(int keyCode, int scancode, int mods) {
Event event;
event.type = EventType::KeyReleased;
event.data = KeyEvent{keyCode, scancode, mods};
return event;
}
/**
* @brief
*
* Event对象
*
* @param button
* @param mods
* @param pos
* @return Event对象
*/
Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) {
Event event;
event.type = EventType::MouseButtonPressed;
event.data = MouseButtonEvent{button, mods, pos};
return event;
}
/**
* @brief
*
* Event对象
*
* @param button
* @param mods
* @param pos
* @return Event对象
*/
Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) {
Event event;
event.type = EventType::MouseButtonReleased;
event.data = MouseButtonEvent{button, mods, pos};
return event;
}
/**
* @brief
*
* Event对象
*
* @param pos
* @param delta
* @return Event对象
*/
Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) {
Event event;
event.type = EventType::MouseMoved;
event.data = MouseMoveEvent{pos, delta};
return event;
}
/**
* @brief
*
* Event对象
*
* @param offset
* @param pos
* @return Event对象
*/
Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) {
Event event;
event.type = EventType::MouseScrolled;
event.data = MouseScrollEvent{offset, pos};
return event;
}
} // namespace extra2d

View File

@ -1,137 +0,0 @@
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/event_queue.h>
namespace extra2d {
/**
* @brief
*
* ID为1
*/
EventDispatcher::EventDispatcher() : nextId_(1) {}
/**
* @brief
*
* ID用于后续移除
*
* @param type
* @param callback
* @return ID
*/
ListenerId EventDispatcher::addListener(EventType type,
EventCallback callback) {
ListenerId id = nextId_++;
listeners_[type].push_back({id, type, callback});
return id;
}
/**
* @brief
*
* ID移除对应的事件监听器
*
* @param id ID
*/
void EventDispatcher::removeListener(ListenerId id) {
for (auto &[type, listeners] : listeners_) {
auto it = std::remove_if(listeners.begin(), listeners.end(),
[id](const Listener &l) { return l.id == id; });
if (it != listeners.end()) {
listeners.erase(it, listeners.end());
return;
}
}
}
/**
* @brief
*
*
*
* @param type
*/
void EventDispatcher::removeAllListeners(EventType type) {
listeners_.erase(type);
}
/**
* @brief
*
*
*/
void EventDispatcher::removeAllListeners() { listeners_.clear(); }
/**
* @brief
*
*
*
* @param event
*/
void EventDispatcher::dispatch(Event &event) {
auto it = listeners_.find(event.type);
if (it != listeners_.end()) {
for (auto &listener : it->second) {
if (event.handled)
break;
listener.callback(event);
}
}
}
/**
* @brief
*
*
*
* @param event
*/
void EventDispatcher::dispatch(const Event &event) {
Event mutableEvent = event;
dispatch(mutableEvent);
}
/**
* @brief
*
*
*
* @param queue
*/
void EventDispatcher::processQueue(EventQueue &queue) {
Event event;
while (queue.poll(event)) {
dispatch(event);
}
}
/**
* @brief
*
*
*
* @param type
* @return
*/
size_t EventDispatcher::getListenerCount(EventType type) const {
auto it = listeners_.find(type);
return (it != listeners_.end()) ? it->second.size() : 0;
}
/**
* @brief
*
*
*
* @return
*/
size_t EventDispatcher::getTotalListenerCount() const {
size_t count = 0;
for (const auto &[type, listeners] : listeners_) {
count += listeners.size();
}
return count;
}
} // namespace extra2d

View File

@ -1,107 +0,0 @@
#include <extra2d/event/event_queue.h>
namespace extra2d {
/**
* @brief
*
*
*/
EventQueue::EventQueue() = default;
/**
* @brief
*
* 线
*
* @param event
*/
void EventQueue::push(const Event &event) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(event);
}
/**
* @brief
*
* 线
*
* @param event
*/
void EventQueue::push(Event &&event) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(event));
}
/**
* @brief
*
* 线
*
* @param event
* @return truefalse
*/
bool EventQueue::poll(Event &event) {
std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) {
return false;
}
event = queue_.front();
queue_.pop();
return true;
}
/**
* @brief
*
* 线
*
* @param event
* @return truefalse
*/
bool EventQueue::peek(Event &event) const {
std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) {
return false;
}
event = queue_.front();
return true;
}
/**
* @brief
*
* 线
*/
void EventQueue::clear() {
std::lock_guard<std::mutex> lock(mutex_);
while (!queue_.empty()) {
queue_.pop();
}
}
/**
* @brief
*
* 线
*
* @return truefalse
*/
bool EventQueue::empty() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}
/**
* @brief
*
* 线
*
* @return
*/
size_t EventQueue::size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
} // namespace extra2d

View File

@ -1,127 +0,0 @@
#include <extra2d/graphics/backends/backend_factory.h>
// 条件编译包含对应后端实现
#ifdef E2D_BACKEND_OPENGL
#include <extra2d/graphics/backends/opengl/gl_renderer.h>
#endif
#ifdef E2D_BACKEND_VULKAN
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
#endif
#include <extra2d/utils/logger.h>
#include <cstring>
namespace extra2d {
BackendFactory& BackendFactory::getInstance() {
static BackendFactory instance;
return instance;
}
UniquePtr<RenderBackend> BackendFactory::createBackend(BackendType type) {
switch (type) {
#ifdef E2D_BACKEND_OPENGL
case BackendType::OpenGL:
E2D_LOG_INFO("Creating OpenGL render backend");
return makeUnique<GLRenderer>();
#endif
#ifdef E2D_BACKEND_VULKAN
case BackendType::Vulkan:
E2D_LOG_INFO("Creating Vulkan render backend");
return makeUnique<VulkanRenderer>();
#endif
default:
E2D_LOG_ERROR("Unsupported render backend type: {}", static_cast<int>(type));
return nullptr;
}
}
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
BackendType recommended = getRecommendedBackend();
return createBackend(recommended);
}
bool BackendFactory::isBackendAvailable(BackendType type) const {
switch (type) {
#ifdef E2D_BACKEND_OPENGL
case BackendType::OpenGL:
return true;
#endif
#ifdef E2D_BACKEND_VULKAN
case BackendType::Vulkan:
return true;
#endif
default:
return false;
}
}
BackendType BackendFactory::getRecommendedBackend() const {
// 平台特定的默认后端选择
// 优先级Vulkan > OpenGL
#ifdef E2D_BACKEND_VULKAN
return BackendType::Vulkan;
#endif
#ifdef E2D_BACKEND_OPENGL
return BackendType::OpenGL;
#endif
// 如果没有可用的后端返回OpenGL作为默认值
return BackendType::OpenGL;
}
const char* BackendFactory::getBackendName(BackendType type) const {
switch (type) {
case BackendType::OpenGL:
return "OpenGL";
case BackendType::Vulkan:
return "Vulkan";
case BackendType::Metal:
return "Metal";
case BackendType::D3D11:
return "D3D11";
case BackendType::D3D12:
return "D3D12";
case BackendType::OpenGLES:
return "OpenGL ES";
default:
return "Unknown";
}
}
BackendType BackendFactory::parseBackendType(const char* name) const {
if (!name) {
return BackendType::OpenGL;
}
if (std::strcmp(name, "opengl") == 0 || std::strcmp(name, "OpenGL") == 0) {
return BackendType::OpenGL;
}
if (std::strcmp(name, "vulkan") == 0 || std::strcmp(name, "Vulkan") == 0) {
return BackendType::Vulkan;
}
if (std::strcmp(name, "metal") == 0 || std::strcmp(name, "Metal") == 0) {
return BackendType::Metal;
}
if (std::strcmp(name, "d3d11") == 0 || std::strcmp(name, "D3D11") == 0) {
return BackendType::D3D11;
}
if (std::strcmp(name, "d3d12") == 0 || std::strcmp(name, "D3D12") == 0) {
return BackendType::D3D12;
}
if (std::strcmp(name, "opengles") == 0 || std::strcmp(name, "OpenGLES") == 0) {
return BackendType::OpenGLES;
}
E2D_LOG_WARN("Unknown backend type '{}', defaulting to OpenGL", name);
return BackendType::OpenGL;
}
} // namespace extra2d

View File

@ -1,171 +0,0 @@
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
#include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/utils/logger.h>
#include <cstring>
namespace extra2d {
// ============================================================================
// GLBuffer 实现
// ============================================================================
GLBuffer::GLBuffer() = default;
GLBuffer::~GLBuffer() {
shutdown();
}
bool GLBuffer::init(const BufferDesc& desc) {
if (bufferID_ != 0) {
shutdown();
}
type_ = desc.type;
usage_ = desc.usage;
size_ = desc.size;
target_ = convertType(type_);
glUsage_ = convertUsage(usage_);
// 生成缓冲区
glGenBuffers(1, &bufferID_);
if (bufferID_ == 0) {
E2D_LOG_ERROR("Failed to generate OpenGL buffer");
return false;
}
// 绑定并分配缓冲区
glBindBuffer(target_, bufferID_);
glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData, glUsage_);
glBindBuffer(target_, 0);
// 追踪显存使用
VRAMMgr::get().allocBuffer(size_);
E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}",
bufferID_, size_, static_cast<int>(type_), static_cast<int>(usage_));
return true;
}
void GLBuffer::shutdown() {
if (bufferID_ != 0) {
if (mapped_) {
unmap();
}
// 释放显存追踪
VRAMMgr::get().freeBuffer(size_);
glDeleteBuffers(1, &bufferID_);
E2D_LOG_DEBUG("GLBuffer destroyed: ID={}", bufferID_);
bufferID_ = 0;
}
size_ = 0;
mapped_ = false;
mappedPtr_ = nullptr;
}
void GLBuffer::bind() {
if (bufferID_ != 0) {
glBindBuffer(target_, bufferID_);
}
}
void GLBuffer::unbind() {
glBindBuffer(target_, 0);
}
void GLBuffer::setData(const void* data, size_t size) {
if (bufferID_ == 0) {
return;
}
bind();
// 如果大小相同,使用 glBufferSubData 更高效
if (size == size_) {
glBufferSubData(target_, 0, static_cast<GLsizeiptr>(size), data);
} else {
// 大小不同,重新分配
size_ = size;
glBufferData(target_, static_cast<GLsizeiptr>(size_), data, glUsage_);
}
unbind();
}
void GLBuffer::updateData(const void* data, size_t offset, size_t size) {
if (bufferID_ == 0 || data == nullptr || size == 0) {
return;
}
if (offset + size > size_) {
E2D_LOG_WARN("GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}",
offset, size, size_);
return;
}
bind();
glBufferSubData(target_, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), data);
unbind();
}
void* GLBuffer::map() {
if (bufferID_ == 0 || mapped_) {
return nullptr;
}
bind();
// 使用 glMapBufferRange 替代 glMapBuffer更现代且安全
GLbitfield access = GL_MAP_WRITE_BIT;
if (usage_ == BufferUsage::Dynamic || usage_ == BufferUsage::Stream) {
access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据
}
mappedPtr_ = glMapBufferRange(target_, 0, static_cast<GLsizeiptr>(size_), access);
if (mappedPtr_) {
mapped_ = true;
} else {
E2D_LOG_ERROR("Failed to map GLBuffer");
}
return mappedPtr_;
}
void GLBuffer::unmap() {
if (!mapped_ || bufferID_ == 0) {
return;
}
glUnmapBuffer(target_);
mapped_ = false;
mappedPtr_ = nullptr;
unbind();
}
GLenum GLBuffer::convertUsage(BufferUsage usage) {
switch (usage) {
case BufferUsage::Static:
return GL_STATIC_DRAW;
case BufferUsage::Dynamic:
return GL_DYNAMIC_DRAW;
case BufferUsage::Stream:
return GL_STREAM_DRAW;
default:
return GL_STATIC_DRAW;
}
}
GLenum GLBuffer::convertType(BufferType type) {
switch (type) {
case BufferType::Vertex:
return GL_ARRAY_BUFFER;
case BufferType::Index:
return GL_ELEMENT_ARRAY_BUFFER;
case BufferType::Uniform:
return GL_UNIFORM_BUFFER;
default:
return GL_ARRAY_BUFFER;
}
}
} // namespace extra2d

View File

@ -1,167 +0,0 @@
#include <extra2d/graphics/backends/opengl/gl_context.h>
#include <extra2d/graphics/memory/gpu_context.h>
#include <extra2d/utils/logger.h>
#include <cstring>
#include <sstream>
namespace extra2d {
// ============================================================================
// GLContext 实现
// ============================================================================
GLContext& GLContext::get() {
static GLContext instance;
return instance;
}
bool GLContext::init() {
if (initialized_) {
return true;
}
// 解析 OpenGL 版本
parseVersion();
// 加载扩展GLAD 已在 glad.c 中完成)
if (!loadExtensions()) {
E2D_LOG_ERROR("Failed to load OpenGL extensions");
return false;
}
initialized_ = true;
// 标记 GPU 上下文为有效
GPUContext::get().markValid();
E2D_LOG_INFO("OpenGL Context initialized");
E2D_LOG_INFO(" Version: {}", getVersionString());
E2D_LOG_INFO(" Vendor: {}", getVendor());
E2D_LOG_INFO(" Renderer: {}", getRenderer());
E2D_LOG_INFO(" Max Texture Size: {}", getMaxTextureSize());
E2D_LOG_INFO(" Max Texture Units: {}", getMaxTextureUnits());
return true;
}
void GLContext::shutdown() {
// 标记 GPU 上下文为无效
GPUContext::get().markInvalid();
initialized_ = false;
version_ = GLVersion{};
maxTextureSize_ = -1;
maxTextureUnits_ = -1;
maxVertexAttribs_ = -1;
maxUniformBufferBindings_ = -1;
}
std::string GLContext::getVersionString() const {
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
return version ? version : "Unknown";
}
std::string GLContext::getVendor() const {
const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
return vendor ? vendor : "Unknown";
}
std::string GLContext::getRenderer() const {
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
return renderer ? renderer : "Unknown";
}
bool GLContext::hasExtension(const std::string& extension) const {
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (GLint i = 0; i < numExtensions; ++i) {
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
if (ext && extension == ext) {
return true;
}
}
return false;
}
int GLContext::getMaxTextureSize() const {
if (maxTextureSize_ < 0) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_);
}
return maxTextureSize_;
}
int GLContext::getMaxTextureUnits() const {
if (maxTextureUnits_ < 0) {
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_);
}
return maxTextureUnits_;
}
int GLContext::getMaxVertexAttribs() const {
if (maxVertexAttribs_ < 0) {
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_);
}
return maxVertexAttribs_;
}
int GLContext::getMaxUniformBufferBindings() const {
if (maxUniformBufferBindings_ < 0) {
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_);
}
return maxUniformBufferBindings_;
}
bool GLContext::hasVAO() const {
// OpenGL 3.0+ 或 OpenGL ES 3.0+ 原生支持 VAO
if (version_.es) {
return version_.major >= 3;
}
return version_.major > 3 || (version_.major == 3 && version_.minor >= 0);
}
bool GLContext::hasFBO() const {
// OpenGL 3.0+ 或 OpenGL ES 2.0+ 原生支持 FBO
if (version_.es) {
return version_.major >= 2;
}
return version_.major >= 3;
}
bool GLContext::hasShader() const {
// OpenGL 2.0+ 或 OpenGL ES 2.0+ 原生支持 Shader
if (version_.es) {
return version_.major >= 2;
}
return version_.major >= 2;
}
void GLContext::parseVersion() {
const char* versionStr = reinterpret_cast<const char*>(glGetString(GL_VERSION));
if (!versionStr) {
version_ = GLVersion{0, 0, false};
return;
}
std::string version(versionStr);
// 检查是否为 OpenGL ES
if (version.find("OpenGL ES") != std::string::npos) {
version_.es = true;
// 解析 ES 版本号,格式如 "OpenGL ES 3.0"
std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, &version_.minor);
} else {
version_.es = false;
// 解析桌面版本号,格式如 "3.3.0 NVIDIA"
std::sscanf(version.c_str(), "%d.%d", &version_.major, &version_.minor);
}
}
bool GLContext::loadExtensions() {
// GLAD 已经在 glad.c 中加载了所有扩展
// 这里可以添加额外的扩展检查
return true;
}
} // namespace extra2d

Some files were not shown because too many files have changed in this diff Show More