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
396 changed files with 20240 additions and 59695 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,172 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <functional>
namespace extra2d {
class Node;
/**
* @brief
*/
enum class ActionState {
Idle,
Running,
Paused,
Completed
};
/**
* @brief
*
*
* Node
*/
class Action {
public:
using CompletionCallback = std::function<void()>;
Action();
virtual ~Action() = default;
Action(const Action&) = delete;
Action& operator=(const Action&) = delete;
Action(Action&&) = default;
Action& operator=(Action&&) = default;
/**
* @brief
* @return true
*/
virtual bool isDone() const;
/**
* @brief 使
* @param target
*/
virtual void startWithTarget(Node* target);
/**
* @brief
*/
virtual void stop();
/**
* @brief
* @param dt
*/
virtual void step(float dt);
/**
* @brief
* @param time [0, 1]
*/
virtual void update(float time);
/**
* @brief
* @return
*/
virtual Action* clone() const = 0;
/**
* @brief
* @return
*/
virtual Action* reverse() const = 0;
/**
* @brief
*/
void pause();
/**
* @brief
*/
void resume();
/**
* @brief
*/
void restart();
/**
* @brief
* @param callback
*/
void setCompletionCallback(const CompletionCallback& callback) {
completionCallback_ = callback;
}
/**
* @brief
* @return
*/
Node* getTarget() const { return target_; }
/**
* @brief
* @return
*/
Node* getOriginalTarget() const { return originalTarget_; }
/**
* @brief
* @return
*/
ActionState getState() const { return state_; }
/**
* @brief
* @return
*/
int getTag() const { return tag_; }
/**
* @brief
* @param tag
*/
void setTag(int tag) { tag_ = tag; }
/**
* @brief
* @return
*/
unsigned int getFlags() const { return flags_; }
/**
* @brief
* @param flags
*/
void setFlags(unsigned int flags) { flags_ = flags; }
protected:
/**
* @brief
*/
virtual void onStart() {}
/**
* @brief
*/
virtual void onComplete() {
if (completionCallback_) {
completionCallback_();
}
}
/**
* @brief
*/
void setDone() { state_ = ActionState::Completed; }
Node* target_ = nullptr;
Node* originalTarget_ = nullptr;
ActionState state_ = ActionState::Idle;
int tag_ = -1;
unsigned int flags_ = 0;
CompletionCallback completionCallback_;
};
} // namespace extra2d

View File

@ -1,344 +0,0 @@
#pragma once
#include <extra2d/action/action_interval.h>
#include <extra2d/action/ease.h>
namespace extra2d {
/**
* @brief
*
* 使
*/
class ActionEase : public ActionInterval {
public:
virtual ~ActionEase();
/**
* @brief
* @return
*/
ActionInterval* getInnerAction() const { return innerAction_; }
void startWithTarget(Node* target) override;
void stop() override;
void update(float time) override;
ActionInterval* clone() const override = 0;
ActionInterval* reverse() const override = 0;
protected:
ActionEase() = default;
bool initWithAction(ActionInterval* action);
void onUpdate(float progress) override {}
ActionInterval* innerAction_ = nullptr;
};
// ============================================================================
// 指数缓动
// ============================================================================
class EaseExponentialIn : public ActionEase {
public:
static EaseExponentialIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseExponentialOut : public ActionEase {
public:
static EaseExponentialOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseExponentialInOut : public ActionEase {
public:
static EaseExponentialInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 正弦缓动
// ============================================================================
class EaseSineIn : public ActionEase {
public:
static EaseSineIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseSineOut : public ActionEase {
public:
static EaseSineOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseSineInOut : public ActionEase {
public:
static EaseSineInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 弹性缓动
// ============================================================================
class EaseElasticIn : public ActionEase {
public:
static EaseElasticIn* create(ActionInterval* action, float period = 0.3f);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
protected:
float period_ = 0.3f;
};
class EaseElasticOut : public ActionEase {
public:
static EaseElasticOut* create(ActionInterval* action, float period = 0.3f);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
protected:
float period_ = 0.3f;
};
class EaseElasticInOut : public ActionEase {
public:
static EaseElasticInOut* create(ActionInterval* action, float period = 0.3f);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
protected:
float period_ = 0.3f;
};
// ============================================================================
// 弹跳缓动
// ============================================================================
class EaseBounceIn : public ActionEase {
public:
static EaseBounceIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseBounceOut : public ActionEase {
public:
static EaseBounceOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseBounceInOut : public ActionEase {
public:
static EaseBounceInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 回震缓动
// ============================================================================
class EaseBackIn : public ActionEase {
public:
static EaseBackIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseBackOut : public ActionEase {
public:
static EaseBackOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseBackInOut : public ActionEase {
public:
static EaseBackInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 二次缓动
// ============================================================================
class EaseQuadIn : public ActionEase {
public:
static EaseQuadIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuadOut : public ActionEase {
public:
static EaseQuadOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuadInOut : public ActionEase {
public:
static EaseQuadInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 三次缓动
// ============================================================================
class EaseCubicIn : public ActionEase {
public:
static EaseCubicIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseCubicOut : public ActionEase {
public:
static EaseCubicOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseCubicInOut : public ActionEase {
public:
static EaseCubicInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 四次缓动
// ============================================================================
class EaseQuartIn : public ActionEase {
public:
static EaseQuartIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuartOut : public ActionEase {
public:
static EaseQuartOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuartInOut : public ActionEase {
public:
static EaseQuartInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 五次缓动
// ============================================================================
class EaseQuintIn : public ActionEase {
public:
static EaseQuintIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuintOut : public ActionEase {
public:
static EaseQuintOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseQuintInOut : public ActionEase {
public:
static EaseQuintInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 圆形缓动
// ============================================================================
class EaseCircleIn : public ActionEase {
public:
static EaseCircleIn* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseCircleOut : public ActionEase {
public:
static EaseCircleOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
class EaseCircleInOut : public ActionEase {
public:
static EaseCircleInOut* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
};
// ============================================================================
// 自定义缓动
// ============================================================================
/**
* @brief
*/
class EaseCustom : public ActionEase {
public:
static EaseCustom* create(ActionInterval* action, EaseFunction easeFunc);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
void update(float time) override;
protected:
EaseFunction easeFunc_ = nullptr;
};
} // namespace extra2d

View File

@ -1,57 +0,0 @@
#pragma once
#include <extra2d/action/finite_time_action.h>
namespace extra2d {
/**
* @brief
*
*
* FiniteTimeAction 0
*/
class ActionInstant : public FiniteTimeAction {
public:
ActionInstant();
virtual ~ActionInstant() = default;
/**
* @brief
* @return true
*/
bool isDone() const override;
/**
* @brief 使
* @param target
*/
void startWithTarget(Node* target) override;
/**
* @brief
* @param dt
*/
void step(float dt) override;
/**
* @brief
* @return
*/
ActionInstant* clone() const override = 0;
/**
* @brief
* @return
*/
ActionInstant* reverse() const override = 0;
protected:
/**
* @brief
*/
virtual void execute() = 0;
bool done_ = false;
};
} // namespace extra2d

View File

@ -1,169 +0,0 @@
#pragma once
#include <extra2d/action/action_instant.h>
#include <extra2d/core/math_types.h>
#include <functional>
namespace extra2d {
// ============================================================================
// 回调动作
// ============================================================================
/**
* @brief
*/
class CallFunc : public ActionInstant {
public:
using Callback = std::function<void()>;
static CallFunc* create(const Callback& callback);
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
Callback callback_;
};
/**
* @brief
*/
class CallFuncN : public ActionInstant {
public:
using Callback = std::function<void(Node*)>;
static CallFuncN* create(const Callback& callback);
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
Callback callback_;
};
// ============================================================================
// 位置动作
// ============================================================================
/**
* @brief
*/
class Place : public ActionInstant {
public:
static Place* create(const Vec2& position);
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
Vec2 position_;
};
// ============================================================================
// 翻转动作
// ============================================================================
/**
* @brief X轴翻转动作
*/
class FlipX : public ActionInstant {
public:
static FlipX* create(bool flipX);
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
bool flipX_ = false;
};
/**
* @brief Y轴翻转动作
*/
class FlipY : public ActionInstant {
public:
static FlipY* create(bool flipY);
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
bool flipY_ = false;
};
// ============================================================================
// 可见性动作
// ============================================================================
/**
* @brief
*/
class Show : public ActionInstant {
public:
static Show* create();
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
};
/**
* @brief
*/
class Hide : public ActionInstant {
public:
static Hide* create();
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
};
/**
* @brief
*/
class ToggleVisibility : public ActionInstant {
public:
static ToggleVisibility* create();
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
};
// ============================================================================
// 节点管理动作
// ============================================================================
/**
* @brief
*/
class RemoveSelf : public ActionInstant {
public:
static RemoveSelf* create();
ActionInstant* clone() const override;
ActionInstant* reverse() const override;
protected:
void execute() override;
};
} // namespace extra2d

View File

@ -1,103 +0,0 @@
#pragma once
#include <extra2d/action/finite_time_action.h>
#include <extra2d/action/ease.h>
namespace extra2d {
/**
* @brief
*
*
* FiniteTimeAction
*/
class ActionInterval : public FiniteTimeAction {
public:
ActionInterval() = default;
explicit ActionInterval(float duration);
virtual ~ActionInterval() = default;
/**
* @brief
* @return
*/
float getElapsed() const { return elapsed_; }
/**
* @brief
* @return true
*/
bool isDone() const override;
/**
* @brief 使
* @param target
*/
void startWithTarget(Node* target) override;
/**
* @brief
*/
void stop() override;
/**
* @brief
* @param dt
*/
void step(float dt) override;
/**
* @brief
* @param amp
*/
void setAmplitudeRate(float amp) { amplitudeRate_ = amp; }
/**
* @brief
* @return
*/
float getAmplitudeRate() const { return amplitudeRate_; }
/**
* @brief
* @param easeFunc
*/
void setEaseFunction(EaseFunction easeFunc) { easeFunc_ = easeFunc; }
/**
* @brief
* @return
*/
EaseFunction getEaseFunction() const { return easeFunc_; }
/**
* @brief
* @return
*/
ActionInterval* clone() const override = 0;
/**
* @brief
* @return
*/
ActionInterval* reverse() const override = 0;
protected:
/**
* @brief
*/
virtual void onStart() {}
/**
* @brief
* @param progress [0, 1]
*/
virtual void onUpdate(float progress) = 0;
float elapsed_ = 0.0f;
bool firstTick_ = true;
float amplitudeRate_ = 1.0f;
EaseFunction easeFunc_ = nullptr;
};
} // namespace extra2d

View File

@ -1,469 +0,0 @@
#pragma once
#include <extra2d/action/action_interval.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/color.h>
#include <functional>
#include <vector>
namespace extra2d {
// ============================================================================
// 移动动作
// ============================================================================
/**
* @brief
*/
class MoveBy : public ActionInterval {
public:
static MoveBy* create(float duration, const Vec2& delta);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Vec2 delta_;
Vec2 startPosition_;
};
/**
* @brief
*/
class MoveTo : public ActionInterval {
public:
static MoveTo* create(float duration, const Vec2& position);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Vec2 endPosition_;
Vec2 startPosition_;
Vec2 delta_;
};
// ============================================================================
// 跳跃动作
// ============================================================================
/**
* @brief
*/
class JumpBy : public ActionInterval {
public:
static JumpBy* create(float duration, const Vec2& position, float height, int jumps);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Vec2 startPosition_;
Vec2 delta_;
float height_ = 0.0f;
int jumps_ = 1;
};
/**
* @brief
*/
class JumpTo : public JumpBy {
public:
static JumpTo* create(float duration, const Vec2& position, float height, int jumps);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
Vec2 endPosition_;
};
// ============================================================================
// 贝塞尔曲线动作
// ============================================================================
/**
* @brief 线
*/
struct BezierConfig {
Vec2 controlPoint1;
Vec2 controlPoint2;
Vec2 endPosition;
};
/**
* @brief 线
*/
class BezierBy : public ActionInterval {
public:
static BezierBy* create(float duration, const BezierConfig& config);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
static float bezierat(float a, float b, float c, float d, float t);
BezierConfig config_;
Vec2 startPosition_;
};
/**
* @brief 线
*/
class BezierTo : public BezierBy {
public:
static BezierTo* create(float duration, const BezierConfig& config);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
BezierConfig originalConfig_;
};
// ============================================================================
// 缩放动作
// ============================================================================
/**
* @brief
*/
class ScaleBy : public ActionInterval {
public:
static ScaleBy* create(float duration, float scale);
static ScaleBy* create(float duration, float scaleX, float scaleY);
static ScaleBy* create(float duration, const Vec2& scale);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Vec2 deltaScale_;
Vec2 startScale_;
};
/**
* @brief
*/
class ScaleTo : public ActionInterval {
public:
static ScaleTo* create(float duration, float scale);
static ScaleTo* create(float duration, float scaleX, float scaleY);
static ScaleTo* create(float duration, const Vec2& scale);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Vec2 endScale_;
Vec2 startScale_;
Vec2 delta_;
};
// ============================================================================
// 旋转动作
// ============================================================================
/**
* @brief
*/
class RotateBy : public ActionInterval {
public:
static RotateBy* create(float duration, float deltaAngle);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
float deltaAngle_ = 0.0f;
float startAngle_ = 0.0f;
};
/**
* @brief
*/
class RotateTo : public ActionInterval {
public:
static RotateTo* create(float duration, float angle);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
float endAngle_ = 0.0f;
float startAngle_ = 0.0f;
float deltaAngle_ = 0.0f;
};
// ============================================================================
// 淡入淡出动作
// ============================================================================
/**
* @brief
*/
class FadeIn : public ActionInterval {
public:
static FadeIn* create(float duration);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
float startOpacity_ = 0.0f;
};
/**
* @brief
*/
class FadeOut : public ActionInterval {
public:
static FadeOut* create(float duration);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
float startOpacity_ = 0.0f;
};
/**
* @brief
*/
class FadeTo : public ActionInterval {
public:
static FadeTo* create(float duration, float opacity);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
float endOpacity_ = 0.0f;
float startOpacity_ = 0.0f;
float deltaOpacity_ = 0.0f;
};
// ============================================================================
// 闪烁动作
// ============================================================================
/**
* @brief
*/
class Blink : public ActionInterval {
public:
static Blink* create(float duration, int times);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
int times_ = 1;
int currentTimes_ = 0;
bool originalVisible_ = true;
};
// ============================================================================
// 色调动作
// ============================================================================
/**
* @brief
*/
class TintTo : public ActionInterval {
public:
static TintTo* create(float duration, uint8_t red, uint8_t green, uint8_t blue);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Color3B startColor_;
Color3B endColor_;
Color3B deltaColor_;
};
/**
* @brief
*/
class TintBy : public ActionInterval {
public:
static TintBy* create(float duration, int16_t deltaRed, int16_t deltaGreen, int16_t deltaBlue);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
Color3B startColor_;
int16_t deltaR_ = 0;
int16_t deltaG_ = 0;
int16_t deltaB_ = 0;
};
// ============================================================================
// 组合动作
// ============================================================================
/**
* @brief
*/
class Sequence : public ActionInterval {
public:
static Sequence* create(ActionInterval* action1, ...);
static Sequence* create(const std::vector<ActionInterval*>& actions);
~Sequence();
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
std::vector<ActionInterval*> actions_;
size_t currentIndex_ = 0;
float split_ = 0.0f;
float last_ = -1.0f;
};
/**
* @brief
*/
class Spawn : public ActionInterval {
public:
static Spawn* create(ActionInterval* action1, ...);
static Spawn* create(const std::vector<ActionInterval*>& actions);
~Spawn();
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
std::vector<ActionInterval*> actions_;
};
/**
* @brief
*/
class Repeat : public ActionInterval {
public:
static Repeat* create(ActionInterval* action, int times);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
bool isDone() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
ActionInterval* innerAction_ = nullptr;
int times_ = 1;
int currentTimes_ = 0;
};
/**
* @brief
*/
class RepeatForever : public ActionInterval {
public:
static RepeatForever* create(ActionInterval* action);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
bool isDone() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
ActionInterval* innerAction_ = nullptr;
};
/**
* @brief
*/
class DelayTime : public ActionInterval {
public:
static DelayTime* create(float duration);
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onUpdate(float progress) override {}
};
/**
* @brief
*/
class ReverseTime : public ActionInterval {
public:
static ReverseTime* create(ActionInterval* action);
~ReverseTime();
ActionInterval* clone() const override;
ActionInterval* reverse() const override;
protected:
void onStart() override;
void onUpdate(float progress) override;
ActionInterval* innerAction_ = nullptr;
};
} // namespace extra2d

View File

@ -1,130 +0,0 @@
#pragma once
#include <extra2d/action/action.h>
#include <unordered_map>
#include <vector>
#include <functional>
namespace extra2d {
/**
* @brief
*
*
*
*/
class ActionManager {
public:
/**
* @brief
* @return ActionManager
*/
static ActionManager* getInstance();
/**
* @brief
*/
static void destroyInstance();
/**
* @brief
* @param action
* @param target
* @param paused
*/
void addAction(Action* action, Node* target, bool paused = false);
/**
* @brief
* @param action
*/
void removeAction(Action* action);
/**
* @brief
* @param tag
* @param target
*/
void removeActionByTag(int tag, Node* target);
/**
* @brief
* @param flags
* @param target
*/
void removeActionsByFlags(unsigned int flags, Node* target);
/**
* @brief
* @param target
*/
void removeAllActionsFromTarget(Node* target);
/**
* @brief
*/
void removeAllActions();
/**
* @brief
* @param tag
* @param target
* @return nullptr
*/
Action* getActionByTag(int tag, Node* target);
/**
* @brief
* @param target
* @return
*/
size_t getActionCount(Node* target) const;
/**
* @brief
* @param target
*/
void pauseTarget(Node* target);
/**
* @brief
* @param target
*/
void resumeTarget(Node* target);
/**
* @brief
* @param target
* @return true
*/
bool isPaused(Node* target) const;
/**
* @brief
* @param dt
*/
void update(float dt);
private:
ActionManager();
~ActionManager();
struct ActionElement {
std::vector<Action*> actions;
Node* target = nullptr;
bool paused = false;
int actionIndex = 0;
Action* currentAction = nullptr;
bool currentActionSalvaged = false;
};
using ActionMap = std::unordered_map<Node*, ActionElement>;
void removeActionAt(size_t index, ActionElement& element);
void deleteAction(Action* action);
ActionMap targets_;
static ActionManager* instance_;
};
} // namespace extra2d

View File

@ -1,166 +0,0 @@
#pragma once
#include <extra2d/action/action.h>
#include <extra2d/action/action_interval.h>
#include <extra2d/core/math_types.h>
namespace extra2d {
/**
* @brief
*
*
*
*/
class Speed : public Action {
public:
/**
* @brief
* @param action
* @param speed 1.0
* @return
*/
static Speed* create(ActionInterval* action, float speed);
~Speed();
/**
* @brief
* @return
*/
float getSpeed() const { return speed_; }
/**
* @brief
* @param speed
*/
void setSpeed(float speed) { speed_ = speed; }
/**
* @brief
* @return
*/
ActionInterval* getInnerAction() const { return innerAction_; }
void startWithTarget(Node* target) override;
void stop() override;
void step(float dt) override;
bool isDone() const override;
Action* clone() const override;
Action* reverse() const override;
protected:
Speed() = default;
ActionInterval* innerAction_ = nullptr;
float speed_ = 1.0f;
};
/**
* @brief
*
* 使
*
*/
class Follow : public Action {
public:
/**
* @brief
* @param followedNode
* @return
*/
static Follow* create(Node* followedNode);
/**
* @brief
* @param followedNode
* @param boundary
* @return
*/
static Follow* create(Node* followedNode, const Rect& boundary);
~Follow();
/**
* @brief
* @return
*/
Node* getFollowedNode() const { return followedNode_; }
/**
* @brief
* @return true
*/
bool isBoundarySet() const { return boundarySet_; }
void startWithTarget(Node* target) override;
void stop() override;
void step(float dt) override;
bool isDone() const override;
Action* clone() const override;
Action* reverse() const override;
protected:
Follow() = default;
Node* followedNode_ = nullptr;
Rect boundary_;
bool boundarySet_ = false;
Vec2 halfScreenSize_;
Vec2 fullScreenSize_;
Vec2 leftBoundary_;
Vec2 rightBoundary_;
Vec2 topBoundary_;
Vec2 bottomBoundary_;
};
/**
* @brief
*
*
*/
class TargetedAction : public Action {
public:
/**
* @brief
* @param target
* @param action
* @return
*/
static TargetedAction* create(Node* target, FiniteTimeAction* action);
~TargetedAction();
/**
* @brief
* @return
*/
Node* getTargetNode() const { return targetNode_; }
/**
* @brief
* @param target
*/
void setTargetNode(Node* target) { targetNode_ = target; }
/**
* @brief
* @return
*/
FiniteTimeAction* getAction() const { return innerAction_; }
void startWithTarget(Node* target) override;
void stop() override;
void step(float dt) override;
bool isDone() const override;
Action* clone() const override;
Action* reverse() const override;
protected:
TargetedAction() = default;
Node* targetNode_ = nullptr;
FiniteTimeAction* innerAction_ = nullptr;
};
} // namespace extra2d

View File

@ -1,101 +0,0 @@
#pragma once
namespace extra2d {
/**
* @brief
*/
using EaseFunction = float (*)(float);
// ============================================================================
// 线性缓动
// ============================================================================
/**
* @brief 线
* @param t [0, 1]
* @return
*/
float easeLinear(float t);
// ============================================================================
// 二次缓动 (Quad)
// ============================================================================
float easeInQuad(float t);
float easeOutQuad(float t);
float easeInOutQuad(float t);
// ============================================================================
// 三次缓动 (Cubic)
// ============================================================================
float easeInCubic(float t);
float easeOutCubic(float t);
float easeInOutCubic(float t);
// ============================================================================
// 四次缓动 (Quart)
// ============================================================================
float easeInQuart(float t);
float easeOutQuart(float t);
float easeInOutQuart(float t);
// ============================================================================
// 五次缓动 (Quint)
// ============================================================================
float easeInQuint(float t);
float easeOutQuint(float t);
float easeInOutQuint(float t);
// ============================================================================
// 正弦缓动 (Sine)
// ============================================================================
float easeInSine(float t);
float easeOutSine(float t);
float easeInOutSine(float t);
// ============================================================================
// 指数缓动 (Exponential)
// ============================================================================
float easeInExpo(float t);
float easeOutExpo(float t);
float easeInOutExpo(float t);
// ============================================================================
// 圆形缓动 (Circular)
// ============================================================================
float easeInCirc(float t);
float easeOutCirc(float t);
float easeInOutCirc(float t);
// ============================================================================
// 回震缓动 (Back)
// ============================================================================
float easeInBack(float t);
float easeOutBack(float t);
float easeInOutBack(float t);
// ============================================================================
// 弹性缓动 (Elastic)
// ============================================================================
float easeInElastic(float t);
float easeOutElastic(float t);
float easeInOutElastic(float t);
// ============================================================================
// 弹跳缓动 (Bounce)
// ============================================================================
float easeInBounce(float t);
float easeOutBounce(float t);
float easeInOutBounce(float t);
} // namespace extra2d

View File

@ -1,47 +0,0 @@
#pragma once
#include <extra2d/action/action.h>
namespace extra2d {
/**
* @brief
*
*
* Action
*/
class FiniteTimeAction : public Action {
public:
FiniteTimeAction() = default;
explicit FiniteTimeAction(float duration);
virtual ~FiniteTimeAction() = default;
/**
* @brief
* @return
*/
float getDuration() const { return duration_; }
/**
* @brief
* @param duration
*/
void setDuration(float duration) { duration_ = duration; }
/**
* @brief
* @return
*/
FiniteTimeAction* clone() const override = 0;
/**
* @brief
* @return
*/
FiniteTimeAction* reverse() const override = 0;
protected:
float duration_ = 0.0f;
};
} // namespace extra2d

View File

@ -1,52 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// ALS 图层信息
// ============================================================================
struct AlsLayerInfo {
std::string aniPath; // 子动画的 ANI 文件路径
int zOrder = 0; // 层级顺序
Vec2 offset; // 层偏移
};
// ============================================================================
// ALS 解析结果
// ============================================================================
struct AlsParseResult {
bool success = false;
std::string errorMessage;
std::vector<AlsLayerInfo> layers;
};
// ============================================================================
// AlsParser - ALS 复合动画文件解析器
// 解析 .als 文件获取多层动画的图层信息
// ============================================================================
class AlsParser {
public:
AlsParser() = default;
/// 从文件解析
AlsParseResult parse(const std::string &filePath);
/// 从内存内容解析
AlsParseResult parseFromMemory(const std::string &content,
const std::string &basePath = "");
/// 设置基础路径
void setBasePath(const std::string &basePath) { basePath_ = basePath; }
private:
std::string basePath_;
std::string resolvePath(const std::string &relativePath) const;
};
} // namespace extra2d

View File

@ -1,68 +0,0 @@
#pragma once
#include <cstdint>
#include <extra2d/animation/ani_parser.h>
#include <extra2d/animation/animation_cache.h>
#include <extra2d/core/types.h>
#include <functional>
#include <string>
namespace extra2d {
// ============================================================================
// DNF ANI 二进制格式中的节点类型枚举
// ============================================================================
enum class AniNodeType : uint16_t {
Loop = 0,
Shadow = 1,
Coord = 3,
ImageRate = 7,
ImageRotate = 8,
RGBA = 9,
Interpolation = 10,
GraphicEffect = 11,
Delay = 12,
DamageType = 13,
DamageBox = 14,
AttackBox = 15,
PlaySound = 16,
Preload = 17,
Spectrum = 18,
SetFlag = 23,
FlipType = 24,
LoopStart = 25,
LoopEnd = 26,
Clip = 27,
Operation = 28,
};
// ============================================================================
// AniBinaryParser - ANI 二进制格式解析器
// 参考 DNF-Porting 的 PvfAnimation 实现
// ============================================================================
class AniBinaryParser {
public:
AniBinaryParser() = default;
/// 从二进制数据解析
AniParseResult parse(const uint8_t *data, size_t length);
/// 从文件解析
AniParseResult parseFromFile(const std::string &filePath);
/// 设置路径替换回调
void setPathResolver(PathResolveCallback callback) {
pathResolver_ = std::move(callback);
}
/// 设置基础路径
void setBasePath(const std::string &basePath) { basePath_ = basePath; }
private:
PathResolveCallback pathResolver_;
std::string basePath_;
std::string resolvePath(const std::string &relativePath) const;
};
} // namespace extra2d

View File

@ -1,50 +0,0 @@
#pragma once
#include <extra2d/animation/animation_cache.h>
#include <extra2d/animation/animation_clip.h>
#include <extra2d/core/types.h>
#include <functional>
#include <string>
namespace extra2d {
// ============================================================================
// ANI 文件解析结果
// ============================================================================
struct AniParseResult {
bool success = false;
std::string errorMessage;
Ptr<AnimationClip> clip;
};
// ============================================================================
// AniParser - ANI 脚本文件解析器
// 将原始 ANI 文件格式解析为 AnimationClip 数据
// ============================================================================
class AniParser {
public:
AniParser() = default;
/// 从文件解析
AniParseResult parse(const std::string &filePath);
/// 从内存内容解析
AniParseResult parseFromMemory(const std::string &content,
const std::string &basePath = "");
/// 设置路径替换回调(对应原始 AdditionalOptions
void setPathResolver(PathResolveCallback callback) {
pathResolver_ = std::move(callback);
}
/// 设置基础路径(用于解析相对路径)
void setBasePath(const std::string &basePath) { basePath_ = basePath; }
private:
PathResolveCallback pathResolver_;
std::string basePath_;
std::string resolvePath(const std::string &relativePath) const;
};
} // namespace extra2d

View File

@ -1,128 +0,0 @@
#pragma once
#include <array>
#include <cstdint>
#include <extra2d/animation/animation_cache.h>
#include <extra2d/animation/animation_controller.h>
#include <extra2d/scene/sprite.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// AnimatedSprite - 动画精灵节点
// 将 AnimationController 与 Sprite 渲染桥接,接入场景图
// ============================================================================
class AnimatedSprite : public Sprite {
public:
AnimatedSprite();
~AnimatedSprite() override = default;
// ------ 静态工厂 ------
static Ptr<AnimatedSprite> create();
static Ptr<AnimatedSprite> create(Ptr<AnimationClip> clip);
static Ptr<AnimatedSprite> create(const std::string &aniFilePath);
// ------ 动画绑定 ------
void setAnimationClip(Ptr<AnimationClip> clip);
void loadAnimation(const std::string &aniFilePath);
Ptr<AnimationClip> getAnimationClip() const;
// ------ 动画字典 ------
void addAnimation(const std::string &name, Ptr<AnimationClip> clip);
void play(const std::string &name, bool loop = true);
bool hasAnimation(const std::string &name) const;
Ptr<AnimationClip> getAnimation(const std::string &name) const;
const std::string &getCurrentAnimationName() const;
// ------ 播放控制(委托 controller_------
void play();
void pause();
void resume();
void stop();
void reset();
bool isPlaying() const;
bool isPaused() const;
bool isStopped() const;
// ------ 属性控制 ------
void setLooping(bool loop);
bool isLooping() const;
void setPlaybackSpeed(float speed);
float getPlaybackSpeed() const;
// ------ 帧控制 ------
void setFrameIndex(size_t index);
size_t getCurrentFrameIndex() const;
size_t getTotalFrames() const;
void nextFrame();
void prevFrame();
// ------ 帧范围限制 ------
/// 设置帧播放范围(用于精灵图动画,限制在指定范围内循环)
/// @param start 起始帧索引(包含)
/// @param end 结束帧索引(包含),-1表示不限制
void setFrameRange(int start, int end = -1);
/// 获取当前帧范围
/// @return pair<起始帧, 结束帧>,结束帧为-1表示不限制
std::pair<int, int> getFrameRange() const;
/// 清除帧范围限制(恢复播放所有帧)
void clearFrameRange();
/// 检查是否设置了帧范围限制
bool hasFrameRange() const;
// ------ 回调 ------
void setCompletionCallback(AnimationController::CompletionCallback cb);
void setKeyframeCallback(AnimationController::KeyframeCallback cb);
void setSoundTriggerCallback(AnimationController::SoundTriggerCallback cb);
// ------ 碰撞盒访问(当前帧)------
const std::vector<std::array<int32_t, 6>> &getCurrentDamageBoxes() const;
const std::vector<std::array<int32_t, 6>> &getCurrentAttackBoxes() const;
// ------ 帧变换控制 ------
/// 设置是否由动画帧数据覆盖节点的 position/scale/rotation
/// ANI 动画需要开启(默认),精灵图动画应关闭
void setApplyFrameTransform(bool apply) { applyFrameTransform_ = apply; }
bool isApplyFrameTransform() const { return applyFrameTransform_; }
// ------ 自动播放 ------
void setAutoPlay(bool autoPlay) { autoPlay_ = autoPlay; }
bool isAutoPlay() const { return autoPlay_; }
// ------ 直接控制器访问 ------
AnimationController &getController() { return controller_; }
const AnimationController &getController() const { return controller_; }
protected:
void onUpdate(float dt) override;
void onEnter() override;
private:
AnimationController controller_;
bool autoPlay_ = false;
bool applyFrameTransform_ = true;
// 动画字典
std::unordered_map<std::string, Ptr<AnimationClip>> animations_;
std::string currentAnimationName_;
static const std::string emptyString_;
// 帧范围限制(用于精灵图动画)
int frameRangeStart_ = 0; // 起始帧索引
int frameRangeEnd_ = -1; // 结束帧索引,-1表示不限制
// 空碰撞盒列表(用于无帧时返回引用)
static const std::vector<std::array<int32_t, 6>> emptyBoxes_;
void applyFrame(const AnimationFrame &frame);
void onFrameChanged(size_t oldIdx, size_t newIdx,
const AnimationFrame &frame);
};
} // namespace extra2d

View File

@ -1,102 +0,0 @@
#pragma once
#include <extra2d/animation/animation_clip.h>
#include <functional>
#include <mutex>
#include <string>
#include <unordered_map>
namespace extra2d {
// 路径替换回调(对应原始 AdditionalOptions
using PathResolveCallback = std::function<std::string(const std::string &)>;
// ============================================================================
// AnimationCache - 动画片段全局缓存(借鉴 Cocos AnimationCache
// 同一 ANI 文件只解析一次,后续直接复用数据
// ============================================================================
class AnimationCache {
public:
static AnimationCache &getInstance() {
static AnimationCache instance;
return instance;
}
// ------ 加载与获取 ------
/// 从文件加载(自动缓存),已缓存则直接返回
/// 注意:实际的 ANI 解析逻辑在 AniParser 中实现
/// 此方法在 animation_cache.cpp 中实现,依赖 AniParser
Ptr<AnimationClip> loadClip(const std::string &aniFilePath);
/// 从缓存获取(不触发加载)
Ptr<AnimationClip> getClip(const std::string &name) const {
std::lock_guard<std::mutex> lock(mutex_);
auto it = clips_.find(name);
if (it != clips_.end())
return it->second;
return nullptr;
}
/// 手动添加到缓存
void addClip(Ptr<AnimationClip> clip, const std::string &name) {
std::lock_guard<std::mutex> lock(mutex_);
clips_[name] = std::move(clip);
}
// ------ 缓存管理 ------
bool has(const std::string &name) const {
std::lock_guard<std::mutex> lock(mutex_);
return clips_.find(name) != clips_.end();
}
void removeClip(const std::string &name) {
std::lock_guard<std::mutex> lock(mutex_);
clips_.erase(name);
}
/// 移除未被外部引用的动画片段
void removeUnusedClips() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto it = clips_.begin(); it != clips_.end();) {
if (it->second.use_count() == 1) {
it = clips_.erase(it);
} else {
++it;
}
}
}
void clear() {
std::lock_guard<std::mutex> lock(mutex_);
clips_.clear();
}
size_t count() const {
std::lock_guard<std::mutex> lock(mutex_);
return clips_.size();
}
// ------ 路径配置 ------
void setPathResolver(PathResolveCallback resolver) {
pathResolver_ = std::move(resolver);
}
PathResolveCallback getPathResolver() const { return pathResolver_; }
private:
AnimationCache() = default;
~AnimationCache() = default;
AnimationCache(const AnimationCache &) = delete;
AnimationCache &operator=(const AnimationCache &) = delete;
mutable std::mutex mutex_;
std::unordered_map<std::string, Ptr<AnimationClip>> clips_;
PathResolveCallback pathResolver_;
};
// 便捷宏
#define E2D_ANIMATION_CACHE() ::extra2d::AnimationCache::getInstance()
} // namespace extra2d

View File

@ -1,184 +0,0 @@
#pragma once
#include <cassert>
#include <extra2d/animation/animation_frame.h>
#include <extra2d/animation/sprite_frame_cache.h>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// AnimationClip - 动画片段(纯数据,可复用)
// 借鉴 Cocos一份 AnimationClip 可被多个 AnimationNode 同时使用
// ============================================================================
class AnimationClip {
public:
AnimationClip() = default;
explicit AnimationClip(const std::string &name) : name_(name) {}
// ------ 帧管理 ------
void addFrame(const AnimationFrame &frame) { frames_.push_back(frame); }
void addFrame(AnimationFrame &&frame) { frames_.push_back(std::move(frame)); }
void insertFrame(size_t index, const AnimationFrame &frame) {
assert(index <= frames_.size());
frames_.insert(frames_.begin() + static_cast<ptrdiff_t>(index), frame);
}
void removeFrame(size_t index) {
assert(index < frames_.size());
frames_.erase(frames_.begin() + static_cast<ptrdiff_t>(index));
}
void clearFrames() { frames_.clear(); }
const AnimationFrame &getFrame(size_t index) const {
assert(index < frames_.size());
return frames_[index];
}
AnimationFrame &getFrame(size_t index) {
assert(index < frames_.size());
return frames_[index];
}
size_t getFrameCount() const { return frames_.size(); }
bool empty() const { return frames_.empty(); }
// ------ 全局属性(对应原始 AnimationFlag------
FramePropertySet &globalProperties() { return globalProperties_; }
const FramePropertySet &globalProperties() const { return globalProperties_; }
bool isLooping() const {
return globalProperties_.getOr<bool>(FramePropertyKey::Loop, false);
}
void setLooping(bool loop) { globalProperties_.withLoop(loop); }
// ------ 时间信息 ------
float getTotalDuration() const {
float total = 0.0f;
for (const auto &frame : frames_) {
total += frame.delay;
}
return total;
}
// ------ 预计算最大帧尺寸 ------
Size getMaxFrameSize() const {
Size maxSize;
for (const auto &frame : frames_) {
if (frame.spriteFrame && frame.spriteFrame->isValid()) {
const auto &rect = frame.spriteFrame->getRect();
if (rect.size.width > maxSize.width)
maxSize.width = rect.size.width;
if (rect.size.height > maxSize.height)
maxSize.height = rect.size.height;
}
}
return maxSize;
}
// ------ 元数据 ------
void setName(const std::string &name) { name_ = name; }
const std::string &getName() const { return name_; }
void setSourcePath(const std::string &path) { sourcePath_ = path; }
const std::string &getSourcePath() const { return sourcePath_; }
// ------ 静态工厂 ------
static Ptr<AnimationClip> create(const std::string &name = "") {
return makePtr<AnimationClip>(name);
}
/// 从精灵图网格创建(所有帧按顺序)
static Ptr<AnimationClip> createFromGrid(Ptr<Texture> texture, int frameWidth,
int frameHeight,
float frameDurationMs = 100.0f,
int frameCount = -1, int spacing = 0,
int margin = 0) {
if (!texture)
return nullptr;
int texW = texture->getWidth();
int texH = texture->getHeight();
int usableW = texW - 2 * margin;
int usableH = texH - 2 * margin;
int cols = (usableW + spacing) / (frameWidth + spacing);
int rows = (usableH + spacing) / (frameHeight + spacing);
int total = (frameCount > 0) ? frameCount : cols * rows;
auto clip = makePtr<AnimationClip>();
for (int i = 0; i < total; ++i) {
int col = i % cols;
int row = i / cols;
if (row >= rows)
break;
// 翻转行顺序精灵图第0行在顶部但OpenGL纹理V坐标从底部开始
// 所以将行索引翻转使第0行对应纹理底部V=1.0第3行对应纹理顶部V=0.0
int flippedRow = (rows - 1) - row;
Rect rect(
static_cast<float>(margin + col * (frameWidth + spacing)),
static_cast<float>(margin + flippedRow * (frameHeight + spacing)),
static_cast<float>(frameWidth), static_cast<float>(frameHeight));
auto sf = SpriteFrame::create(texture, rect);
AnimationFrame frame;
frame.spriteFrame = std::move(sf);
frame.delay = frameDurationMs;
clip->addFrame(std::move(frame));
}
return clip;
}
/// 从精灵图网格创建(指定帧索引列表)
static Ptr<AnimationClip>
createFromGridIndices(Ptr<Texture> texture, int frameWidth, int frameHeight,
const std::vector<int> &frameIndices,
float frameDurationMs = 100.0f, int spacing = 0,
int margin = 0) {
if (!texture)
return nullptr;
int texW = texture->getWidth();
int texH = texture->getHeight();
int usableW = texW - 2 * margin;
int usableH = texH - 2 * margin;
int cols = (usableW + spacing) / (frameWidth + spacing);
int rows = (usableH + spacing) / (frameHeight + spacing);
auto clip = makePtr<AnimationClip>();
for (int idx : frameIndices) {
int col = idx % cols;
int row = idx / cols;
// 翻转行顺序精灵图第0行在顶部但OpenGL纹理V坐标从底部开始
int flippedRow = (rows - 1) - row;
Rect rect(
static_cast<float>(margin + col * (frameWidth + spacing)),
static_cast<float>(margin + flippedRow * (frameHeight + spacing)),
static_cast<float>(frameWidth), static_cast<float>(frameHeight));
auto sf = SpriteFrame::create(texture, rect);
AnimationFrame frame;
frame.spriteFrame = std::move(sf);
frame.delay = frameDurationMs;
clip->addFrame(std::move(frame));
}
return clip;
}
private:
std::string name_;
std::string sourcePath_;
std::vector<AnimationFrame> frames_;
FramePropertySet globalProperties_;
};
} // namespace extra2d

View File

@ -1,108 +0,0 @@
#pragma once
#include <extra2d/animation/animation_clip.h>
#include <extra2d/animation/interpolation_engine.h>
#include <extra2d/core/types.h>
#include <functional>
#include <string>
namespace extra2d {
// ============================================================================
// 动画播放状态
// ============================================================================
enum class AnimPlayState : uint8 { Stopped, Playing, Paused };
// ============================================================================
// AnimationController - 动画播放控制器
// 借鉴 Cocos Creator 的 AnimationState纯播放逻辑不持有渲染资源
// ============================================================================
class AnimationController {
public:
// 回调类型定义
using FrameChangeCallback = std::function<void(size_t oldIdx, size_t newIdx,
const AnimationFrame &frame)>;
using KeyframeCallback = std::function<void(int flagIndex)>;
using SoundTriggerCallback = std::function<void(const std::string &path)>;
using CompletionCallback = std::function<void()>;
AnimationController() = default;
// ------ 绑定动画数据 ------
void setClip(Ptr<AnimationClip> clip);
Ptr<AnimationClip> getClip() const { return clip_; }
// ------ 播放控制 ------
void play();
void pause();
void resume();
void stop();
void reset();
// ------ 帧控制 ------
void setFrameIndex(size_t index);
void nextFrame();
void prevFrame();
// ------ 核心更新(每帧调用)------
void update(float dt);
// ------ 状态查询 ------
AnimPlayState getState() const { return state_; }
bool isPlaying() const { return state_ == AnimPlayState::Playing; }
bool isPaused() const { return state_ == AnimPlayState::Paused; }
bool isStopped() const { return state_ == AnimPlayState::Stopped; }
size_t getCurrentFrameIndex() const { return currentFrameIndex_; }
size_t getTotalFrames() const;
const AnimationFrame &getCurrentFrame() const;
float getPlaybackSpeed() const { return playbackSpeed_; }
void setPlaybackSpeed(float speed) { playbackSpeed_ = speed; }
bool isLooping() const;
void setLooping(bool loop);
// ------ 插值状态 ------
float getInterpolationFactor() const { return interpolationFactor_; }
bool isInterpolating() const { return interpolating_; }
// ------ 回调注册 ------
void setFrameChangeCallback(FrameChangeCallback cb) {
onFrameChange_ = std::move(cb);
}
void setKeyframeCallback(KeyframeCallback cb) { onKeyframe_ = std::move(cb); }
void setSoundTriggerCallback(SoundTriggerCallback cb) {
onSoundTrigger_ = std::move(cb);
}
void setCompletionCallback(CompletionCallback cb) {
onComplete_ = std::move(cb);
}
private:
Ptr<AnimationClip> clip_;
AnimPlayState state_ = AnimPlayState::Stopped;
size_t currentFrameIndex_ = 0;
float accumulatedTime_ = 0.0f; // 当前帧已累积时间 (ms)
float playbackSpeed_ = 1.0f;
bool loopOverride_ = false; // 外部循环覆盖值
bool hasLoopOverride_ = false; // 是否使用外部循环覆盖
// 插值状态
bool interpolating_ = false;
float interpolationFactor_ = 0.0f;
// 回调
FrameChangeCallback onFrameChange_;
KeyframeCallback onKeyframe_;
SoundTriggerCallback onSoundTrigger_;
CompletionCallback onComplete_;
// 内部方法
void advanceFrame(size_t newIndex);
void processFrameProperties(const AnimationFrame &frame);
void updateInterpolation();
};
} // namespace extra2d

View File

@ -1,43 +0,0 @@
#pragma once
#include <cstdint>
#include <functional>
#include <string>
namespace extra2d {
// 前向声明
class Node;
// ============================================================================
// 动画事件类型
// ============================================================================
enum class AnimationEventType : uint32_t {
FrameChanged = 0x2001, // 帧切换
KeyframeHit = 0x2002, // 关键帧触发
SoundTrigger = 0x2003, // 音效触发
AnimationStart = 0x2004, // 动画开始播放
AnimationEnd = 0x2005, // 动画播放结束
AnimationLoop = 0x2006, // 动画循环一轮
};
// ============================================================================
// 动画事件数据
// ============================================================================
struct AnimationEvent {
AnimationEventType type;
size_t frameIndex = 0;
size_t previousFrameIndex = 0;
int keyframeFlag = -1;
std::string soundPath;
Node *source = nullptr;
};
// ============================================================================
// 动画事件回调类型
// ============================================================================
using AnimationEventCallback = std::function<void(const AnimationEvent &)>;
using KeyframeHitCallback = std::function<void(int flagIndex)>;
using AnimationCompleteCallback = std::function<void()>;
} // namespace extra2d

View File

@ -1,62 +0,0 @@
#pragma once
#include <array>
#include <cstdint>
#include <extra2d/animation/frame_property.h>
#include <extra2d/animation/sprite_frame.h>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// AnimationFrame - 单帧数据
// 引用 SpriteFrame 而非直接持有纹理(借鉴 Cocos 模式)
// 通过 FramePropertySet 支持不固定数据ANI Flag 系统增强版)
// ============================================================================
struct AnimationFrame {
// ------ 核心数据(固定部分)------
Ptr<SpriteFrame> spriteFrame; // 精灵帧引用Cocos 模式)
std::string texturePath; // 原始图片路径(用于解析时定位资源)
int textureIndex = 0; // 精灵图集索引
Vec2 offset; // 位置偏移
float delay = 100.0f; // 帧延迟(毫秒)
// ------ 碰撞盒数据DNF ANI 格式)------
std::vector<std::array<int32_t, 6>> damageBoxes; // 伤害碰撞盒
std::vector<std::array<int32_t, 6>> attackBoxes; // 攻击碰撞盒
// ------ 不固定数据(属性集合)------
FramePropertySet properties; // 类型安全的 Flag 系统
// ------ 便捷方法 ------
bool hasTexture() const {
return spriteFrame != nullptr && spriteFrame->isValid();
}
bool hasInterpolation() const {
return properties.getOr<bool>(FramePropertyKey::Interpolation, false);
}
bool hasKeyframeCallback() const {
return properties.has(FramePropertyKey::SetFlag);
}
int getKeyframeIndex() const {
return properties.getOr<int>(FramePropertyKey::SetFlag, -1);
}
Vec2 getEffectiveScale() const {
return properties.getOr<Vec2>(FramePropertyKey::ImageRate, Vec2::One());
}
float getEffectiveRotation() const {
return properties.getOr<float>(FramePropertyKey::ImageRotate, 0.0f);
}
Color getEffectiveColor() const {
return properties.getOr<Color>(FramePropertyKey::ColorTint, Colors::White);
}
};
} // namespace extra2d

View File

@ -1,108 +0,0 @@
#pragma once
#include <extra2d/animation/animation_cache.h>
#include <extra2d/animation/animation_clip.h>
#include <extra2d/animation/animation_controller.h>
#include <extra2d/animation/animation_event.h>
#include <extra2d/animation/frame_renderer.h>
#include <extra2d/scene/node.h>
#include <vector>
namespace extra2d {
// ============================================================================
// AnimationNode - 动画节点(继承 Node
// 使用 FrameRenderer 单渲染器策略,不依赖 Sprite 基类
// 适用于需要独立渲染控制的动画(如特效、复合动画图层)
// ============================================================================
class AnimationNode : public Node {
public:
AnimationNode();
~AnimationNode() override = default;
// ------ 静态工厂Cocos 风格)------
static Ptr<AnimationNode> create();
static Ptr<AnimationNode> create(Ptr<AnimationClip> clip);
static Ptr<AnimationNode> create(const std::string &aniFilePath);
// ------ 动画数据 ------
void setClip(Ptr<AnimationClip> clip);
Ptr<AnimationClip> getClip() const;
bool loadFromFile(const std::string &aniFilePath);
// ------ 播放控制 ------
void play();
void pause();
void resume();
void stop();
void reset();
bool isPlaying() const;
bool isPaused() const;
bool isStopped() const;
void setPlaybackSpeed(float speed);
float getPlaybackSpeed() const;
void setLooping(bool loop);
bool isLooping() const;
// ------ 帧控制 ------
void setFrameIndex(size_t index);
size_t getCurrentFrameIndex() const;
size_t getTotalFrames() const;
// ------ 事件回调 ------
void setKeyframeCallback(KeyframeHitCallback callback);
void setCompletionCallback(AnimationCompleteCallback callback);
void
setFrameChangeCallback(AnimationController::FrameChangeCallback callback);
void addEventListener(AnimationEventCallback callback);
// ------ 视觉属性 ------
void setTintColor(const Color &color);
Color getTintColor() const { return tintColor_; }
void setFlipX(bool flip) { flipX_ = flip; }
void setFlipY(bool flip) { flipY_ = flip; }
bool isFlipX() const { return flipX_; }
bool isFlipY() const { return flipY_; }
// ------ 自动播放 ------
void setAutoPlay(bool autoPlay) { autoPlay_ = autoPlay; }
bool isAutoPlay() const { return autoPlay_; }
// ------ 碰撞盒访问 ------
const std::vector<std::array<int32_t, 6>> &getCurrentDamageBoxes() const;
const std::vector<std::array<int32_t, 6>> &getCurrentAttackBoxes() const;
// ------ 查询 ------
Size getMaxFrameSize() const;
Rect getBoundingBox() const override;
// ------ 直接访问 ------
AnimationController &getController() { return controller_; }
const AnimationController &getController() const { return controller_; }
FrameRenderer &getFrameRenderer() { return frameRenderer_; }
const FrameRenderer &getFrameRenderer() const { return frameRenderer_; }
protected:
void onUpdate(float dt) override;
void onDraw(RenderBackend &renderer) override;
void onEnter() override;
void onExit() override;
private:
AnimationController controller_;
FrameRenderer frameRenderer_;
Color tintColor_ = Colors::White;
bool flipX_ = false;
bool flipY_ = false;
bool autoPlay_ = false;
std::vector<AnimationEventCallback> eventListeners_;
static const std::vector<std::array<int32_t, 6>> emptyBoxes_;
void setupControllerCallbacks();
void dispatchEvent(const AnimationEvent &event);
};
} // namespace extra2d

View File

@ -1,65 +0,0 @@
#pragma once
#include <extra2d/animation/als_parser.h>
#include <extra2d/animation/animation_event.h>
#include <extra2d/animation/animation_node.h>
#include <extra2d/scene/node.h>
#include <vector>
namespace extra2d {
// ============================================================================
// CompositeAnimation - ALS 多层复合动画节点
// 管理多个 AnimationNode 图层,统一控制播放
// 对应 DNF 的 ALS 格式(多层动画叠加)
// ============================================================================
class CompositeAnimation : public Node {
public:
CompositeAnimation() = default;
~CompositeAnimation() override = default;
// ------ 静态工厂 ------
static Ptr<CompositeAnimation> create();
static Ptr<CompositeAnimation> create(const std::string &alsFilePath);
// ------ 加载 ------
bool loadFromFile(const std::string &alsFilePath);
// ------ 图层管理 ------
void addLayer(Ptr<AnimationNode> node, int zOrder = 0);
void removeLayer(size_t index);
Ptr<AnimationNode> getLayer(size_t index) const;
Ptr<AnimationNode> getMainLayer() const;
size_t getLayerCount() const;
// ------ 统一播放控制 ------
void play();
void pause();
void resume();
void stop();
void reset();
void setPlaybackSpeed(float speed);
void setLooping(bool loop);
bool isPlaying() const;
bool isStopped() const;
// ------ 事件回调(绑定到主图层)------
void setKeyframeCallback(KeyframeHitCallback callback);
void setCompletionCallback(AnimationCompleteCallback callback);
void addEventListener(AnimationEventCallback callback);
// ------ 视觉属性(应用到所有图层)------
void setTintColor(const Color &color);
void setFlipX(bool flip);
void setFlipY(bool flip);
private:
struct LayerEntry {
Ptr<AnimationNode> node;
int zOrder = 0;
};
std::vector<LayerEntry> layers_;
};
} // namespace extra2d

View File

@ -1,210 +0,0 @@
#pragma once
#include <any>
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace extra2d {
// ============================================================================
// 帧属性键 - 强类型枚举替代原始 ANI 的字符串键
// ============================================================================
enum class FramePropertyKey : uint32 {
// 事件触发
SetFlag = 0x0001, // int: 关键帧回调索引
PlaySound = 0x0002, // string: 音效路径
// 变换属性
ImageRate = 0x0010, // Vec2: 缩放比例
ImageRotate = 0x0011, // float: 旋转角度(度)
ImageOffset = 0x0012, // Vec2: 额外位置偏移
// 视觉效果
BlendLinearDodge = 0x0020, // bool: 线性减淡
BlendAdditive = 0x0021, // bool: 加法混合
ColorTint = 0x0022, // Color: RGBA 颜色
// 控制标记
Interpolation = 0x0030, // bool: 启用到下一帧的插值
Loop = 0x0031, // bool: 全局循环标记
// DNF ANI 扩展属性
DamageType = 0x0040, // int: 伤害类型 (0=Normal, 1=SuperArmor, 2=Unbreakable)
Shadow = 0x0041, // bool: 阴影
FlipType = 0x0042, // int: 翻转类型 (1=Horizon, 2=Vertical, 3=All)
Coord = 0x0043, // int: 坐标系
LoopStart = 0x0044, // bool: 循环起始标记
LoopEnd = 0x0045, // int: 循环结束帧数
GraphicEffect = 0x0046, // int: 图形特效类型
ClipRegion = 0x0047, // vector<int>: 裁剪区域 [4个int16]
// 用户自定义扩展区间 (0x1000+)
UserDefined = 0x1000,
};
// ============================================================================
// 帧属性值 - variant 多态值(优化版本)
// 使用紧凑存储,常用小类型直接内联,大类型使用索引引用
// ============================================================================
// 前向声明
struct FramePropertyValue;
// 属性存储类型枚举
enum class PropertyValueType : uint8_t {
Empty = 0,
Bool = 1,
Int = 2,
Float = 3,
Vec2 = 4,
Color = 5,
String = 6, // 字符串使用索引引用
IntVector = 7, // vector<int> 使用索引引用
};
// 紧凑的属性值结构16字节
struct FramePropertyValue {
PropertyValueType type = PropertyValueType::Empty;
uint8_t padding[3] = {0};
// 使用结构体包装非平凡类型使其可以在union中使用
struct Vec2Storage {
float x, y;
Vec2Storage() = default;
Vec2Storage(const Vec2& v) : x(v.x), y(v.y) {}
operator Vec2() const { return Vec2(x, y); }
};
struct ColorStorage {
float r, g, b, a;
ColorStorage() = default;
ColorStorage(const Color& c) : r(c.r), g(c.g), b(c.b), a(c.a) {}
operator Color() const { return Color(r, g, b, a); }
};
union Data {
bool boolValue;
int intValue;
float floatValue;
Vec2Storage vec2Value;
ColorStorage colorValue;
uint32_t stringIndex; // 字符串池索引
uint32_t vectorIndex; // vector池索引
Data() : intValue(0) {} // 默认构造函数
~Data() {} // 析构函数
} data;
FramePropertyValue() : type(PropertyValueType::Empty) {}
explicit FramePropertyValue(bool v) : type(PropertyValueType::Bool) { data.boolValue = v; }
explicit FramePropertyValue(int v) : type(PropertyValueType::Int) { data.intValue = v; }
explicit FramePropertyValue(float v) : type(PropertyValueType::Float) { data.floatValue = v; }
explicit FramePropertyValue(const Vec2& v) : type(PropertyValueType::Vec2) { data.vec2Value = v; }
explicit FramePropertyValue(const Color& v) : type(PropertyValueType::Color) { data.colorValue = v; }
bool isInline() const {
return type <= PropertyValueType::Color;
}
bool isString() const { return type == PropertyValueType::String; }
bool isIntVector() const { return type == PropertyValueType::IntVector; }
};
// ============================================================================
// FramePropertyKey 的 hash 支持
// ============================================================================
struct FramePropertyKeyHash {
size_t operator()(FramePropertyKey key) const noexcept {
return std::hash<uint32>{}(static_cast<uint32>(key));
}
};
// ============================================================================
// FramePropertySet - 单帧属性集合(优化版本)
// 使用紧凑存储和线性探测哈希表,提高缓存命中率
// ============================================================================
class FramePropertySet {
public:
FramePropertySet() = default;
// ------ 设置属性 ------
void set(FramePropertyKey key, FramePropertyValue value);
void set(FramePropertyKey key, bool value) { set(key, FramePropertyValue(value)); }
void set(FramePropertyKey key, int value) { set(key, FramePropertyValue(value)); }
void set(FramePropertyKey key, float value) { set(key, FramePropertyValue(value)); }
void set(FramePropertyKey key, const Vec2& value) { set(key, FramePropertyValue(value)); }
void set(FramePropertyKey key, const Color& value) { set(key, FramePropertyValue(value)); }
void set(FramePropertyKey key, const std::string& value);
void set(FramePropertyKey key, const std::vector<int>& value);
void setCustom(const std::string &key, std::any value);
// ------ 类型安全获取 ------
template <typename T> std::optional<T> get(FramePropertyKey key) const;
template <typename T>
T getOr(FramePropertyKey key, const T &defaultValue) const {
auto result = get<T>(key);
return result.value_or(defaultValue);
}
std::optional<std::any> getCustom(const std::string &key) const;
// ------ 查询 ------
bool has(FramePropertyKey key) const;
bool hasCustom(const std::string &key) const;
bool empty() const { return properties_.empty() && customProperties_.empty(); }
size_t count() const { return properties_.size() + customProperties_.size(); }
// ------ 移除 ------
void remove(FramePropertyKey key);
void removeCustom(const std::string &key);
void clear();
// ------ 迭代 ------
using PropertyMap = std::unordered_map<FramePropertyKey, FramePropertyValue,
FramePropertyKeyHash>;
const PropertyMap &properties() const { return properties_; }
// ------ 链式 API ------
FramePropertySet &withSetFlag(int index);
FramePropertySet &withPlaySound(const std::string &path);
FramePropertySet &withImageRate(const Vec2 &scale);
FramePropertySet &withImageRotate(float degrees);
FramePropertySet &withColorTint(const Color &color);
FramePropertySet &withInterpolation(bool enabled = true);
FramePropertySet &withBlendLinearDodge(bool enabled = true);
FramePropertySet &withLoop(bool enabled = true);
private:
PropertyMap properties_;
std::unordered_map<std::string, std::any> customProperties_;
// 字符串池和vector池用于存储大对象
mutable std::vector<std::string> stringPool_;
mutable std::vector<std::vector<int>> vectorPool_;
mutable uint32_t nextStringIndex_ = 0;
mutable uint32_t nextVectorIndex_ = 0;
uint32_t allocateString(const std::string& str);
uint32_t allocateVector(const std::vector<int>& vec);
const std::string* getString(uint32_t index) const;
const std::vector<int>* getVector(uint32_t index) const;
};
// 模板特化声明
template <> std::optional<bool> FramePropertySet::get<bool>(FramePropertyKey key) const;
template <> std::optional<int> FramePropertySet::get<int>(FramePropertyKey key) const;
template <> std::optional<float> FramePropertySet::get<float>(FramePropertyKey key) const;
template <> std::optional<Vec2> FramePropertySet::get<Vec2>(FramePropertyKey key) const;
template <> std::optional<Color> FramePropertySet::get<Color>(FramePropertyKey key) const;
template <> std::optional<std::string> FramePropertySet::get<std::string>(FramePropertyKey key) const;
template <> std::optional<std::vector<int>> FramePropertySet::get<std::vector<int>>(FramePropertyKey key) const;
} // namespace extra2d

View File

@ -1,57 +0,0 @@
#pragma once
#include <extra2d/animation/animation_frame.h>
#include <extra2d/animation/interpolation_engine.h>
#include <extra2d/animation/sprite_frame.h>
#include <extra2d/animation/sprite_frame_cache.h>
#include <extra2d/graphics/render_backend.h>
#include <vector>
namespace extra2d {
// ============================================================================
// FrameRenderer - 帧渲染器
// 单渲染器 + SpriteFrame 引用策略,替代 N帧=N个Sprite 的旧设计
// 负责预加载帧的 SpriteFrame、渲染当前帧、处理混合模式
// ============================================================================
class FrameRenderer {
public:
FrameRenderer() = default;
// ------ 预加载 ------
// 解析所有帧的 SpriteFrame通过 SpriteFrameCache
bool preloadFrames(const std::vector<AnimationFrame> &frames);
void releaseFrames();
// ------ 渲染当前帧 ------
void renderFrame(RenderBackend &renderer, const AnimationFrame &frame,
size_t frameIndex, const Vec2 &position, float nodeOpacity,
const Color &tintColor, bool flipX, bool flipY);
// ------ 渲染插值帧 ------
void renderInterpolated(RenderBackend &renderer,
const AnimationFrame &fromFrame, size_t fromIndex,
const InterpolatedProperties &props,
const Vec2 &position, float nodeOpacity,
const Color &tintColor, bool flipX, bool flipY);
// ------ 混合模式映射 ------
static BlendMode mapBlendMode(const FramePropertySet &props);
// ------ 查询 ------
Ptr<SpriteFrame> getSpriteFrame(size_t frameIndex) const;
Size getMaxFrameSize() const { return maxFrameSize_; }
bool isLoaded() const { return !spriteFrames_.empty(); }
private:
std::vector<Ptr<SpriteFrame>> spriteFrames_;
Size maxFrameSize_;
void drawSpriteFrame(RenderBackend &renderer, Ptr<SpriteFrame> sf,
const Vec2 &position, const Vec2 &offset,
const Vec2 &scale, float rotation, float opacity,
const Color &tint, bool flipX, bool flipY,
BlendMode blend);
};
} // namespace extra2d

View File

@ -1,106 +0,0 @@
#pragma once
#include <cmath>
#include <extra2d/animation/animation_frame.h>
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
namespace extra2d {
// ============================================================================
// 插值结果 - 两帧之间的插值后属性
// ============================================================================
struct InterpolatedProperties {
Vec2 position;
Vec2 scale = Vec2::One();
float rotation = 0.0f;
Color color = Colors::White;
};
// ============================================================================
// 插值曲线类型
// ============================================================================
enum class InterpolationCurve : uint8 {
Linear, // 线性(原始系统的 uniform velocity
EaseIn, // 缓入
EaseOut, // 缓出
EaseInOut, // 缓入缓出
};
// ============================================================================
// InterpolationEngine - 帧间属性插值计算(静态方法,无状态)
// 独立于 AnimationController可复用于其他系统
// ============================================================================
class InterpolationEngine {
public:
/// 核心插值计算:根据 t 因子 (0~1) 计算两帧之间的插值属性
static InterpolatedProperties
interpolate(const AnimationFrame &from, const AnimationFrame &to, float t,
InterpolationCurve curve = InterpolationCurve::Linear) {
float curvedT = applyCurve(t, curve);
InterpolatedProperties result;
result.position = lerpPosition(from, to, curvedT);
result.scale = lerpScale(from, to, curvedT);
result.rotation = lerpRotation(from, to, curvedT);
result.color = lerpColor(from, to, curvedT);
return result;
}
/// 位置插值
static Vec2 lerpPosition(const AnimationFrame &from, const AnimationFrame &to,
float t) {
return Vec2::lerp(from.offset, to.offset, t);
}
/// 缩放插值
static Vec2 lerpScale(const AnimationFrame &from, const AnimationFrame &to,
float t) {
Vec2 fromScale = from.getEffectiveScale();
Vec2 toScale = to.getEffectiveScale();
return Vec2::lerp(fromScale, toScale, t);
}
/// 旋转插值
static float lerpRotation(const AnimationFrame &from,
const AnimationFrame &to, float t) {
float fromRot = from.getEffectiveRotation();
float toRot = to.getEffectiveRotation();
return math::lerp(fromRot, toRot, t);
}
/// 颜色插值
static Color lerpColor(const AnimationFrame &from, const AnimationFrame &to,
float t) {
Color fromColor = from.getEffectiveColor();
Color toColor = to.getEffectiveColor();
return Color::lerp(fromColor, toColor, t);
}
/// 应用曲线函数
static float applyCurve(float t, InterpolationCurve curve) {
t = math::clamp(t, 0.0f, 1.0f);
switch (curve) {
case InterpolationCurve::Linear:
return t;
case InterpolationCurve::EaseIn:
return t * t;
case InterpolationCurve::EaseOut:
return t * (2.0f - t);
case InterpolationCurve::EaseInOut:
if (t < 0.5f)
return 2.0f * t * t;
else
return -1.0f + (4.0f - 2.0f * t) * t;
}
return t;
}
};
} // namespace extra2d

View File

@ -1,73 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture.h>
#include <string>
namespace extra2d {
// ============================================================================
// SpriteFrame - 精灵帧(纹理 + 区域 + 偏移的中间抽象)
// 借鉴 Cocos2d-x SpriteFrame解耦纹理物理存储与逻辑帧
// 一个纹理图集可包含多个 SpriteFrame减少纹理切换提升渲染性能
// ============================================================================
class SpriteFrame {
public:
SpriteFrame() = default;
SpriteFrame(Ptr<Texture> texture, const Rect &rect)
: texture_(std::move(texture)), rect_(rect), originalSize_(rect.size) {}
SpriteFrame(Ptr<Texture> texture, const Rect &rect, const Vec2 &offset,
const Size &originalSize)
: texture_(std::move(texture)), rect_(rect), offset_(offset),
originalSize_(originalSize) {}
// ------ 静态创建 ------
static Ptr<SpriteFrame> create(Ptr<Texture> texture, const Rect &rect) {
return makePtr<SpriteFrame>(std::move(texture), rect);
}
static Ptr<SpriteFrame> create(Ptr<Texture> texture, const Rect &rect,
const Vec2 &offset, const Size &originalSize) {
return makePtr<SpriteFrame>(std::move(texture), rect, offset, originalSize);
}
// ------ 纹理信息 ------
void setTexture(Ptr<Texture> texture) { texture_ = std::move(texture); }
Ptr<Texture> getTexture() const { return texture_; }
// ------ 矩形区域(在纹理图集中的位置)------
void setRect(const Rect &rect) { rect_ = rect; }
const Rect &getRect() const { return rect_; }
// ------ 偏移(图集打包时的裁剪偏移)------
void setOffset(const Vec2 &offset) { offset_ = offset; }
const Vec2 &getOffset() const { return offset_; }
// ------ 原始尺寸(裁剪前的完整尺寸)------
void setOriginalSize(const Size &size) { originalSize_ = size; }
const Size &getOriginalSize() const { return originalSize_; }
// ------ 旋转标志图集工具可能旋转90度------
void setRotated(bool rotated) { rotated_ = rotated; }
bool isRotated() const { return rotated_; }
// ------ 名称(用于缓存索引)------
void setName(const std::string &name) { name_ = name; }
const std::string &getName() const { return name_; }
// ------ 有效性检查 ------
bool isValid() const { return texture_ != nullptr; }
private:
Ptr<Texture> texture_;
Rect rect_;
Vec2 offset_;
Size originalSize_;
bool rotated_ = false;
std::string name_;
};
} // namespace extra2d

View File

@ -1,201 +0,0 @@
#pragma once
#include <extra2d/animation/sprite_frame.h>
#include <extra2d/graphics/texture.h>
#include <extra2d/resource/resource_manager.h>
#include <extra2d/utils/logger.h>
#include <mutex>
#include <string>
#include <unordered_map>
namespace extra2d {
// ============================================================================
// SpriteFrameCache - 精灵帧全局缓存(借鉴 Cocos SpriteFrameCache
// 全局单例管理所有精灵帧,避免重复创建,支持图集自动切割
// ============================================================================
class SpriteFrameCache {
public:
static SpriteFrameCache &getInstance() {
static SpriteFrameCache instance;
return instance;
}
// ------ 添加帧 ------
/// 添加单个精灵帧
void addSpriteFrame(Ptr<SpriteFrame> frame, const std::string &name) {
std::lock_guard<std::mutex> lock(mutex_);
frames_[name] = std::move(frame);
}
/// 从纹理和矩形区域创建并添加帧
void addSpriteFrameFromTexture(Ptr<Texture> texture, const Rect &rect,
const std::string &name) {
auto frame = SpriteFrame::create(std::move(texture), rect);
frame->setName(name);
addSpriteFrame(std::move(frame), name);
}
/// 从纹理图集批量切割添加(等宽等高网格)
void addSpriteFramesFromGrid(const std::string &texturePath, int frameWidth,
int frameHeight, int frameCount = -1,
int spacing = 0, int margin = 0) {
auto texture = loadTextureFromFile(texturePath);
if (!texture)
return;
addSpriteFramesFromGrid(texture, texturePath, frameWidth, frameHeight,
frameCount, spacing, margin);
}
/// 从纹理对象批量切割添加(等宽等高网格,无需走 TexturePool
void addSpriteFramesFromGrid(Ptr<Texture> texture,
const std::string &keyPrefix, int frameWidth,
int frameHeight, int frameCount = -1,
int spacing = 0, int margin = 0) {
if (!texture)
return;
int texW = texture->getWidth();
int texH = texture->getHeight();
int usableW = texW - 2 * margin;
int usableH = texH - 2 * margin;
int cols = (usableW + spacing) / (frameWidth + spacing);
int rows = (usableH + spacing) / (frameHeight + spacing);
int total = (frameCount > 0) ? frameCount : cols * rows;
std::lock_guard<std::mutex> lock(mutex_);
for (int i = 0; i < total; ++i) {
int col = i % cols;
int row = i / cols;
if (row >= rows)
break;
Rect rect(static_cast<float>(margin + col * (frameWidth + spacing)),
static_cast<float>(margin + row * (frameHeight + spacing)),
static_cast<float>(frameWidth),
static_cast<float>(frameHeight));
std::string name = keyPrefix + "#" + std::to_string(i);
auto frame = SpriteFrame::create(texture, rect);
frame->setName(name);
frames_[name] = std::move(frame);
}
}
// ------ 获取帧 ------
/// 按名称获取
Ptr<SpriteFrame> getSpriteFrame(const std::string &name) const {
std::lock_guard<std::mutex> lock(mutex_);
auto it = frames_.find(name);
if (it != frames_.end())
return it->second;
return nullptr;
}
/// 通过路径+索引获取或创建ANI 格式的定位方式)
Ptr<SpriteFrame> getOrCreateFromFile(const std::string &texturePath,
int index = 0) {
std::string key = texturePath + "#" + std::to_string(index);
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = frames_.find(key);
if (it != frames_.end())
return it->second;
}
// 缓存未命中,加载纹理并创建 SpriteFrame
auto texture = loadTextureFromFile(texturePath);
if (!texture)
return nullptr;
// 默认整张纹理作为一帧index=0或用整张纹理
Rect rect(0.0f, 0.0f, static_cast<float>(texture->getWidth()),
static_cast<float>(texture->getHeight()));
auto frame = SpriteFrame::create(texture, rect);
frame->setName(key);
std::lock_guard<std::mutex> lock(mutex_);
frames_[key] = frame;
return frame;
}
// ------ 缓存管理 ------
bool has(const std::string &name) const {
std::lock_guard<std::mutex> lock(mutex_);
return frames_.find(name) != frames_.end();
}
void removeSpriteFrame(const std::string &name) {
std::lock_guard<std::mutex> lock(mutex_);
frames_.erase(name);
}
/// 移除未被外部引用的精灵帧use_count == 1 表示仅缓存自身持有)
void removeUnusedSpriteFrames() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto it = frames_.begin(); it != frames_.end();) {
if (it->second.use_count() == 1) {
it = frames_.erase(it);
} else {
++it;
}
}
}
void clear() {
std::lock_guard<std::mutex> lock(mutex_);
frames_.clear();
}
size_t count() const {
std::lock_guard<std::mutex> lock(mutex_);
return frames_.size();
}
private:
SpriteFrameCache() = default;
~SpriteFrameCache() = default;
SpriteFrameCache(const SpriteFrameCache &) = delete;
SpriteFrameCache &operator=(const SpriteFrameCache &) = delete;
/**
* @brief 使 ResourceManager LRU
* @param filepath
* @return nullptr
*/
Ptr<Texture> loadTextureFromFile(const std::string &filepath) {
// 使用 ResourceManager 的纹理缓存机制
// 这样可以享受 LRU 缓存、自动清理和缓存统计等功能
auto &resources = ResourceManager::getInstance();
// 先检查缓存中是否已有该纹理
auto texture = resources.getTexture(filepath);
if (texture) {
E2D_TRACE("SpriteFrameCache: 使用缓存纹理: {}", filepath);
return texture;
}
// 缓存未命中,通过 ResourceManager 加载
texture = resources.loadTexture(filepath);
if (!texture) {
E2D_ERROR("SpriteFrameCache: 加载纹理失败: {}", filepath);
return nullptr;
}
E2D_TRACE("SpriteFrameCache: 加载新纹理: {}", filepath);
return texture;
}
mutable std::mutex mutex_;
std::unordered_map<std::string, Ptr<SpriteFrame>> frames_;
};
// 便捷宏
#define E2D_SPRITE_FRAME_CACHE() ::extra2d::SpriteFrameCache::getInstance()
} // namespace extra2d

View File

@ -1,139 +0,0 @@
#pragma once
#include <extra2d/core/string.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/render_backend.h>
#include <extra2d/platform/window.h>
#include <memory>
namespace extra2d {
// 前向声明
class Input;
class AudioEngine;
class SceneManager;
class ResourceManager;
class TimerManager;
class EventQueue;
class EventDispatcher;
class Camera;
// ============================================================================
// Application 配置
// ============================================================================
enum class PlatformType {
Auto = 0,
PC,
Switch
};
struct AppConfig {
std::string title = "Easy2D Application";
int width = 800;
int height = 600;
bool fullscreen = false;
bool resizable = true;
bool vsync = true;
int fpsLimit = 0;
BackendType renderBackend = BackendType::OpenGL;
int msaaSamples = 0;
PlatformType platform = PlatformType::Auto;
// 窗口高级配置
bool enableCursors = true; // 是否启用光标
bool enableDpiScale = false; // 是否启用DPI缩放
};
// ============================================================================
// Application 单例 - 应用主控
// ============================================================================
class Application {
public:
// Meyer's 单例
static Application &instance();
// 禁止拷贝
Application(const Application &) = delete;
Application &operator=(const Application &) = delete;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
bool init(const AppConfig &config);
void shutdown();
void run();
void quit();
// ------------------------------------------------------------------------
// 状态控制
// ------------------------------------------------------------------------
void pause();
void resume();
bool isPaused() const { return paused_; }
bool isRunning() const { return running_; }
// ------------------------------------------------------------------------
// 子系统访问
// ------------------------------------------------------------------------
Window &window() { return *window_; }
RenderBackend &renderer() { return *renderer_; }
Input &input();
AudioEngine &audio();
SceneManager &scenes();
ResourceManager &resources();
TimerManager &timers();
EventQueue &eventQueue();
EventDispatcher &eventDispatcher();
Camera &camera();
// ------------------------------------------------------------------------
// 便捷方法
// ------------------------------------------------------------------------
void enterScene(Ptr<class Scene> scene);
void enterScene(Ptr<class Scene> scene, Ptr<class TransitionScene> transitionScene);
float deltaTime() const { return deltaTime_; }
float totalTime() const { return totalTime_; }
int fps() const { return currentFps_; }
// 获取配置
const AppConfig &getConfig() const { return config_; }
private:
Application() = default;
~Application();
void mainLoop();
void update();
void render();
void prewarmObjectPools();
// 配置
AppConfig config_;
// 子系统
UniquePtr<Window> window_;
UniquePtr<RenderBackend> renderer_;
UniquePtr<SceneManager> sceneManager_;
UniquePtr<ResourceManager> resourceManager_;
UniquePtr<TimerManager> timerManager_;
UniquePtr<EventQueue> eventQueue_;
UniquePtr<EventDispatcher> eventDispatcher_;
UniquePtr<Camera> camera_;
// 状态
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,47 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include <extra2d/core/types.h>
namespace extra2d {
class Sound;
class AudioEngine {
public:
static AudioEngine& getInstance();
AudioEngine(const AudioEngine&) = delete;
AudioEngine& operator=(const AudioEngine&) = delete;
AudioEngine(AudioEngine&&) = delete;
AudioEngine& operator=(AudioEngine&&) = delete;
bool initialize();
void shutdown();
std::shared_ptr<Sound> loadSound(const std::string& filePath);
std::shared_ptr<Sound> loadSound(const std::string& name, const std::string& filePath);
std::shared_ptr<Sound> getSound(const std::string& name);
void unloadSound(const std::string& name);
void unloadAllSounds();
void setMasterVolume(float volume);
float getMasterVolume() const;
void pauseAll();
void resumeAll();
void stopAll();
private:
AudioEngine() = default;
~AudioEngine();
std::unordered_map<std::string, std::shared_ptr<Sound>> sounds_;
float masterVolume_ = 1.0f;
bool initialized_ = false;
};
} // namespace extra2d

View File

@ -1,57 +0,0 @@
#pragma once
#include <string>
#include <extra2d/core/types.h>
struct Mix_Chunk;
namespace extra2d {
class AudioEngine;
class Sound {
public:
~Sound();
Sound(const Sound&) = delete;
Sound& operator=(const Sound&) = delete;
bool play();
void pause();
void resume();
void stop();
bool isPlaying() const;
bool isPaused() const;
void setVolume(float volume);
float getVolume() const { return volume_; }
void setLooping(bool looping);
bool isLooping() const { return looping_; }
void setPitch(float pitch);
float getPitch() const { return pitch_; }
float getDuration() const;
float getCursor() const;
void setCursor(float seconds);
const std::string& getFilePath() const { return filePath_; }
const std::string& getName() const { return name_; }
private:
friend class AudioEngine;
Sound(const std::string& name, const std::string& filePath, Mix_Chunk* chunk);
std::string name_;
std::string filePath_;
Mix_Chunk* chunk_ = nullptr;
int channel_ = -1; // SDL_mixer 分配的通道,-1 表示未播放
float volume_ = 1.0f;
float pitch_ = 1.0f;
bool looping_ = false;
};
} // namespace extra2d

View File

@ -1,171 +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
// 为了向后兼容,在 Color 结构体内提供静态引用
struct ColorConstants {
static const Color &White;
static const Color &Black;
static const Color &Red;
static const Color &Green;
static const Color &Blue;
static const Color &Yellow;
static const Color &Cyan;
static const Color &Magenta;
static const Color &Transparent;
};
} // namespace extra2d

View File

@ -1,335 +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; }
} // namespace math
} // namespace extra2d

View File

@ -1,209 +0,0 @@
#pragma once
#include <string>
namespace extra2d {
// ============================================================================
// 字符串编码转换工具函数
// 统一使用 std::string (UTF-8) 作为项目标准字符串类型
// ============================================================================
// UTF-8 ↔ UTF-16 转换
std::u16string utf8ToUtf16(const std::string& utf8);
std::string utf16ToUtf8(const std::u16string& utf16);
// UTF-8 ↔ UTF-32 转换
std::u32string utf8ToUtf32(const std::string& utf8);
std::string utf32ToUtf8(const std::u32string& utf32);
// UTF-8 ↔ Wide String 转换
std::wstring utf8ToWide(const std::string& utf8);
std::string wideToUtf8(const std::wstring& wide);
// UTF-8 ↔ GBK/GB2312 转换Windows 中文系统常用)
std::string utf8ToGbk(const std::string& utf8);
std::string gbkToUtf8(const std::string& gbk);
// ============================================================================
// 内联实现
// ============================================================================
inline std::u16string utf8ToUtf16(const std::string& utf8) {
if (utf8.empty()) return std::u16string();
// UTF-8 → UTF-32 → UTF-16 (with surrogate pairs)
std::u32string u32 = utf8ToUtf32(utf8);
std::u16string result;
result.reserve(u32.size());
for (char32_t ch : u32) {
if (ch <= 0xFFFF) {
result.push_back(static_cast<char16_t>(ch));
} else if (ch <= 0x10FFFF) {
// Surrogate pair
ch -= 0x10000;
result.push_back(static_cast<char16_t>(0xD800 | (ch >> 10)));
result.push_back(static_cast<char16_t>(0xDC00 | (ch & 0x3FF)));
}
}
return result;
}
inline std::string utf16ToUtf8(const std::u16string& utf16) {
if (utf16.empty()) return std::string();
// UTF-16 → UTF-32 → UTF-8
std::u32string u32;
u32.reserve(utf16.size());
for (size_t i = 0; i < utf16.size(); ++i) {
char16_t cu = utf16[i];
char32_t ch;
if (cu >= 0xD800 && cu <= 0xDBFF && i + 1 < utf16.size()) {
// High surrogate
char16_t cl = utf16[i + 1];
if (cl >= 0xDC00 && cl <= 0xDFFF) {
ch = 0x10000 + ((static_cast<char32_t>(cu - 0xD800) << 10) |
(cl - 0xDC00));
++i;
} else {
ch = cu; // Invalid, pass through
}
} else {
ch = cu;
}
u32.push_back(ch);
}
return utf32ToUtf8(u32);
}
inline std::u32string utf8ToUtf32(const std::string& utf8) {
std::u32string result;
result.reserve(utf8.size());
const char* ptr = utf8.c_str();
const char* end = ptr + utf8.size();
while (ptr < end) {
char32_t ch = 0;
unsigned char byte = static_cast<unsigned char>(*ptr);
if ((byte & 0x80) == 0) {
// 1-byte sequence
ch = byte;
ptr += 1;
} else if ((byte & 0xE0) == 0xC0) {
// 2-byte sequence
ch = (byte & 0x1F) << 6;
ch |= (static_cast<unsigned char>(ptr[1]) & 0x3F);
ptr += 2;
} else if ((byte & 0xF0) == 0xE0) {
// 3-byte sequence
ch = (byte & 0x0F) << 12;
ch |= (static_cast<unsigned char>(ptr[1]) & 0x3F) << 6;
ch |= (static_cast<unsigned char>(ptr[2]) & 0x3F);
ptr += 3;
} else if ((byte & 0xF8) == 0xF0) {
// 4-byte sequence
ch = (byte & 0x07) << 18;
ch |= (static_cast<unsigned char>(ptr[1]) & 0x3F) << 12;
ch |= (static_cast<unsigned char>(ptr[2]) & 0x3F) << 6;
ch |= (static_cast<unsigned char>(ptr[3]) & 0x3F);
ptr += 4;
} else {
// Invalid UTF-8, skip
ptr += 1;
continue;
}
result.push_back(ch);
}
return result;
}
inline std::string utf32ToUtf8(const std::u32string& utf32) {
std::string result;
for (char32_t ch : utf32) {
if (ch <= 0x7F) {
// 1-byte
result.push_back(static_cast<char>(ch));
} else if (ch <= 0x7FF) {
// 2-byte
result.push_back(static_cast<char>(0xC0 | ((ch >> 6) & 0x1F)));
result.push_back(static_cast<char>(0x80 | (ch & 0x3F)));
} else if (ch <= 0xFFFF) {
// 3-byte
result.push_back(static_cast<char>(0xE0 | ((ch >> 12) & 0x0F)));
result.push_back(static_cast<char>(0x80 | ((ch >> 6) & 0x3F)));
result.push_back(static_cast<char>(0x80 | (ch & 0x3F)));
} else if (ch <= 0x10FFFF) {
// 4-byte
result.push_back(static_cast<char>(0xF0 | ((ch >> 18) & 0x07)));
result.push_back(static_cast<char>(0x80 | ((ch >> 12) & 0x3F)));
result.push_back(static_cast<char>(0x80 | ((ch >> 6) & 0x3F)));
result.push_back(static_cast<char>(0x80 | (ch & 0x3F)));
}
}
return result;
}
inline std::wstring utf8ToWide(const std::string& utf8) {
if (utf8.empty()) return std::wstring();
if constexpr (sizeof(wchar_t) == 4) {
// wchar_t is 32-bit (Linux/Switch): same as UTF-32
std::u32string u32 = utf8ToUtf32(utf8);
return std::wstring(u32.begin(), u32.end());
} else {
// wchar_t is 16-bit (Windows): same as UTF-16
std::u16string u16 = utf8ToUtf16(utf8);
return std::wstring(u16.begin(), u16.end());
}
}
inline std::string wideToUtf8(const std::wstring& wide) {
if (wide.empty()) return std::string();
if constexpr (sizeof(wchar_t) == 4) {
std::u32string u32(wide.begin(), wide.end());
return utf32ToUtf8(u32);
} else {
std::u16string u16(wide.begin(), wide.end());
return utf16ToUtf8(u16);
}
}
// GBK/GB2312 转换Windows 平台实现)
// 注意Windows 实现在 .cpp 文件中,避免头文件包含 windows.h 导致冲突
#ifdef _WIN32
// 前向声明,实现在 .cpp 文件中
std::string utf8ToGbkImpl(const std::string& utf8);
std::string gbkToUtf8Impl(const std::string& gbk);
inline std::string utf8ToGbk(const std::string& utf8) {
return utf8ToGbkImpl(utf8);
}
inline std::string gbkToUtf8(const std::string& gbk) {
return gbkToUtf8Impl(gbk);
}
#else
// 非 Windows 平台GBK 转换使用 iconv 或返回原字符串
inline std::string utf8ToGbk(const std::string& utf8) {
// TODO: 使用 iconv 实现
return utf8;
}
inline std::string gbkToUtf8(const std::string& gbk) {
// TODO: 使用 iconv 实现
return gbk;
}
#endif
} // namespace extra2d

View File

@ -1,47 +0,0 @@
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
namespace extra2d {
// ---------------------------------------------------------------------------
// 智能指针别名
// ---------------------------------------------------------------------------
template <typename T> using Ptr = 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)...);
}
/// 创建 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,324 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/effects/particle_system.h>
#include <extra2d/effects/post_process.h>
#include <extra2d/graphics/shader_system.h>
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// 自定义特效类型
// ============================================================================
enum class CustomEffectType {
Particle, // 粒子特效
PostProcess, // 后处理特效
Shader, // Shader特效
Combined // 组合特效
};
// ============================================================================
// 自定义特效配置
// ============================================================================
struct CustomEffectConfig {
std::string name; // 特效名称
CustomEffectType type; // 特效类型
std::string description; // 描述
// 粒子特效配置
EmitterConfig emitterConfig;
// 后处理特效配置
std::string shaderVertPath; // 顶点着色器路径
std::string shaderFragPath; // 片段着色器路径
std::unordered_map<std::string, float> shaderParams; // Shader参数
// 通用配置
float duration; // 持续时间(-1表示无限)
bool loop; // 是否循环
float delay; // 延迟启动时间
};
// ============================================================================
// 自定义特效基类
// ============================================================================
class CustomEffect {
public:
explicit CustomEffect(const CustomEffectConfig &config);
virtual ~CustomEffect() = default;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
virtual bool init();
virtual void update(float dt);
virtual void render(RenderBackend &renderer);
virtual void shutdown();
// ------------------------------------------------------------------------
// 控制
// ------------------------------------------------------------------------
void play();
void pause();
void stop();
void reset();
bool isPlaying() const { return playing_; }
bool isFinished() const { return finished_; }
float getElapsedTime() const { return elapsedTime_; }
// ------------------------------------------------------------------------
// 配置
// ------------------------------------------------------------------------
const std::string &getName() const { return config_.name; }
const CustomEffectConfig &getConfig() const { return config_; }
void setPosition(const Vec2 &pos) { position_ = pos; }
void setRotation(float rot) { rotation_ = rot; }
void setScale(float scale) { scale_ = scale; }
Vec2 getPosition() const { return position_; }
float getRotation() const { return rotation_; }
float getScale() const { return scale_; }
protected:
CustomEffectConfig config_;
Vec2 position_ = Vec2::Zero();
float rotation_ = 0.0f;
float scale_ = 1.0f;
bool playing_ = false;
bool paused_ = false;
bool finished_ = false;
float elapsedTime_ = 0.0f;
float delayTimer_ = 0.0f;
};
// ============================================================================
// 自定义粒子特效
// ============================================================================
class CustomParticleEffect : public CustomEffect {
public:
explicit CustomParticleEffect(const CustomEffectConfig &config);
bool init() override;
void update(float dt) override;
void render(RenderBackend &renderer) override;
void shutdown() override;
void play();
void stop();
Ptr<ParticleEmitter> getEmitter() { return emitter_; }
private:
Ptr<ParticleSystem> particleSystem_;
Ptr<ParticleEmitter> emitter_;
};
// ============================================================================
// 自定义后处理特效
// ============================================================================
class CustomPostProcessEffect : public CustomEffect, public PostProcessEffect {
public:
explicit CustomPostProcessEffect(const CustomEffectConfig &config);
bool init() override;
void update(float dt) override;
void shutdown() override;
void onShaderBind(GLShader &shader) override;
void setParam(const std::string &name, float value);
float getParam(const std::string &name) const;
private:
std::unordered_map<std::string, float> runtimeParams_;
};
// ============================================================================
// 自定义特效工厂
// ============================================================================
class CustomEffectFactory {
public:
using EffectCreator =
std::function<Ptr<CustomEffect>(const CustomEffectConfig &)>;
static CustomEffectFactory &getInstance();
// 注册自定义特效创建器
void registerEffect(const std::string &typeName, EffectCreator creator);
// 创建特效
Ptr<CustomEffect> create(const std::string &typeName,
const CustomEffectConfig &config);
// 检查是否已注册
bool isRegistered(const std::string &typeName) const;
// 获取所有已注册的类型
std::vector<std::string> getRegisteredTypes() const;
private:
CustomEffectFactory() = default;
~CustomEffectFactory() = default;
CustomEffectFactory(const CustomEffectFactory &) = delete;
CustomEffectFactory &operator=(const CustomEffectFactory &) = delete;
std::unordered_map<std::string, EffectCreator> creators_;
};
// ============================================================================
// 自定义特效管理器
// ============================================================================
class CustomEffectManager {
public:
static CustomEffectManager &getInstance();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
bool init();
void shutdown();
// ------------------------------------------------------------------------
// 特效管理
// ------------------------------------------------------------------------
/**
* @brief JSON和文本格式
* JSON格式优先退
*/
bool loadFromFile(const std::string &filepath);
/**
* @brief
* EMISSION 100
*/
bool loadFromTextFile(const std::string &filepath);
/**
* @brief
* @param useJson true=JSON格式, false=
*/
bool saveToFile(const std::string &name, const std::string &filepath,
bool useJson = true);
/**
* @brief JSON文件
*/
bool saveAllToFile(const std::string &filepath);
/**
* @brief
*/
void registerConfig(const std::string &name,
const CustomEffectConfig &config);
/**
* @brief
*/
CustomEffectConfig *getConfig(const std::string &name);
/**
* @brief
*/
void removeConfig(const std::string &name);
/**
* @brief
*/
std::vector<std::string> getConfigNames() const;
// ------------------------------------------------------------------------
// 特效实例管理
// ------------------------------------------------------------------------
/**
* @brief
*/
Ptr<CustomEffect> createEffect(const std::string &name);
/**
* @brief
*/
Ptr<CustomEffect> createEffectFromConfig(const CustomEffectConfig &config);
/**
* @brief
*/
void destroyEffect(Ptr<CustomEffect> effect);
/**
* @brief
*/
void update(float dt);
/**
* @brief
*/
void render(RenderBackend &renderer);
/**
* @brief
*/
void stopAll();
// ------------------------------------------------------------------------
// 便捷方法
// ------------------------------------------------------------------------
/**
* @brief
*/
Ptr<CustomEffect> play(const std::string &name, const Vec2 &position);
/**
* @brief
*/
void playOneShot(const std::string &name, const Vec2 &position);
private:
CustomEffectManager() = default;
~CustomEffectManager() = default;
CustomEffectManager(const CustomEffectManager &) = delete;
CustomEffectManager &operator=(const CustomEffectManager &) = delete;
std::unordered_map<std::string, CustomEffectConfig> configs_;
std::vector<Ptr<CustomEffect>> activeEffects_;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_CUSTOM_EFFECT_MANAGER() \
::extra2d::CustomEffectManager::getInstance()
#define E2D_CUSTOM_EFFECT_FACTORY() \
::extra2d::CustomEffectFactory::getInstance()
// ============================================================================
// 预设特效快速创建
// ============================================================================
class EffectBuilder {
public:
// 粒子特效
static CustomEffectConfig Particle(const std::string &name);
static CustomEffectConfig Fire(const std::string &name);
static CustomEffectConfig Smoke(const std::string &name);
static CustomEffectConfig Explosion(const std::string &name);
static CustomEffectConfig Magic(const std::string &name);
static CustomEffectConfig Sparkle(const std::string &name);
// 后处理特效
static CustomEffectConfig Bloom(const std::string &name);
static CustomEffectConfig Blur(const std::string &name);
static CustomEffectConfig Vignette(const std::string &name);
static CustomEffectConfig ColorGrading(const std::string &name);
};
} // namespace extra2d

View File

@ -1,300 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture.h>
#include <extra2d/scene/node.h>
#include <functional>
#include <random>
#include <vector>
namespace extra2d {
// ============================================================================
// 快速随机数生成器 - 使用 xorshift 算法,比 std::mt19937 更快
// ============================================================================
class FastRNG {
public:
explicit FastRNG(uint32_t seed = 0) : state_(seed ? seed : 0x853c49e67) {}
float nextFloat() {
return static_cast<float>(next()) / static_cast<float>(UINT32_MAX);
}
float nextFloat(float min, float max) {
return min + (max - min) * nextFloat();
}
private:
uint32_t state_;
uint32_t next() {
uint32_t x = state_;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
state_ = x;
return x;
}
};
// ============================================================================
// 粒子数据
// ============================================================================
struct Particle {
Vec2 position;
Vec2 velocity;
Vec2 acceleration;
float rotation;
float angularVelocity;
float size;
float sizeDelta;
Color color;
Color colorDelta;
float life;
float maxLife;
bool active;
Particle()
: position(Vec2::Zero()), velocity(Vec2::Zero()),
acceleration(Vec2::Zero()), rotation(0.0f), angularVelocity(0.0f),
size(1.0f), sizeDelta(0.0f), color(Colors::White),
colorDelta(Colors::Transparent), life(0.0f), maxLife(1.0f),
active(false) {}
};
// ============================================================================
// 发射器配置
// ============================================================================
struct EmitterConfig {
// 发射速率
float emissionRate = 100.0f; // 每秒发射粒子数
float emissionDuration = -1.0f; // 发射持续时间(-1表示无限
// 粒子生命周期
float minLife = 1.0f;
float maxLife = 2.0f;
// 粒子大小
float minStartSize = 10.0f;
float maxStartSize = 20.0f;
float minEndSize = 0.0f;
float maxEndSize = 5.0f;
// 粒子速度
Vec2 minVelocity = Vec2(-50.0f, -50.0f);
Vec2 maxVelocity = Vec2(50.0f, 50.0f);
// 粒子加速度
Vec2 acceleration = Vec2(0.0f, -100.0f); // 重力
// 粒子旋转
float minRotation = 0.0f;
float maxRotation = 360.0f;
float minAngularVelocity = -90.0f;
float maxAngularVelocity = 90.0f;
// 颜色
Color startColor = Colors::White;
Color endColor = Colors::Transparent;
// 发射形状
enum class Shape {
Point, // 点发射
Circle, // 圆形区域
Rectangle, // 矩形区域
Cone // 锥形
};
Shape shape = Shape::Point;
float shapeRadius = 50.0f; // 圆形/锥形半径
Vec2 shapeSize = Vec2(100.0f, 100.0f); // 矩形大小
float coneAngle = 45.0f; // 锥形角度
// 纹理
Ptr<Texture> texture = nullptr;
// 混合模式
BlendMode blendMode = BlendMode::Additive;
};
// ============================================================================
// 粒子发射器
// ============================================================================
class ParticleEmitter {
public:
ParticleEmitter();
~ParticleEmitter() = default;
// 形状生成函数(公有,用于查找表)
Vec2 randomPointShape();
Vec2 randomCircleShape();
Vec2 randomRectangleShape();
Vec2 randomConeShape();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
bool init(size_t maxParticles);
void shutdown();
// ------------------------------------------------------------------------
// 配置
// ------------------------------------------------------------------------
void setConfig(const EmitterConfig &config) { config_ = config; }
const EmitterConfig &getConfig() const { return config_; }
// 链式配置API
ParticleEmitter &withEmissionRate(float rate) {
config_.emissionRate = rate;
return *this;
}
ParticleEmitter &withLife(float minLife, float maxLife) {
config_.minLife = minLife;
config_.maxLife = maxLife;
return *this;
}
ParticleEmitter &withSize(float minStart, float maxStart, float minEnd = 0.0f,
float maxEnd = 0.0f) {
config_.minStartSize = minStart;
config_.maxStartSize = maxStart;
config_.minEndSize = minEnd;
config_.maxEndSize = maxEnd;
return *this;
}
ParticleEmitter &withVelocity(const Vec2 &minVel, const Vec2 &maxVel) {
config_.minVelocity = minVel;
config_.maxVelocity = maxVel;
return *this;
}
ParticleEmitter &withAcceleration(const Vec2 &accel) {
config_.acceleration = accel;
return *this;
}
ParticleEmitter &withColor(const Color &start, const Color &end) {
config_.startColor = start;
config_.endColor = end;
return *this;
}
ParticleEmitter &withTexture(Ptr<Texture> texture) {
config_.texture = texture;
return *this;
}
ParticleEmitter &withBlendMode(BlendMode mode) {
config_.blendMode = mode;
return *this;
}
// ------------------------------------------------------------------------
// 发射控制
// ------------------------------------------------------------------------
void start();
void stop();
void burst(int count); // 爆发发射
void reset();
bool isEmitting() const { return emitting_; }
// ------------------------------------------------------------------------
// 更新和渲染
// ------------------------------------------------------------------------
void update(float dt);
void render(RenderBackend &renderer);
// ------------------------------------------------------------------------
// 状态查询
// ------------------------------------------------------------------------
size_t getActiveParticleCount() const { return activeCount_; }
size_t getMaxParticles() const { return particles_.size(); }
bool isActive() const { return activeCount_ > 0 || emitting_; }
// ------------------------------------------------------------------------
// 变换
// ------------------------------------------------------------------------
void setPosition(const Vec2 &pos) { position_ = pos; }
void setRotation(float rot) { rotation_ = rot; }
Vec2 getPosition() const { return position_; }
float getRotation() const { return rotation_; }
private:
EmitterConfig config_;
std::vector<Particle> particles_;
size_t activeCount_ = 0;
Vec2 position_ = Vec2::Zero();
float rotation_ = 0.0f;
bool emitting_ = false;
float emissionTimer_ = 0.0f;
float emissionTime_ = 0.0f;
FastRNG rng_; // 使用快速 RNG 替代 std::mt19937
void emitParticle();
float randomFloat(float min, float max);
Vec2 randomPointInShape();
Vec2 randomVelocity();
};
// ============================================================================
// 粒子系统 - 管理多个发射器
// ============================================================================
class ParticleSystem : public Node {
public:
ParticleSystem();
~ParticleSystem() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<ParticleSystem> create();
// ------------------------------------------------------------------------
// 发射器管理
// ------------------------------------------------------------------------
Ptr<ParticleEmitter> addEmitter(const EmitterConfig &config = {});
void removeEmitter(Ptr<ParticleEmitter> emitter);
void removeAllEmitters();
size_t getEmitterCount() const { return emitters_.size(); }
// ------------------------------------------------------------------------
// 全局控制
// ------------------------------------------------------------------------
void startAll();
void stopAll();
void resetAll();
// ------------------------------------------------------------------------
// 预设
// ------------------------------------------------------------------------
static EmitterConfig PresetFire();
static EmitterConfig PresetSmoke();
static EmitterConfig PresetExplosion();
static EmitterConfig PresetSparkle();
static EmitterConfig PresetRain();
static EmitterConfig PresetSnow();
// ------------------------------------------------------------------------
// 重写Node方法
// ------------------------------------------------------------------------
void onUpdate(float dt) override;
void onDraw(RenderBackend &renderer) override;
private:
std::vector<Ptr<ParticleEmitter>> emitters_;
};
// ============================================================================
// 粒子预设(便捷类)
// ============================================================================
class ParticlePreset {
public:
static EmitterConfig Fire();
static EmitterConfig Smoke();
static EmitterConfig Explosion();
static EmitterConfig Sparkle();
static EmitterConfig Rain();
static EmitterConfig Snow();
static EmitterConfig Magic();
static EmitterConfig Bubbles();
};
} // namespace extra2d

View File

@ -1,228 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/opengl/gl_shader.h>
#include <extra2d/graphics/texture.h>
#include <functional>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// 前向声明
// ============================================================================
class RenderTarget;
class RenderBackend;
// ============================================================================
// 后处理效果基类
// ============================================================================
class PostProcessEffect {
public:
PostProcessEffect(const std::string &name);
virtual ~PostProcessEffect() = default;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
/**
* @brief
*/
virtual bool init();
/**
* @brief
*/
virtual void shutdown();
// ------------------------------------------------------------------------
// 渲染
// ------------------------------------------------------------------------
/**
* @brief
* @param source
* @param target
* @param renderer
*/
virtual void apply(const Texture &source, RenderTarget &target,
RenderBackend &renderer);
/**
* @brief Shader参数
*/
virtual void onShaderBind(GLShader &shader) {}
// ------------------------------------------------------------------------
// 状态
// ------------------------------------------------------------------------
const std::string &getName() const { return name_; }
bool isEnabled() const { return enabled_; }
void setEnabled(bool enabled) { enabled_ = enabled; }
bool isValid() const { return valid_; }
// ------------------------------------------------------------------------
// 链式API
// ------------------------------------------------------------------------
PostProcessEffect &withEnabled(bool enabled) {
enabled_ = enabled;
return *this;
}
protected:
std::string name_;
bool enabled_ = true;
bool valid_ = false;
Ptr<GLShader> shader_;
/**
* @brief Shader
*/
bool loadShader(const std::string &vertSource, const std::string &fragSource);
bool loadShaderFromFile(const std::string &vertPath,
const std::string &fragPath);
/**
* @brief
*/
void renderFullscreenQuad();
private:
static GLuint quadVao_;
static GLuint quadVbo_;
static bool quadInitialized_;
void initQuad();
void destroyQuad();
};
// ============================================================================
// 后处理栈 - 管理多个后处理效果
// ============================================================================
class PostProcessStack {
public:
PostProcessStack();
~PostProcessStack();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
bool init(int width, int height);
void shutdown();
// ------------------------------------------------------------------------
// 效果管理
// ------------------------------------------------------------------------
/**
* @brief
*/
void addEffect(Ptr<PostProcessEffect> effect);
/**
* @brief
*/
void insertEffect(size_t index, Ptr<PostProcessEffect> effect);
/**
* @brief
*/
void removeEffect(const std::string &name);
void removeEffect(size_t index);
/**
* @brief
*/
Ptr<PostProcessEffect> getEffect(const std::string &name);
Ptr<PostProcessEffect> getEffect(size_t index);
/**
* @brief
*/
void clearEffects();
/**
* @brief
*/
size_t getEffectCount() const { return effects_.size(); }
// ------------------------------------------------------------------------
// 渲染
// ------------------------------------------------------------------------
/**
* @brief
*/
void beginCapture();
/**
* @brief
*/
void endCapture(RenderBackend &renderer);
/**
* @brief
*/
void process(const Texture &source, RenderTarget &target,
RenderBackend &renderer);
// ------------------------------------------------------------------------
// 配置
// ------------------------------------------------------------------------
void resize(int width, int height);
bool isValid() const { return valid_; }
// ------------------------------------------------------------------------
// 便捷方法 - 添加内置效果
// ------------------------------------------------------------------------
PostProcessStack &addBloom(float intensity = 1.0f, float threshold = 0.8f);
PostProcessStack &addBlur(float radius = 2.0f);
PostProcessStack &addColorGrading(const Color &tint);
PostProcessStack &addVignette(float intensity = 0.5f);
PostProcessStack &addChromaticAberration(float amount = 1.0f);
private:
std::vector<Ptr<PostProcessEffect>> effects_;
Ptr<RenderTarget> renderTargetA_;
Ptr<RenderTarget> renderTargetB_;
int width_ = 0;
int height_ = 0;
bool valid_ = false;
bool capturing_ = false;
};
// ============================================================================
// 全局后处理管理
// ============================================================================
class PostProcessManager {
public:
static PostProcessManager &getInstance();
void init(int width, int height);
void shutdown();
PostProcessStack &getMainStack() { return mainStack_; }
void resize(int width, int height);
void beginFrame();
void endFrame(RenderBackend &renderer);
private:
PostProcessManager() = default;
~PostProcessManager() = default;
PostProcessManager(const PostProcessManager &) = delete;
PostProcessManager &operator=(const PostProcessManager &) = delete;
PostProcessStack mainStack_;
bool initialized_ = false;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_POST_PROCESS() ::extra2d::PostProcessManager::getInstance()
} // 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,212 +0,0 @@
#pragma once
// SDL2 键码定义
#include <SDL2/SDL.h>
namespace extra2d {
// ============================================================================
// 键盘按键码 (基于 SDL2)
// ============================================================================
namespace Key {
enum : int {
Unknown = SDLK_UNKNOWN,
Space = SDLK_SPACE,
Apostrophe = SDLK_QUOTE,
Comma = SDLK_COMMA,
Minus = SDLK_MINUS,
Period = SDLK_PERIOD,
Slash = SDLK_SLASH,
Num0 = SDLK_0,
Num1 = SDLK_1,
Num2 = SDLK_2,
Num3 = SDLK_3,
Num4 = SDLK_4,
Num5 = SDLK_5,
Num6 = SDLK_6,
Num7 = SDLK_7,
Num8 = SDLK_8,
Num9 = SDLK_9,
Semicolon = SDLK_SEMICOLON,
Equal = SDLK_EQUALS,
A = SDLK_a,
B = SDLK_b,
C = SDLK_c,
D = SDLK_d,
E = SDLK_e,
F = SDLK_f,
G = SDLK_g,
H = SDLK_h,
I = SDLK_i,
J = SDLK_j,
K = SDLK_k,
L = SDLK_l,
M = SDLK_m,
N = SDLK_n,
O = SDLK_o,
P = SDLK_p,
Q = SDLK_q,
R = SDLK_r,
S = SDLK_s,
T = SDLK_t,
U = SDLK_u,
V = SDLK_v,
W = SDLK_w,
X = SDLK_x,
Y = SDLK_y,
Z = SDLK_z,
LeftBracket = SDLK_LEFTBRACKET,
Backslash = SDLK_BACKSLASH,
RightBracket = SDLK_RIGHTBRACKET,
GraveAccent = SDLK_BACKQUOTE,
Escape = SDLK_ESCAPE,
Enter = SDLK_RETURN,
Tab = SDLK_TAB,
Backspace = SDLK_BACKSPACE,
Insert = SDLK_INSERT,
Delete = SDLK_DELETE,
Right = SDLK_RIGHT,
Left = SDLK_LEFT,
Down = SDLK_DOWN,
Up = SDLK_UP,
PageUp = SDLK_PAGEUP,
PageDown = SDLK_PAGEDOWN,
Home = SDLK_HOME,
End = SDLK_END,
CapsLock = SDLK_CAPSLOCK,
ScrollLock = SDLK_SCROLLLOCK,
NumLock = SDLK_NUMLOCKCLEAR,
PrintScreen = SDLK_PRINTSCREEN,
Pause = SDLK_PAUSE,
F1 = SDLK_F1,
F2 = SDLK_F2,
F3 = SDLK_F3,
F4 = SDLK_F4,
F5 = SDLK_F5,
F6 = SDLK_F6,
F7 = SDLK_F7,
F8 = SDLK_F8,
F9 = SDLK_F9,
F10 = SDLK_F10,
F11 = SDLK_F11,
F12 = SDLK_F12,
F13 = SDLK_F13,
F14 = SDLK_F14,
F15 = SDLK_F15,
F16 = SDLK_F16,
F17 = SDLK_F17,
F18 = SDLK_F18,
F19 = SDLK_F19,
F20 = SDLK_F20,
F21 = SDLK_F21,
F22 = SDLK_F22,
F23 = SDLK_F23,
F24 = SDLK_F24,
KP0 = SDLK_KP_0,
KP1 = SDLK_KP_1,
KP2 = SDLK_KP_2,
KP3 = SDLK_KP_3,
KP4 = SDLK_KP_4,
KP5 = SDLK_KP_5,
KP6 = SDLK_KP_6,
KP7 = SDLK_KP_7,
KP8 = SDLK_KP_8,
KP9 = SDLK_KP_9,
KPDecimal = SDLK_KP_PERIOD,
KPDivide = SDLK_KP_DIVIDE,
KPMultiply = SDLK_KP_MULTIPLY,
KPSubtract = SDLK_KP_MINUS,
KPAdd = SDLK_KP_PLUS,
KPEnter = SDLK_KP_ENTER,
KPEqual = SDLK_KP_EQUALS,
LeftShift = SDLK_LSHIFT,
LeftControl = SDLK_LCTRL,
LeftAlt = SDLK_LALT,
LeftSuper = SDLK_LGUI,
RightShift = SDLK_RSHIFT,
RightControl = SDLK_RCTRL,
RightAlt = SDLK_RALT,
RightSuper = SDLK_RGUI,
Menu = SDLK_MENU,
Last = SDLK_MENU
};
}
// ============================================================================
// 修饰键
// ============================================================================
namespace Mod {
enum : int {
Shift = KMOD_SHIFT,
Control = KMOD_CTRL,
Alt = KMOD_ALT,
Super = KMOD_GUI,
CapsLock = KMOD_CAPS,
NumLock = KMOD_NUM
};
}
// ============================================================================
// 鼠标按键码
// ============================================================================
namespace Mouse {
enum : int {
Button1 = 0,
Button2 = 1,
Button3 = 2,
Button4 = 3,
Button5 = 4,
Button6 = 5,
Button7 = 6,
Button8 = 7,
ButtonLast = Button8,
ButtonLeft = Button1,
ButtonRight = Button2,
ButtonMiddle = Button3
};
}
// ============================================================================
// 游戏手柄按键
// ============================================================================
namespace GamepadButton {
enum : int {
A = SDL_CONTROLLER_BUTTON_A,
B = SDL_CONTROLLER_BUTTON_B,
X = SDL_CONTROLLER_BUTTON_X,
Y = SDL_CONTROLLER_BUTTON_Y,
LeftBumper = SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
RightBumper = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
Back = SDL_CONTROLLER_BUTTON_BACK,
Start = SDL_CONTROLLER_BUTTON_START,
Guide = SDL_CONTROLLER_BUTTON_GUIDE,
LeftThumb = SDL_CONTROLLER_BUTTON_LEFTSTICK,
RightThumb = SDL_CONTROLLER_BUTTON_RIGHTSTICK,
DPadUp = SDL_CONTROLLER_BUTTON_DPAD_UP,
DPadRight = SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
DPadDown = SDL_CONTROLLER_BUTTON_DPAD_DOWN,
DPadLeft = SDL_CONTROLLER_BUTTON_DPAD_LEFT,
Last = SDL_CONTROLLER_BUTTON_DPAD_LEFT,
Cross = A,
Circle = B,
Square = X,
Triangle = Y
};
}
// ============================================================================
// 游戏手柄轴
// ============================================================================
namespace GamepadAxis {
enum : int {
LeftX = SDL_CONTROLLER_AXIS_LEFTX,
LeftY = SDL_CONTROLLER_AXIS_LEFTY,
RightX = SDL_CONTROLLER_AXIS_RIGHTX,
RightY = SDL_CONTROLLER_AXIS_RIGHTY,
LeftTrigger = SDL_CONTROLLER_AXIS_TRIGGERLEFT,
RightTrigger = SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
Last = SDL_CONTROLLER_AXIS_TRIGGERRIGHT
};
}
} // namespace extra2d

View File

@ -1,114 +0,0 @@
#pragma once
// Easy2D v3.0 - 统一入口头文件
// 包含所有公共 API
// Core
#include <extra2d/core/types.h>
#include <extra2d/core/string.h>
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
// Platform
#include <extra2d/platform/window.h>
#include <extra2d/platform/input.h>
// Graphics
#include <extra2d/graphics/render_backend.h>
#include <extra2d/graphics/texture.h>
#include <extra2d/graphics/font.h>
#include <extra2d/graphics/camera.h>
#include <extra2d/graphics/shader_system.h>
#include <extra2d/graphics/render_target.h>
#include <extra2d/graphics/vram_manager.h>
// Scene
#include <extra2d/scene/node.h>
#include <extra2d/scene/scene.h>
#include <extra2d/scene/sprite.h>
#include <extra2d/scene/shape_node.h>
#include <extra2d/scene/scene_manager.h>
#include <extra2d/scene/transition_scene.h>
#include <extra2d/scene/transition_fade_scene.h>
#include <extra2d/scene/transition_slide_scene.h>
#include <extra2d/scene/transition_scale_scene.h>
#include <extra2d/scene/transition_flip_scene.h>
#include <extra2d/scene/transition_box_scene.h>
// Animation
#include <extra2d/animation/sprite_frame.h>
#include <extra2d/animation/sprite_frame_cache.h>
#include <extra2d/animation/frame_property.h>
#include <extra2d/animation/animation_frame.h>
#include <extra2d/animation/animation_clip.h>
#include <extra2d/animation/animation_controller.h>
#include <extra2d/animation/animation_cache.h>
#include <extra2d/animation/interpolation_engine.h>
#include <extra2d/animation/animated_sprite.h>
#include <extra2d/animation/frame_renderer.h>
#include <extra2d/animation/animation_event.h>
#include <extra2d/animation/animation_node.h>
#include <extra2d/animation/composite_animation.h>
#include <extra2d/animation/ani_parser.h>
#include <extra2d/animation/ani_binary_parser.h>
#include <extra2d/animation/als_parser.h>
// UI
#include <extra2d/ui/widget.h>
#include <extra2d/ui/button.h>
#include <extra2d/ui/text.h>
#include <extra2d/ui/label.h>
#include <extra2d/ui/progress_bar.h>
#include <extra2d/ui/check_box.h>
#include <extra2d/ui/radio_button.h>
#include <extra2d/ui/slider.h>
// Action
#include <extra2d/action/action.h>
#include <extra2d/action/finite_time_action.h>
#include <extra2d/action/action_interval.h>
#include <extra2d/action/action_instant.h>
#include <extra2d/action/action_interval_actions.h>
#include <extra2d/action/action_instant_actions.h>
#include <extra2d/action/action_ease.h>
#include <extra2d/action/action_special.h>
#include <extra2d/action/action_manager.h>
#include <extra2d/action/ease.h>
// Event
#include <extra2d/event/event.h>
#include <extra2d/event/event_queue.h>
#include <extra2d/event/event_dispatcher.h>
#include <extra2d/event/input_codes.h>
// Audio
#include <extra2d/audio/audio_engine.h>
#include <extra2d/audio/sound.h>
// Resource
#include <extra2d/resource/resource_manager.h>
// Utils
#include <extra2d/utils/logger.h>
#include <extra2d/utils/timer.h>
#include <extra2d/utils/data.h>
#include <extra2d/utils/random.h>
// Spatial
#include <extra2d/spatial/spatial_index.h>
#include <extra2d/spatial/quadtree.h>
#include <extra2d/spatial/spatial_hash.h>
#include <extra2d/spatial/spatial_manager.h>
// Effects
#include <extra2d/effects/post_process.h>
#include <extra2d/effects/particle_system.h>
#include <extra2d/effects/custom_effect_manager.h>
// Application
#include <extra2d/app/application.h>
#ifdef __SWITCH__
#include <switch.h>
#endif

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,93 +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 {
// ============================================================================
// 2D 正交相机
// ============================================================================
class Camera {
public:
Camera();
Camera(float left, float right, float bottom, float top);
Camera(const Size &viewport);
~Camera() = default;
// ------------------------------------------------------------------------
// 位置和变换
// ------------------------------------------------------------------------
void setPosition(const Vec2 &position);
void setPosition(float x, float y);
Vec2 getPosition() const { return position_; }
void setRotation(float degrees);
float getRotation() const { return rotation_; }
void setZoom(float zoom);
float getZoom() const { return zoom_; }
// ------------------------------------------------------------------------
// 视口设置
// ------------------------------------------------------------------------
void setViewport(float left, float right, float bottom, float top);
void setViewport(const Rect &rect);
Rect getViewport() const;
// ------------------------------------------------------------------------
// 矩阵获取
// ------------------------------------------------------------------------
glm::mat4 getViewMatrix() const;
glm::mat4 getProjectionMatrix() const;
glm::mat4 getViewProjectionMatrix() const;
// ------------------------------------------------------------------------
// 坐标转换
// ------------------------------------------------------------------------
Vec2 screenToWorld(const Vec2 &screenPos) const;
Vec2 worldToScreen(const Vec2 &worldPos) const;
Vec2 screenToWorld(float x, float y) const;
Vec2 worldToScreen(float x, float y) const;
// ------------------------------------------------------------------------
// 移动相机
// ------------------------------------------------------------------------
void move(const Vec2 &offset);
void move(float x, float y);
// ------------------------------------------------------------------------
// 边界限制
// ------------------------------------------------------------------------
void setBounds(const Rect &bounds);
void clearBounds();
void clampToBounds();
// ------------------------------------------------------------------------
// 快捷方法:看向某点
// ------------------------------------------------------------------------
void lookAt(const Vec2 &target);
private:
Vec2 position_ = Vec2::Zero();
float rotation_ = 0.0f;
float zoom_ = 1.0f;
float left_ = -1.0f;
float right_ = 1.0f;
float bottom_ = -1.0f;
float top_ = 1.0f;
Rect bounds_;
bool hasBounds_ = false;
mutable glm::mat4 viewMatrix_;
mutable glm::mat4 projMatrix_;
mutable glm::mat4 vpMatrix_;
mutable bool viewDirty_ = true;
mutable bool projDirty_ = true;
};
} // namespace 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,36 +0,0 @@
#pragma once
#include <atomic>
namespace extra2d {
// ============================================================================
// GPU 上下文状态管理器
// 用于跟踪 OpenGL/Vulkan 等 GPU 上下文的生命周期状态
// 确保在 GPU 资源析构时能安全地检查上下文是否有效
// ============================================================================
class GPUContext {
public:
/// 获取单例实例
static GPUContext& getInstance();
/// 标记 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,67 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/graphics/opengl/gl_texture.h>
#include <extra2d/graphics/texture.h>
#include <memory>
#include <stb/stb_rect_pack.h>
#include <stb/stb_truetype.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// OpenGL 字体图集实现 - 使用 stb_rect_pack 进行矩形打包
// ============================================================================
class GLFontAtlas : public FontAtlas {
public:
GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF = false);
~GLFontAtlas();
// FontAtlas 接口实现
const Glyph *getGlyph(char32_t codepoint) const override;
Texture *getTexture() const override { return texture_.get(); }
int getFontSize() const override { return fontSize_; }
float getAscent() const override { return ascent_; }
float getDescent() const override { return descent_; }
float getLineGap() const override { return lineGap_; }
float getLineHeight() const override { return ascent_ - descent_ + lineGap_; }
Vec2 measureText(const std::string &text) override;
bool isSDF() const override { return useSDF_; }
private:
// 图集配置 - 增大尺寸以支持更多字符
static constexpr int ATLAS_WIDTH = 1024;
static constexpr int ATLAS_HEIGHT = 1024;
static constexpr int PADDING = 2; // 字形之间的间距
int fontSize_;
bool useSDF_;
mutable std::unique_ptr<GLTexture> texture_;
mutable std::unordered_map<char32_t, Glyph> glyphs_;
// stb_rect_pack 上下文
mutable stbrp_context packContext_;
mutable std::vector<stbrp_node> packNodes_;
mutable int currentY_;
std::vector<unsigned char> fontData_;
stbtt_fontinfo fontInfo_;
float scale_;
float ascent_;
float descent_;
float lineGap_;
// 预分配字形位图缓冲区,避免每次动态分配
mutable std::vector<uint8_t> glyphBitmapCache_;
mutable std::vector<uint8_t> glyphRgbaCache_;
void createAtlas();
void cacheGlyph(char32_t codepoint) const;
};
} // namespace extra2d

View File

@ -1,131 +0,0 @@
#pragma once
#include <extra2d/graphics/opengl/gl_shader.h>
#include <extra2d/graphics/opengl/gl_sprite_batch.h>
#include <extra2d/graphics/render_backend.h>
#include <array>
#include <glad/glad.h>
#include <vector>
namespace extra2d {
class Window;
// ============================================================================
// OpenGL 渲染器实现
// ============================================================================
class GLRenderer : public RenderBackend {
public:
GLRenderer();
~GLRenderer() override;
// RenderBackend 接口实现
bool init(Window *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:
// 形状批处理常量
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;
};
Window *window_;
GLSpriteBatch spriteBatch_;
GLShader shapeShader_;
GLuint shapeVao_;
GLuint shapeVbo_;
GLuint lineVao_; // 线条专用 VAO
GLuint lineVbo_; // 线条专用 VBO
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 状态缓存
BlendMode cachedBlendMode_ = BlendMode::None;
bool blendEnabled_ = false;
int cachedViewportX_ = 0;
int cachedViewportY_ = 0;
int cachedViewportWidth_ = 0;
int cachedViewportHeight_ = 0;
void initShapeRendering();
void flushShapeBatch();
void flushLineBatch();
void addShapeVertex(float x, float y, const Color &color);
void addLineVertex(float x, float y, const Color &color);
void submitShapeBatch(GLenum mode);
};
} // namespace extra2d

View File

@ -1,55 +0,0 @@
#pragma once
#include <glad/glad.h>
#include <string>
#include <unordered_map>
#include <glm/mat4x4.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
namespace extra2d {
// ============================================================================
// OpenGL Shader 程序
// ============================================================================
class GLShader {
public:
GLShader();
~GLShader();
// 从源码编译
bool compileFromSource(const char* vertexSource, const char* fragmentSource);
// 从文件加载并编译
bool compileFromFile(const std::string& vertexPath, const std::string& fragmentPath);
// 使用/激活
void bind() const;
void unbind() const;
// Uniform 设置
void setBool(const std::string& name, bool value);
void setInt(const std::string& name, int value);
void setFloat(const std::string& name, float value);
void setVec2(const std::string& name, const glm::vec2& value);
void setVec3(const std::string& name, const glm::vec3& value);
void setVec4(const std::string& name, const glm::vec4& value);
void setMat4(const std::string& name, const glm::mat4& value);
// 获取程序 ID
GLuint getProgramID() const { return programID_; }
// 检查是否有效
bool isValid() const { return programID_ != 0; }
private:
GLuint programID_;
std::unordered_map<std::string, GLint> uniformCache_;
GLuint compileShader(GLenum type, const char* source);
GLint getUniformLocation(const std::string& name);
};
} // namespace extra2d

View File

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

View File

@ -1,72 +0,0 @@
#pragma once
#include <extra2d/graphics/texture.h>
#include <extra2d/graphics/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,138 +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 Window;
class Texture;
class FontAtlas;
class Shader;
// ============================================================================
// 渲染后端类型
// ============================================================================
enum class BackendType {
OpenGL,
// Vulkan,
// Metal,
// D3D11,
// D3D12
};
// ============================================================================
// 混合模式
// ============================================================================
enum class BlendMode {
None, // 不混合
Alpha, // 标准 Alpha 混合
Additive, // 加法混合
Multiply // 乘法混合
};
// ============================================================================
// 渲染后端抽象接口
// ============================================================================
class RenderBackend {
public:
virtual ~RenderBackend() = default;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
virtual bool init(Window *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;
// ------------------------------------------------------------------------
// 精灵批渲染
// ------------------------------------------------------------------------
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;
// ------------------------------------------------------------------------
// 形状渲染
// ------------------------------------------------------------------------
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.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,333 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/opengl/gl_texture.h>
#include <extra2d/graphics/texture.h>
#include <mutex>
namespace extra2d {
// ============================================================================
// 渲染目标配置
// ============================================================================
struct RenderTargetConfig {
int width = 800; // 宽度
int height = 600; // 高度
PixelFormat colorFormat = PixelFormat::RGBA8; // 颜色格式
bool hasDepth = true; // 是否包含深度缓冲
bool hasDepthBuffer = true; // 兼容旧API的别名 (同hasDepth)
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 create的别名API
*/
bool init(const RenderTargetConfig &config) { return create(config); }
/**
* @brief
*/
bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false);
/**
* @brief
*/
void destroy();
/**
* @brief destroy的别名API
*/
void shutdown() { 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 blitTo的别名API
* @param target
* @param color
* @param depth
*/
void blitTo(RenderTarget &target, bool color = true, bool depth = false);
/**
* @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 &getInstance();
/**
* @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 RenderTargetManager {
public:
/**
* @brief
*/
static RenderTargetManager &getInstance();
/**
* @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:
RenderTargetManager() = default;
~RenderTargetManager() = default;
RenderTargetManager(const RenderTargetManager &) = delete;
RenderTargetManager &operator=(const RenderTargetManager &) = delete;
Ptr<RenderTarget> defaultRenderTarget_;
std::vector<Ptr<RenderTarget>> renderTargets_;
bool initialized_ = false;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::getInstance()
#define E2D_RENDER_TARGET_MANAGER() \
::extra2d::RenderTargetManager::getInstance()
} // namespace extra2d

View File

@ -1,319 +0,0 @@
#pragma once
#include <extra2d/graphics/opengl/gl_shader.h>
#include <extra2d/core/types.h>
#include <extra2d/core/color.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;
};
namespace ShaderSource {
static const char* StandardVert = R"(
#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;
}
)";
static const char* StandardFrag = R"(
#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;
}
}
)";
static const char* WaterFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_waveSpeed;
uniform float u_waveAmplitude;
uniform float u_waveFrequency;
uniform float u_time;
out vec4 fragColor;
void main() {
vec2 uv = v_texCoord;
// 水波纹效果
float wave = sin(uv.y * u_waveFrequency + u_time * u_waveSpeed) * u_waveAmplitude;
uv.x += wave;
vec4 texColor = texture(u_texture, uv);
fragColor = texColor * v_color;
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* OutlineFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform vec4 u_outlineColor;
uniform float u_thickness;
uniform vec2 u_textureSize;
out vec4 fragColor;
void main() {
vec4 color = texture(u_texture, v_texCoord);
// 简单的描边检测
float alpha = 0.0;
vec2 offset = u_thickness / u_textureSize;
alpha += texture(u_texture, v_texCoord + vec2(-offset.x, 0.0)).a;
alpha += texture(u_texture, v_texCoord + vec2(offset.x, 0.0)).a;
alpha += texture(u_texture, v_texCoord + vec2(0.0, -offset.y)).a;
alpha += texture(u_texture, v_texCoord + vec2(0.0, offset.y)).a;
if (color.a < 0.1 && alpha > 0.0) {
fragColor = u_outlineColor;
} else {
fragColor = color;
}
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* DistortionFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_distortionAmount;
uniform float u_time;
uniform float u_timeScale;
out vec4 fragColor;
void main() {
vec2 uv = v_texCoord;
// 扭曲效果
float t = u_time * u_timeScale;
float dx = sin(uv.y * 10.0 + t) * u_distortionAmount;
float dy = cos(uv.x * 10.0 + t) * u_distortionAmount;
uv += vec2(dx, dy);
vec4 texColor = texture(u_texture, uv);
fragColor = texColor * v_color;
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* PixelateFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_pixelSize;
uniform vec2 u_textureSize;
uniform float u_opacity;
out vec4 fragColor;
void main() {
vec2 pixel = u_pixelSize / u_textureSize;
vec2 uv = floor(v_texCoord / pixel) * pixel + pixel * 0.5;
vec4 texColor = texture(u_texture, uv);
fragColor = texColor * v_color;
fragColor.a *= u_opacity;
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* InvertFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_strength;
uniform float u_opacity;
out vec4 fragColor;
void main() {
vec4 texColor = texture(u_texture, v_texCoord) * v_color;
vec3 inverted = vec3(1.0) - texColor.rgb;
texColor.rgb = mix(texColor.rgb, inverted, u_strength);
fragColor = texColor;
fragColor.a *= u_opacity;
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* GrayscaleFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_intensity;
uniform float u_opacity;
out vec4 fragColor;
void main() {
vec4 texColor = texture(u_texture, v_texCoord) * v_color;
float gray = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
texColor.rgb = mix(texColor.rgb, vec3(gray), u_intensity);
fragColor = texColor;
fragColor.a *= u_opacity;
if (fragColor.a < 0.01) {
discard;
}
}
)";
static const char* BlurFrag = R"(
#version 300 es
precision highp float;
in vec2 v_texCoord;
in vec4 v_color;
uniform sampler2D u_texture;
uniform float u_radius;
uniform vec2 u_textureSize;
uniform float u_opacity;
out vec4 fragColor;
void main() {
vec2 texel = u_radius / u_textureSize;
vec4 sum = vec4(0.0);
sum += texture(u_texture, v_texCoord + texel * vec2(-1.0, -1.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 0.0, -1.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 1.0, -1.0));
sum += texture(u_texture, v_texCoord + texel * vec2(-1.0, 0.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 0.0, 0.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 1.0, 0.0));
sum += texture(u_texture, v_texCoord + texel * vec2(-1.0, 1.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 0.0, 1.0));
sum += texture(u_texture, v_texCoord + texel * vec2( 1.0, 1.0));
vec4 texColor = sum / 9.0;
fragColor = texColor * v_color;
fragColor.a *= u_opacity;
if (fragColor.a < 0.01) {
discard;
}
}
)";
} // namespace ShaderSource
class ShaderPreset {
public:
static Ptr<GLShader> Water(const WaterParams& params);
static Ptr<GLShader> Outline(const OutlineParams& params);
static Ptr<GLShader> Distortion(const DistortionParams& params);
static Ptr<GLShader> Pixelate(const PixelateParams& params);
static Ptr<GLShader> Invert(const InvertParams& params);
static Ptr<GLShader> Grayscale(const GrayscaleParams& params);
static Ptr<GLShader> Blur(const BlurParams& params);
static Ptr<GLShader> GrayscaleOutline(const GrayscaleParams& grayParams,
const OutlineParams& outlineParams);
static Ptr<GLShader> PixelateInvert(const PixelateParams& pixParams,
const InvertParams& invParams);
};
} // namespace extra2d

View File

@ -1,179 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/opengl/gl_shader.h>
#include <functional>
#include <string>
#include <unordered_map>
namespace extra2d {
// ============================================================================
// Shader参数绑定回调
// ============================================================================
using ShaderBindCallback = std::function<void(GLShader &)>;
// ============================================================================
// Shader系统 - 管理所有Shader的加载、缓存和热重载
// ============================================================================
class ShaderSystem {
public:
// ------------------------------------------------------------------------
// 单例访问
// ------------------------------------------------------------------------
static ShaderSystem &getInstance();
// ------------------------------------------------------------------------
// 初始化和关闭
// ------------------------------------------------------------------------
bool init();
void shutdown();
// ------------------------------------------------------------------------
// Shader加载
// ------------------------------------------------------------------------
/**
* @brief Shader
* @param name Shader名称
* @param vertPath
* @param fragPath
* @return Shadernullptr
*/
Ptr<GLShader> loadFromFile(const std::string &name,
const std::string &vertPath,
const std::string &fragPath);
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shadernullptr
*/
Ptr<GLShader> loadFromSource(const std::string &name,
const std::string &vertSource,
const std::string &fragSource);
/**
* @brief Shader
* @param name Shader名称
* @return Shadernullptr
*/
Ptr<GLShader> get(const std::string &name);
/**
* @brief Shader是否存在
*/
bool has(const std::string &name) const;
// ------------------------------------------------------------------------
// Shader移除
// ------------------------------------------------------------------------
void remove(const std::string &name);
void clear();
// ------------------------------------------------------------------------
// 热重载支持
// ------------------------------------------------------------------------
/**
* @brief /
*/
void setFileWatching(bool enable);
bool isFileWatching() const { return fileWatching_; }
/**
* @brief
*/
void updateFileWatching();
/**
* @brief Shader
*/
bool reload(const std::string &name);
/**
* @brief Shader
*/
void reloadAll();
// ------------------------------------------------------------------------
// 内置Shader获取
// ------------------------------------------------------------------------
Ptr<GLShader> getBuiltinSpriteShader();
Ptr<GLShader> getBuiltinParticleShader();
Ptr<GLShader> getBuiltinPostProcessShader();
Ptr<GLShader> getBuiltinShapeShader();
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/**
* @brief
*/
static std::string readFile(const std::string &filepath);
/**
* @brief Shader文件的最后修改时间
*/
static uint64_t getFileModifiedTime(const std::string &filepath);
private:
ShaderSystem() = default;
~ShaderSystem() = default;
ShaderSystem(const ShaderSystem &) = delete;
ShaderSystem &operator=(const ShaderSystem &) = delete;
struct ShaderInfo {
Ptr<GLShader> shader;
std::string vertPath;
std::string fragPath;
uint64_t vertModifiedTime;
uint64_t fragModifiedTime;
bool isBuiltin;
};
std::unordered_map<std::string, ShaderInfo> shaders_;
bool fileWatching_ = false;
float watchTimer_ = 0.0f;
static constexpr float WATCH_INTERVAL = 1.0f; // 检查间隔(秒)
// 内置Shader缓存
Ptr<GLShader> builtinSpriteShader_;
Ptr<GLShader> builtinParticleShader_;
Ptr<GLShader> builtinPostProcessShader_;
Ptr<GLShader> builtinShapeShader_;
bool loadBuiltinShaders();
void checkAndReload();
};
// ============================================================================
// Shader参数包装器 - 简化Uniform设置
// ============================================================================
class ShaderParams {
public:
explicit ShaderParams(GLShader &shader);
ShaderParams &setBool(const std::string &name, bool value);
ShaderParams &setInt(const std::string &name, int value);
ShaderParams &setFloat(const std::string &name, float value);
ShaderParams &setVec2(const std::string &name, const glm::vec2 &value);
ShaderParams &setVec3(const std::string &name, const glm::vec3 &value);
ShaderParams &setVec4(const std::string &name, const glm::vec4 &value);
ShaderParams &setMat4(const std::string &name, const glm::mat4 &value);
ShaderParams &setColor(const std::string &name, const Color &color);
private:
GLShader &shader_;
};
// ============================================================================
// 便捷宏
// ============================================================================
#define E2D_SHADER_SYSTEM() ::extra2d::ShaderSystem::getInstance()
} // 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.h>
#include <extra2d/graphics/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 TextureAtlasManager {
public:
static TextureAtlasManager& getInstance();
// 获取主图集
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:
TextureAtlasManager() = default;
~TextureAtlasManager() = default;
TextureAtlasManager(const TextureAtlasManager&) = delete;
TextureAtlasManager& operator=(const TextureAtlasManager&) = delete;
TextureAtlas atlas_;
};
} // namespace extra2d

View File

@ -1,62 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <mutex>
namespace extra2d {
// ============================================================================
// VRAM 管理器 - 跟踪显存使用情况
// ============================================================================
class VRAMManager {
public:
static VRAMManager& getInstance();
// 纹理显存跟踪
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:
VRAMManager();
~VRAMManager() = default;
VRAMManager(const VRAMManager&) = delete;
VRAMManager& operator=(const VRAMManager&) = 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,141 +0,0 @@
#pragma once
#include <array>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/event/input_codes.h>
#include <SDL.h>
namespace extra2d {
// ============================================================================
// 鼠标按钮枚举
// ============================================================================
enum class MouseButton {
Left = 0,
Right = 1,
Middle = 2,
Button4 = 3,
Button5 = 4,
Button6 = 5,
Button7 = 6,
Button8 = 7,
Count = 8
};
// ============================================================================
// Input 类 - 跨平台输入管理
// 支持: 键盘、鼠标、手柄、触摸屏
// ============================================================================
class Input {
public:
Input();
~Input();
// 初始化
void init();
void shutdown();
// 每帧更新
void update();
// ------------------------------------------------------------------------
// 键盘输入
// ------------------------------------------------------------------------
bool isKeyDown(int keyCode) const;
bool isKeyPressed(int keyCode) const;
bool isKeyReleased(int keyCode) const;
// ------------------------------------------------------------------------
// 手柄按钮
// ------------------------------------------------------------------------
bool isButtonDown(int button) const;
bool isButtonPressed(int button) const;
bool isButtonReleased(int button) const;
// 摇杆
Vec2 getLeftStick() const;
Vec2 getRightStick() const;
// ------------------------------------------------------------------------
// 鼠标输入
// ------------------------------------------------------------------------
bool isMouseDown(MouseButton button) const;
bool isMousePressed(MouseButton button) const;
bool isMouseReleased(MouseButton button) const;
Vec2 getMousePosition() const;
Vec2 getMouseDelta() const;
float getMouseScroll() const { return mouseScroll_; }
float getMouseScrollDelta() const { return mouseScroll_ - prevMouseScroll_; }
void setMousePosition(const Vec2 &position);
void setMouseVisible(bool visible);
void setMouseLocked(bool locked);
// ------------------------------------------------------------------------
// 触摸屏 (Switch 原生支持PC 端模拟或禁用)
// ------------------------------------------------------------------------
bool isTouching() const { return touching_; }
Vec2 getTouchPosition() const { return touchPosition_; }
int getTouchCount() const { return touchCount_; }
// ------------------------------------------------------------------------
// 便捷方法
// ------------------------------------------------------------------------
bool isAnyKeyDown() const;
bool isAnyMouseDown() const;
private:
static constexpr int MAX_BUTTONS = SDL_CONTROLLER_BUTTON_MAX;
static constexpr int MAX_KEYS = SDL_NUM_SCANCODES;
SDL_GameController *controller_;
// 键盘状态 (PC 端使用)
std::array<bool, MAX_KEYS> keysDown_;
std::array<bool, MAX_KEYS> prevKeysDown_;
// 手柄按钮状态
std::array<bool, MAX_BUTTONS> buttonsDown_;
std::array<bool, MAX_BUTTONS> prevButtonsDown_;
// 摇杆状态
float leftStickX_;
float leftStickY_;
float rightStickX_;
float rightStickY_;
// 鼠标状态 (PC 端使用)
Vec2 mousePosition_;
Vec2 prevMousePosition_;
float mouseScroll_;
float prevMouseScroll_;
std::array<bool, 8> mouseButtonsDown_;
std::array<bool, 8> prevMouseButtonsDown_;
// 触摸屏状态 (Switch 原生)
bool touching_;
bool prevTouching_;
Vec2 touchPosition_;
Vec2 prevTouchPosition_;
int touchCount_;
// 映射键盘 keyCode 到 SDL GameController 按钮 (Switch 兼容模式)
SDL_GameControllerButton mapKeyToButton(int keyCode) const;
// 更新键盘状态
void updateKeyboard();
// 更新鼠标状态
void updateMouse();
// 更新手柄状态
void updateGamepad();
// 更新触摸屏状态
void updateTouch();
};
} // namespace extra2d

View File

@ -1,153 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/core/string.h>
#include <extra2d/core/math_types.h>
#include <functional>
#include <SDL.h>
namespace extra2d {
// 前向声明
class EventQueue;
class Input;
// ============================================================================
// 窗口配置
// ============================================================================
struct WindowConfig {
std::string title = "Extra2D Application";
int width = 1280;
int height = 720;
bool fullscreen = true;
bool resizable = false;
bool vsync = true;
int msaaSamples = 0;
bool centerWindow = true;
bool enableCursors = true;
bool enableDpiScale = true;
bool fullscreenDesktop = true; // true: SDL_WINDOW_FULLSCREEN_DESKTOP, false: SDL_WINDOW_FULLSCREEN
};
// ============================================================================
// 鼠标光标形状枚举
// ============================================================================
enum class CursorShape {
Arrow,
IBeam,
Crosshair,
Hand,
HResize,
VResize,
ResizeAll,
ResizeNWSE,
ResizeNESW
};
// ============================================================================
// Window 类 - SDL2 Window + GLES 3.2 封装
// 支持平台: Nintendo Switch, Windows, Linux, macOS
// ============================================================================
class Window {
public:
Window();
~Window();
// 创建窗口
bool create(const WindowConfig& config);
void destroy();
// 窗口操作
void pollEvents();
void swapBuffers();
bool shouldClose() const;
void setShouldClose(bool close);
// 窗口属性
void setTitle(const std::string& title);
void setSize(int width, int height);
void setPosition(int x, int y);
void setFullscreen(bool fullscreen);
void setVSync(bool enabled);
void setResizable(bool resizable);
// 获取窗口属性
int getWidth() const { return width_; }
int getHeight() const { return height_; }
Size getSize() const { return Size(static_cast<float>(width_), static_cast<float>(height_)); }
Vec2 getPosition() const;
bool isFullscreen() const { return fullscreen_; }
bool isVSync() const { return vsync_; }
// DPI 缩放 (PC 端自动检测Switch 固定 1.0)
float getContentScaleX() const;
float getContentScaleY() const;
Vec2 getContentScale() const;
// 窗口状态
bool isFocused() const { return focused_; }
bool isMinimized() const;
bool isMaximized() const;
// 获取 SDL2 窗口和 GL 上下文
SDL_Window* getSDLWindow() const { return sdlWindow_; }
SDL_GLContext getGLContext() const { return glContext_; }
// 设置/获取用户数据
void setUserData(void* data) { userData_ = data; }
void* getUserData() const { return userData_; }
// 事件队列
void setEventQueue(EventQueue* queue) { eventQueue_ = queue; }
EventQueue* getEventQueue() const { return eventQueue_; }
// 获取输入管理器
Input* getInput() const { return input_.get(); }
// 光标操作 (PC 端有效Switch 上为空操作)
void setCursor(CursorShape shape);
void resetCursor();
void setMouseVisible(bool visible);
// 窗口回调
using ResizeCallback = std::function<void(int width, int height)>;
using FocusCallback = std::function<void(bool focused)>;
using CloseCallback = std::function<void()>;
void setResizeCallback(ResizeCallback callback) { resizeCallback_ = callback; }
void setFocusCallback(FocusCallback callback) { focusCallback_ = callback; }
void setCloseCallback(CloseCallback callback) { closeCallback_ = callback; }
private:
// SDL2 状态
SDL_Window* sdlWindow_;
SDL_GLContext glContext_;
SDL_Cursor* sdlCursors_[9]; // 光标缓存
SDL_Cursor* currentCursor_;
int width_;
int height_;
bool vsync_;
bool shouldClose_;
bool fullscreen_;
bool focused_;
float contentScaleX_;
float contentScaleY_;
bool enableDpiScale_;
void* userData_;
EventQueue* eventQueue_;
UniquePtr<Input> input_;
ResizeCallback resizeCallback_;
FocusCallback focusCallback_;
CloseCallback closeCallback_;
bool initSDL(const WindowConfig& config);
void deinitSDL();
void initCursors();
void deinitCursors();
void updateContentScale();
};
} // namespace extra2d

View File

@ -1,356 +0,0 @@
#pragma once
#include <extra2d/audio/sound.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/alpha_mask.h>
#include <extra2d/graphics/font.h>
#include <extra2d/graphics/texture.h>
#include <functional>
#include <future>
#include <mutex>
#include <string>
#include <unordered_map>
#include <queue>
#include <thread>
#include <atomic>
#include <list>
#include <vector>
namespace extra2d {
// ============================================================================
// 资源管理器 - 统一管理纹理、字体、音效等资源
// 支持异步加载和纹理压缩
// ============================================================================
// 纹理格式枚举
enum class TextureFormat {
Auto = 0, // 自动选择最佳格式
RGBA8, // 32位 RGBA
RGB8, // 24位 RGB
DXT1, // BC1/DXT1 压缩1 bit alpha
DXT5, // BC3/DXT5 压缩(完整 alpha
ETC2, // ETC2 压缩(移动平台)
ASTC4x4, // ASTC 4x4 压缩(高质量)
ASTC8x8, // ASTC 8x8 压缩(高压缩率)
};
// ============================================================================
// 纹理LRU缓存项
// ============================================================================
struct TextureCacheEntry {
Ptr<Texture> texture;
size_t size = 0; // 纹理大小(字节)
float lastAccessTime = 0.0f; // 最后访问时间
uint32_t accessCount = 0; // 访问次数
};
// 异步加载回调类型
using TextureLoadCallback = std::function<void(Ptr<Texture>)>;
class ResourceManager {
public:
// ------------------------------------------------------------------------
// 单例访问
// ------------------------------------------------------------------------
static ResourceManager &getInstance();
// ------------------------------------------------------------------------
// 纹理资源 - 同步加载
// ------------------------------------------------------------------------
/// 加载纹理(带缓存)
Ptr<Texture> loadTexture(const std::string &filepath);
/// 加载纹理(指定是否异步)
Ptr<Texture> loadTexture(const std::string &filepath, bool async);
/// 加载纹理(完整参数:异步 + 压缩格式)
Ptr<Texture> loadTexture(const std::string &filepath, bool async, TextureFormat format);
/// 异步加载纹理(带回调)
void loadTextureAsync(const std::string &filepath, TextureLoadCallback callback);
/// 异步加载纹理(指定格式 + 回调)
void loadTextureAsync(const std::string &filepath, TextureFormat format, TextureLoadCallback callback);
/// 加载纹理并生成Alpha遮罩用于不规则形状图片
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
/// 通过key获取已缓存的纹理
Ptr<Texture> getTexture(const std::string &key) const;
/// 检查纹理是否已缓存
bool hasTexture(const std::string &key) const;
/// 卸载指定纹理
void unloadTexture(const std::string &key);
// ------------------------------------------------------------------------
// Alpha遮罩资源
// ------------------------------------------------------------------------
/// 获取纹理的Alpha遮罩如果已生成
const AlphaMask *getAlphaMask(const std::string &textureKey) const;
/// 为已加载的纹理生成Alpha遮罩
bool generateAlphaMask(const std::string &textureKey);
/// 检查纹理是否有Alpha遮罩
bool hasAlphaMask(const std::string &textureKey) const;
// ------------------------------------------------------------------------
// 字体图集资源
// ------------------------------------------------------------------------
/// 加载字体图集(带缓存)
Ptr<FontAtlas> loadFont(const std::string &filepath, int fontSize,
bool useSDF = false);
/// 通过key获取已缓存的字体图集
Ptr<FontAtlas> getFont(const std::string &key) const;
/// 检查字体是否已缓存
bool hasFont(const std::string &key) const;
/// 卸载指定字体
void unloadFont(const std::string &key);
// ------------------------------------------------------------------------
// 音效资源
// ------------------------------------------------------------------------
/// 加载音效(带缓存)
Ptr<Sound> loadSound(const std::string &filepath);
Ptr<Sound> loadSound(const std::string &name, const std::string &filepath);
/// 通过key获取已缓存的音效
Ptr<Sound> getSound(const std::string &key) const;
/// 检查音效是否已缓存
bool hasSound(const std::string &key) const;
/// 卸载指定音效
void unloadSound(const std::string &key);
// ------------------------------------------------------------------------
// 文本文件资源
// ------------------------------------------------------------------------
/// 加载文本文件(带缓存)
/// @param filepath 文件路径,支持 romfs:/ 前缀
/// @return 文件内容字符串,加载失败返回空字符串
std::string loadTextFile(const std::string &filepath);
/// 加载文本文件(指定编码)
/// @param filepath 文件路径
/// @param encoding 文件编码(默认 UTF-8
/// @return 文件内容字符串
std::string loadTextFile(const std::string &filepath, const std::string &encoding);
/// 通过key获取已缓存的文本内容
std::string getTextFile(const std::string &key) const;
/// 检查文本文件是否已缓存
bool hasTextFile(const std::string &key) const;
/// 卸载指定文本文件
void unloadTextFile(const std::string &key);
/// 清理所有文本文件缓存
void clearTextFileCache();
// ------------------------------------------------------------------------
// JSON 文件资源
// ------------------------------------------------------------------------
/// 加载并解析 JSON 文件
/// @param filepath 文件路径,支持 romfs:/ 前缀
/// @return JSON 字符串内容,加载或解析失败返回空字符串
/// @note 返回的是原始 JSON 字符串,需要自行解析
std::string loadJsonFile(const std::string &filepath);
/// 通过key获取已缓存的 JSON 内容
std::string getJsonFile(const std::string &key) const;
/// 检查 JSON 文件是否已缓存
bool hasJsonFile(const std::string &key) const;
/// 卸载指定 JSON 文件
void unloadJsonFile(const std::string &key);
/// 清理所有 JSON 文件缓存
void clearJsonFileCache();
// ------------------------------------------------------------------------
// 缓存清理
// ------------------------------------------------------------------------
/// 清理所有失效的弱引用(自动清理已释放的资源)
void purgeUnused();
/// 清理指定类型的所有缓存
void clearTextureCache();
void clearFontCache();
void clearSoundCache();
/// 清理所有资源缓存
void clearAllCaches();
/// 获取各类资源的缓存数量
size_t getTextureCacheSize() const;
size_t getFontCacheSize() const;
size_t getSoundCacheSize() const;
size_t getTextFileCacheSize() const;
size_t getJsonFileCacheSize() const;
// ------------------------------------------------------------------------
// LRU 缓存管理
// ------------------------------------------------------------------------
/// 设置纹理缓存参数
void setTextureCache(size_t maxCacheSize, size_t maxTextureCount,
float unloadInterval);
/// 获取当前缓存的总大小(字节)
size_t getTextureCacheMemoryUsage() const;
/// 获取缓存命中率
float getTextureCacheHitRate() const;
/// 打印缓存统计信息
void printTextureCacheStats() const;
/// 更新缓存(在主循环中调用,用于自动清理)
void update(float dt);
// ------------------------------------------------------------------------
// 异步加载控制
// ------------------------------------------------------------------------
/// 初始化异步加载系统(可选,自动在首次异步加载时初始化)
void initAsyncLoader();
/// 关闭异步加载系统
void shutdownAsyncLoader();
/// 等待所有异步加载完成
void waitForAsyncLoads();
/// 检查是否有正在进行的异步加载
bool hasPendingAsyncLoads() const;
ResourceManager();
~ResourceManager();
ResourceManager(const ResourceManager &) = delete;
ResourceManager &operator=(const ResourceManager &) = delete;
private:
// 生成字体缓存key
std::string makeFontKey(const std::string &filepath, int fontSize,
bool useSDF) const;
// 内部加载实现
Ptr<Texture> loadTextureInternal(const std::string &filepath, TextureFormat format);
// 选择最佳纹理格式
TextureFormat selectBestFormat(TextureFormat requested) const;
// 压缩纹理数据
std::vector<uint8_t> compressTexture(const uint8_t* data, int width, int height,
int channels, TextureFormat format);
// 互斥锁保护缓存
mutable std::mutex textureMutex_;
mutable std::mutex fontMutex_;
mutable std::mutex soundMutex_;
mutable std::mutex textFileMutex_;
mutable std::mutex jsonFileMutex_;
// 资源缓存 - 使用弱指针实现自动清理
std::unordered_map<std::string, WeakPtr<FontAtlas>> fontCache_;
std::unordered_map<std::string, WeakPtr<Sound>> soundCache_;
// 文本文件缓存 - 使用强引用(字符串值类型)
std::unordered_map<std::string, std::string> textFileCache_;
std::unordered_map<std::string, std::string> jsonFileCache_;
// ============================================================================
// 纹理LRU缓存
// ============================================================================
// LRU链表节点
struct LRUNode {
std::string key;
uint32_t prev = 0; // 数组索引0表示无效
uint32_t next = 0; // 数组索引0表示无效
bool valid = false;
};
// 纹理缓存配置
size_t maxCacheSize_ = 64 * 1024 * 1024; // 最大缓存大小 (64MB)
size_t maxTextureCount_ = 256; // 最大纹理数量
float unloadInterval_ = 30.0f; // 自动清理间隔 (秒)
// 纹理缓存 - 使用强指针保持引用
std::unordered_map<std::string, TextureCacheEntry> textureCache_;
// 侵入式LRU链表 - 使用数组索引代替指针,提高缓存局部性
std::vector<LRUNode> lruNodes_;
uint32_t lruHead_ = 0; // 最近使用
uint32_t lruTail_ = 0; // 最久未使用
uint32_t freeList_ = 0; // 空闲节点链表
// 统计
size_t totalTextureSize_ = 0;
uint64_t textureHitCount_ = 0;
uint64_t textureMissCount_ = 0;
float autoUnloadTimer_ = 0.0f;
// 异步加载相关
struct AsyncLoadTask {
std::string filepath;
TextureFormat format;
TextureLoadCallback callback;
std::promise<Ptr<Texture>> promise;
};
std::queue<AsyncLoadTask> asyncTaskQueue_;
std::mutex asyncQueueMutex_;
std::condition_variable asyncCondition_;
std::unique_ptr<std::thread> asyncThread_;
std::atomic<bool> asyncRunning_{false};
std::atomic<int> pendingAsyncLoads_{0};
void asyncLoadLoop();
// ============================================================================
// LRU 缓存内部方法
// ============================================================================
/// 分配LRU节点
uint32_t allocateLRUNode(const std::string &key);
/// 释放LRU节点
void freeLRUNode(uint32_t index);
/// 将节点移到链表头部(最近使用)
void moveToFront(uint32_t index);
/// 从链表中移除节点
void removeFromList(uint32_t index);
/// 驱逐最久未使用的纹理
std::string evictLRU();
/// 访问纹理更新LRU位置
void touchTexture(const std::string &key);
/// 驱逐纹理直到满足大小限制
void evictTexturesIfNeeded();
/// 计算纹理大小
size_t calculateTextureSize(int width, int height, PixelFormat format) const;
};
} // namespace extra2d

View File

@ -1,305 +0,0 @@
#pragma once
#include <algorithm>
#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/render_backend.h>
#include <functional>
#include <string>
#include <vector>
namespace extra2d {
// 前向声明
class Scene;
class Action;
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 removeFromParent();
void removeAllChildren();
Ptr<Node> getParent() const { return parent_.lock(); }
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
Ptr<Node> getChildByName(const std::string &name) const;
Ptr<Node> getChildByTag(int tag) const;
// ------------------------------------------------------------------------
// 变换属性
// ------------------------------------------------------------------------
void setPosition(const Vec2 &pos);
void setPosition(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 convertToWorldSpace(const Vec2 &localPos) const;
Vec2 convertToNodeSpace(const Vec2 &worldPos) const;
glm::mat4 getLocalTransform() const;
glm::mat4 getWorldTransform() const;
/**
* @brief
*/
void markTransformDirty();
/**
* @brief
*
*/
void batchUpdateTransforms();
/**
* @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 getBoundingBox() const;
// 是否需要参与空间索引(默认 true
void setSpatialIndexed(bool indexed) { spatialIndexed_ = indexed; }
bool isSpatialIndexed() const { return spatialIndexed_; }
// 更新空间索引(手动调用,通常在边界框变化后)
void updateSpatialIndex();
// ------------------------------------------------------------------------
// 动作系统
// ------------------------------------------------------------------------
/**
* @brief
* @param action
* @return
*/
Action* runAction(Action* action);
/**
* @brief
*/
void stopAllActions();
/**
* @brief
* @param action
*/
void stopAction(Action* action);
/**
* @brief
* @param tag
*/
void stopActionByTag(int tag);
/**
* @brief
* @param flags
*/
void stopActionsByFlags(unsigned int flags);
/**
* @brief
* @param tag
* @return nullptr
*/
Action* getActionByTag(int tag);
/**
* @brief
* @return
*/
size_t getActionCount() const;
/**
* @brief
* @return true
*/
bool isRunningActions() 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. 边界框(用于空间索引)
Rect lastSpatialBounds_; // 16 bytes
// 9. 浮点属性
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
// 11. 场景指针
Scene *scene_ = nullptr; // 8 bytes
// 12. 布尔标志(打包在一起)
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
bool spatialIndexed_ = true; // 1 byte
// 填充 2 bytes 到 8 字节对齐
};
} // namespace extra2d

View File

@ -1,116 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/graphics/camera.h>
#include <extra2d/scene/node.h>
#include <extra2d/spatial/spatial_manager.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;
// ------------------------------------------------------------------------
// 空间索引系统
// ------------------------------------------------------------------------
SpatialManager &getSpatialManager() { return spatialManager_; }
const SpatialManager &getSpatialManager() const { return spatialManager_; }
// 启用/禁用空间索引
void setSpatialIndexingEnabled(bool enabled) {
spatialIndexingEnabled_ = enabled;
}
bool isSpatialIndexingEnabled() const { return spatialIndexingEnabled_; }
// 节点空间索引管理(内部使用)
void updateNodeInSpatialIndex(Node *node, const Rect &oldBounds,
const Rect &newBounds);
void removeNodeFromSpatialIndex(Node *node);
// 碰撞检测查询
std::vector<Node *> queryNodesInArea(const Rect &area) const;
std::vector<Node *> queryNodesAtPoint(const Vec2 &point) const;
std::vector<std::pair<Node *, Node *>> queryCollisions() const;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
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;
// 空间索引系统
SpatialManager spatialManager_;
bool spatialIndexingEnabled_ = true;
};
} // namespace extra2d

View File

@ -1,140 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/scene/scene.h>
#include <extra2d/scene/transition_scene.h>
#include <functional>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
namespace extra2d {
// 前向声明
struct RenderCommand;
class TransitionScene;
// ============================================================================
// 场景管理器 - 管理场景的生命周期和切换
// ============================================================================
class SceneManager {
public:
using TransitionCallback = std::function<void()>;
// ------------------------------------------------------------------------
// 单例访问
// ------------------------------------------------------------------------
static SceneManager &getInstance();
// ------------------------------------------------------------------------
// 场景栈操作
// ------------------------------------------------------------------------
// 运行第一个场景
void runWithScene(Ptr<Scene> scene);
// 替换当前场景
void replaceScene(Ptr<Scene> scene);
void replaceScene(Ptr<Scene> scene, TransitionType transition,
float duration = 0.5f);
// 压入新场景(当前场景暂停)
void pushScene(Ptr<Scene> scene);
void pushScene(Ptr<Scene> scene, TransitionType transition,
float duration = 0.5f);
// 弹出当前场景(恢复上一个场景)
void popScene();
void popScene(TransitionType transition, float duration = 0.5f);
// 弹出到根场景
void popToRootScene();
void popToRootScene(TransitionType transition, float duration = 0.5f);
// 弹出到指定场景
void popToScene(const std::string &name);
void popToScene(const std::string &name, TransitionType transition,
float duration = 0.5f);
// ------------------------------------------------------------------------
// 获取场景
// ------------------------------------------------------------------------
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;
// 场景切换(供 Application 使用)
void enterScene(Ptr<Scene> scene);
void enterScene(Ptr<Scene> scene, Ptr<TransitionScene> transitionScene);
private:
void doSceneSwitch();
void startTransition(Ptr<Scene> from, Ptr<Scene> to, TransitionType type,
float duration, Function<void()> stackAction);
void finishTransition();
void dispatchPointerEvents(Scene &scene);
// 创建过渡场景
Ptr<TransitionScene> createTransitionScene(TransitionType type,
float duration,
Ptr<Scene> inScene);
std::stack<Ptr<Scene>> sceneStack_;
std::unordered_map<std::string, Ptr<Scene>> namedScenes_;
// Transition state
bool isTransitioning_ = false;
TransitionType currentTransition_ = TransitionType::None;
Ptr<TransitionScene> activeTransitionScene_;
Function<void()> transitionStackAction_;
TransitionCallback transitionCallback_;
// Next scene to switch to (queued during transition)
Ptr<Scene> nextScene_;
bool sendCleanupToScene_ = false;
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 getBoundingBox() 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.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 getBoundingBox() 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,34 +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;
private:
int divisions_;
};
} // namespace extra2d

View File

@ -1,54 +0,0 @@
#pragma once
#include <extra2d/scene/transition_scene.h>
#include <extra2d/scene/sprite.h>
#include <extra2d/core/color.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
*
*/
void renderContent(RenderBackend &renderer) override;
private:
/**
* @brief 退
*/
void hideOutShowIn();
Color maskColor_; // 遮罩颜色
bool hasSwitched_ = false; // 是否已经切换场景
};
} // namespace extra2d

View File

@ -1,37 +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;
private:
Axis axis_;
};
} // namespace extra2d

View File

@ -1,29 +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;
};
} // namespace extra2d

View File

@ -1,127 +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 SceneManager
*/
void finish();
// ------------------------------------------------------------------------
// 渲染 - 在 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);
float duration_;
float elapsed_ = 0.0f;
float progress_ = 0.0f;
bool isFinished_ = false;
Ptr<Scene> inScene_; // 要进入的场景
Ptr<Scene> outScene_; // 要退出的场景
FinishCallback finishCallback_;
};
} // namespace extra2d

View File

@ -1,35 +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;
private:
TransitionDirection direction_;
};
} // namespace extra2d

View File

@ -1,70 +0,0 @@
#pragma once
#include <array>
#include <extra2d/spatial/spatial_index.h>
namespace extra2d {
class QuadTree : public ISpatialIndex {
public:
static constexpr int MAX_OBJECTS = 10;
static constexpr int MAX_LEVELS = 5;
struct QuadTreeNode {
Rect bounds;
int level;
std::vector<std::pair<Node *, Rect>> objects;
std::array<std::unique_ptr<QuadTreeNode>, 4> children;
QuadTreeNode(const Rect &bounds, int level);
bool contains(const Rect &rect) const;
bool intersects(const Rect &rect) const;
};
explicit QuadTree(const Rect &worldBounds);
~QuadTree() override = default;
void insert(Node *node, const Rect &bounds) override;
void remove(Node *node) override;
void update(Node *node, const Rect &newBounds) override;
std::vector<Node *> query(const Rect &area) const override;
std::vector<Node *> query(const Vec2 &point) const override;
std::vector<std::pair<Node *, Node *>> queryCollisions() const override;
void clear() override;
size_t size() const override;
bool empty() const override;
void rebuild() override;
private:
void split(QuadTreeNode *node);
void insertIntoNode(QuadTreeNode *node, Node *object, const Rect &bounds);
void queryNode(const QuadTreeNode *node, const Rect &area,
std::vector<Node *> &results) const;
void queryNode(const QuadTreeNode *node, const Vec2 &point,
std::vector<Node *> &results) const;
void
collectCollisions(const QuadTreeNode *node,
std::vector<std::pair<Node *, Node *>> &collisions) const;
bool removeFromNode(QuadTreeNode *node, Node *object);
/**
* @brief 使线
* @param objects
* @param collisions
*/
void detectCollisionsInNode(
const std::vector<std::pair<Node *, Rect>> &objects,
std::vector<std::pair<Node *, Node *>> &collisions) const;
std::unique_ptr<QuadTreeNode> root_;
Rect worldBounds_;
size_t objectCount_ = 0;
// 碰撞检测用的临时缓冲区,避免重复分配
mutable std::vector<std::pair<Node *, Rect>> collisionBuffer_;
};
} // namespace extra2d

View File

@ -1,75 +0,0 @@
#pragma once
#include <extra2d/spatial/spatial_index.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
/**
* @brief -
* 使
*/
class SpatialHash : public ISpatialIndex {
public:
using CellKey = std::pair<int64_t, int64_t>;
struct CellKeyHash {
size_t operator()(const CellKey &key) const {
return std::hash<int64_t>()(key.first) ^
(std::hash<int64_t>()(key.second) << 1);
}
};
explicit SpatialHash(float cellSize = 64.0f);
~SpatialHash() override = default;
void insert(Node *node, const Rect &bounds) override;
void remove(Node *node) override;
void update(Node *node, const Rect &newBounds) override;
std::vector<Node *> query(const Rect &area) const override;
std::vector<Node *> query(const Vec2 &point) const override;
std::vector<std::pair<Node *, Node *>> queryCollisions() const override;
void clear() override;
size_t size() const override;
bool empty() const override;
void rebuild() override;
void setCellSize(float cellSize);
float getCellSize() const { return cellSize_; }
private:
/**
* @brief - 使vector代替unordered_set减少内存开销
*/
struct Cell {
std::vector<Node *> objects;
void insert(Node *node);
void remove(Node *node);
bool contains(Node *node) const;
void clear() { objects.clear(); }
size_t size() const { return objects.size(); }
bool empty() const { return objects.empty(); }
};
CellKey getCellKey(float x, float y) const;
void getCellsForRect(const Rect &rect, std::vector<CellKey> &cells) const;
void insertIntoCells(Node *node, const Rect &bounds);
void removeFromCells(Node *node, const Rect &bounds);
float cellSize_;
// 使用vector存储对象列表代替unordered_set内存更紧凑
std::unordered_map<CellKey, Cell, CellKeyHash> grid_;
std::unordered_map<Node *, Rect> objectBounds_;
size_t objectCount_ = 0;
// 查询用的临时缓冲区,避免重复分配
mutable std::vector<Node *> queryBuffer_;
mutable std::vector<std::pair<Node *, Node *>> collisionBuffer_;
};
} // namespace extra2d

View File

@ -1,40 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <memory>
#include <vector>
namespace extra2d {
class Node;
enum class SpatialStrategy { Auto, QuadTree, SpatialHash };
struct SpatialQueryResult {
Node *node;
Rect bounds;
};
class ISpatialIndex {
public:
virtual ~ISpatialIndex() = default;
virtual void insert(Node *node, const Rect &bounds) = 0;
virtual void remove(Node *node) = 0;
virtual void update(Node *node, const Rect &newBounds) = 0;
virtual std::vector<Node *> query(const Rect &area) const = 0;
virtual std::vector<Node *> query(const Vec2 &point) const = 0;
virtual std::vector<std::pair<Node *, Node *>> queryCollisions() const = 0;
virtual void clear() = 0;
virtual size_t size() const = 0;
virtual bool empty() const = 0;
virtual void rebuild() = 0;
};
using SpatialIndexPtr = std::unique_ptr<ISpatialIndex>;
} // namespace extra2d

View File

@ -1,62 +0,0 @@
#pragma once
#include <extra2d/spatial/spatial_index.h>
#include <functional>
#include <memory>
namespace extra2d {
class SpatialManager {
public:
using QueryCallback = std::function<bool(Node *)>;
SpatialManager();
explicit SpatialManager(const Rect &worldBounds);
~SpatialManager() = default;
void setStrategy(SpatialStrategy strategy);
void setAutoThresholds(size_t quadTreeThreshold, size_t hashThreshold);
void setWorldBounds(const Rect &bounds);
Rect getWorldBounds() const { return worldBounds_; }
void insert(Node *node, const Rect &bounds);
void remove(Node *node);
void update(Node *node, const Rect &newBounds);
std::vector<Node *> query(const Rect &area) const;
std::vector<Node *> query(const Vec2 &point) const;
std::vector<std::pair<Node *, Node *>> queryCollisions() const;
void query(const Rect &area, const QueryCallback &callback) const;
void query(const Vec2 &point, const QueryCallback &callback) const;
void clear();
size_t size() const;
bool empty() const;
void rebuild();
void optimize();
SpatialStrategy getCurrentStrategy() const;
const char *getStrategyName() const;
static std::unique_ptr<ISpatialIndex> createIndex(SpatialStrategy strategy,
const Rect &bounds);
private:
void selectOptimalStrategy();
SpatialStrategy currentStrategy_ = SpatialStrategy::Auto;
SpatialStrategy activeStrategy_ = SpatialStrategy::QuadTree;
std::unique_ptr<ISpatialIndex> index_;
Rect worldBounds_;
size_t quadTreeThreshold_ = 1000;
size_t hashThreshold_ = 5000;
mutable size_t queryCount_ = 0;
mutable size_t totalQueryTime_ = 0;
};
} // namespace extra2d

View File

@ -1,261 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/graphics/texture.h>
#include <extra2d/platform/window.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// 图片缩放模式
enum class ImageScaleMode {
Original, // 使用原图大小
Stretch, // 拉伸填充
ScaleFit, // 等比缩放,保持完整显示
ScaleFill // 等比缩放,填充整个区域(可能裁剪)
};
// ============================================================================
// 基础按钮类
// ============================================================================
class Button : public Widget {
public:
Button();
explicit Button(const std::string &text);
~Button() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<Button> create();
static Ptr<Button> create(const std::string &text);
static Ptr<Button> create(const std::string &text, Ptr<FontAtlas> font);
// ------------------------------------------------------------------------
// 文字内容
// ------------------------------------------------------------------------
void setText(const std::string &text);
const std::string &getText() const { return text_; }
// ------------------------------------------------------------------------
// 字体
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 内边距
// ------------------------------------------------------------------------
void setPadding(const Vec2 &padding);
void setPadding(float x, float y);
Vec2 getPadding() const { return padding_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 纯色背景设置
// ------------------------------------------------------------------------
void setBackgroundColor(const Color &normal, const Color &hover,
const Color &pressed);
// ------------------------------------------------------------------------
// 边框设置
// ------------------------------------------------------------------------
void setBorder(const Color &color, float width);
float getBorderWidth() const { return borderWidth_; }
Color getBorderColor() const { return borderColor_; }
// ------------------------------------------------------------------------
// 图片背景设置
// ------------------------------------------------------------------------
void setBackgroundImage(Ptr<Texture> normal, Ptr<Texture> hover = nullptr,
Ptr<Texture> pressed = nullptr);
void setBackgroundImage(Ptr<Texture> texture, const Rect &rect);
/**
* @brief
* @param offNormal
* @param onNormal
* @param offHover
* @param onHover
* @param offPressed
* @param onPressed
*/
void setStateBackgroundImage(Ptr<Texture> offNormal, Ptr<Texture> onNormal,
Ptr<Texture> offHover = nullptr,
Ptr<Texture> onHover = nullptr,
Ptr<Texture> offPressed = nullptr,
Ptr<Texture> onPressed = nullptr);
void setBackgroundImageScaleMode(ImageScaleMode mode);
void setCustomSize(const Vec2 &size);
void setCustomSize(float width, float height);
// ------------------------------------------------------------------------
// 圆角矩形设置
// ------------------------------------------------------------------------
void setCornerRadius(float radius);
float getCornerRadius() const { return cornerRadius_; }
void setRoundedCornersEnabled(bool enabled);
bool isRoundedCornersEnabled() const { return roundedCornersEnabled_; }
// ------------------------------------------------------------------------
// 鼠标光标设置
// ------------------------------------------------------------------------
void setHoverCursor(CursorShape cursor);
CursorShape getHoverCursor() const { return hoverCursor_; }
// ------------------------------------------------------------------------
// Alpha遮罩点击检测
// ------------------------------------------------------------------------
void setUseAlphaMaskForHitTest(bool enabled);
bool isUseAlphaMaskForHitTest() const { return useAlphaMaskForHitTest_; }
// ------------------------------------------------------------------------
// 点击回调
// ------------------------------------------------------------------------
void setOnClick(Function<void()> callback);
// ------------------------------------------------------------------------
// 切换模式支持Toggle Button
// ------------------------------------------------------------------------
/**
* @brief
* @param enabled true on/off
*/
void setToggleMode(bool enabled);
/**
* @brief
* @return true
*/
bool isToggleMode() const { return toggleMode_; }
/**
* @brief
* @param on true false
*/
void setOn(bool on);
/**
* @brief
* @return true false
*/
bool isOn() const { return isOn_; }
/**
* @brief
*/
void toggle();
/**
* @brief
* @param callback
*/
void setOnStateChange(Function<void(bool)> callback);
// ------------------------------------------------------------------------
// 状态文字设置(用于切换按钮)
// ------------------------------------------------------------------------
/**
* @brief
* @param textOff
* @param textOn
*/
void setStateText(const std::string &textOff, const std::string &textOn);
/**
* @brief
* @param colorOff
* @param colorOn
*/
void setStateTextColor(const Color &colorOff, const Color &colorOn);
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
void drawBackgroundImage(RenderBackend &renderer, const Rect &rect);
void drawRoundedRect(RenderBackend &renderer, const Rect &rect,
const Color &color, float radius);
void fillRoundedRect(RenderBackend &renderer, const Rect &rect,
const Color &color, float radius);
Vec2 calculateImageSize(const Vec2 &buttonSize, const Vec2 &imageSize);
// 状态访问(供子类使用)
bool isHovered() const { return hovered_; }
bool isPressed() const { return pressed_; }
private:
std::string text_;
Ptr<FontAtlas> font_;
Vec2 padding_ = Vec2(10.0f, 6.0f);
// 文字颜色
Color textColor_ = Colors::White;
// 纯色背景
Color bgNormal_ = Color(0.2f, 0.2f, 0.2f, 1.0f);
Color bgHover_ = Color(0.28f, 0.28f, 0.28f, 1.0f);
Color bgPressed_ = Color(0.15f, 0.15f, 0.15f, 1.0f);
// 图片背景
Ptr<Texture> imgNormal_;
Ptr<Texture> imgHover_;
Ptr<Texture> imgPressed_;
Rect imgNormalRect_;
Rect imgHoverRect_;
Rect imgPressedRect_;
ImageScaleMode scaleMode_ = ImageScaleMode::Original;
bool useImageBackground_ = false;
bool useTextureRect_ = false;
// 切换按钮状态图片
Ptr<Texture> imgOffNormal_, imgOnNormal_;
Ptr<Texture> imgOffHover_, imgOnHover_;
Ptr<Texture> imgOffPressed_, imgOnPressed_;
bool useStateImages_ = false;
// 边框
Color borderColor_ = Color(0.6f, 0.6f, 0.6f, 1.0f);
float borderWidth_ = 1.0f;
// 圆角矩形
float cornerRadius_ = 8.0f;
bool roundedCornersEnabled_ = false;
// 鼠标光标
CursorShape hoverCursor_ = CursorShape::Hand;
bool cursorChanged_ = false;
// Alpha遮罩点击检测
bool useAlphaMaskForHitTest_ = false;
bool hovered_ = false;
bool pressed_ = false;
// 切换模式相关
bool toggleMode_ = false;
bool isOn_ = false;
Function<void(bool)> onStateChange_;
// 状态文字
std::string textOff_, textOn_;
bool useStateText_ = false;
// 状态文字颜色
Color textColorOff_ = Colors::White;
Color textColorOn_ = Colors::White;
bool useStateTextColor_ = false;
Function<void()> onClick_;
};
} // namespace extra2d

View File

@ -1,98 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// ============================================================================
// 复选框组件
// ============================================================================
class CheckBox : public Widget {
public:
CheckBox();
~CheckBox() override = default;
static Ptr<CheckBox> create();
static Ptr<CheckBox> create(const std::string &label);
// ------------------------------------------------------------------------
// 选中状态
// ------------------------------------------------------------------------
void setChecked(bool checked);
bool isChecked() const { return checked_; }
void toggle();
// ------------------------------------------------------------------------
// 标签设置
// ------------------------------------------------------------------------
void setLabel(const std::string &label);
const std::string &getLabel() const { return label_; }
// ------------------------------------------------------------------------
// 字体设置
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 复选框尺寸
// ------------------------------------------------------------------------
void setBoxSize(float size);
float getBoxSize() const { return boxSize_; }
// ------------------------------------------------------------------------
// 间距
// ------------------------------------------------------------------------
void setSpacing(float spacing);
float getSpacing() const { return spacing_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setCheckedColor(const Color &color);
Color getCheckedColor() const { return checkedColor_; }
void setUncheckedColor(const Color &color);
Color getUncheckedColor() const { return uncheckedColor_; }
void setCheckMarkColor(const Color &color);
Color getCheckMarkColor() const { return checkMarkColor_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnStateChange(Function<void(bool)> callback);
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
bool onMousePress(const MouseEvent &event) override;
bool onMouseRelease(const MouseEvent &event) override;
private:
bool checked_ = false;
std::string label_;
Ptr<FontAtlas> font_;
Color textColor_ = Colors::White;
float boxSize_ = 20.0f;
float spacing_ = 8.0f;
Color checkedColor_ = Color(0.2f, 0.6f, 1.0f, 1.0f);
Color uncheckedColor_ = Color(0.3f, 0.3f, 0.3f, 1.0f);
Color checkMarkColor_ = Colors::White;
bool pressed_ = false;
Function<void(bool)> onStateChange_;
};
} // namespace extra2d

View File

@ -1,146 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// ============================================================================
// 文本标签组件 - 用于显示静态文本
// 支持多行、对齐、阴影、描边等游戏常用效果
// ============================================================================
class Label : public Widget {
public:
Label();
explicit Label(const std::string &text);
~Label() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<Label> create();
static Ptr<Label> create(const std::string &text);
static Ptr<Label> create(const std::string &text, Ptr<FontAtlas> font);
// ------------------------------------------------------------------------
// 文本内容
// ------------------------------------------------------------------------
void setText(const std::string &text);
const std::string &getText() const { return text_; }
// ------------------------------------------------------------------------
// 字体设置
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 字体大小
// ------------------------------------------------------------------------
void setFontSize(int size);
int getFontSize() const { return fontSize_; }
// ------------------------------------------------------------------------
// 水平对齐方式
// ------------------------------------------------------------------------
enum class HorizontalAlign { Left, Center, Right };
void setHorizontalAlign(HorizontalAlign align);
HorizontalAlign getHorizontalAlign() const { return hAlign_; }
// ------------------------------------------------------------------------
// 垂直对齐方式
// ------------------------------------------------------------------------
enum class VerticalAlign { Top, Middle, Bottom };
void setVerticalAlign(VerticalAlign align);
VerticalAlign getVerticalAlign() const { return vAlign_; }
// ------------------------------------------------------------------------
// 阴影效果
// ------------------------------------------------------------------------
void setShadowEnabled(bool enabled);
bool isShadowEnabled() const { return shadowEnabled_; }
void setShadowColor(const Color &color);
Color getShadowColor() const { return shadowColor_; }
void setShadowOffset(const Vec2 &offset);
Vec2 getShadowOffset() const { return shadowOffset_; }
// ------------------------------------------------------------------------
// 描边效果
// ------------------------------------------------------------------------
void setOutlineEnabled(bool enabled);
bool isOutlineEnabled() const { return outlineEnabled_; }
void setOutlineColor(const Color &color);
Color getOutlineColor() const { return outlineColor_; }
void setOutlineWidth(float width);
float getOutlineWidth() const { return outlineWidth_; }
// ------------------------------------------------------------------------
// 多行文本
// ------------------------------------------------------------------------
void setMultiLine(bool multiLine);
bool isMultiLine() const { return multiLine_; }
void setLineSpacing(float spacing);
float getLineSpacing() const { return lineSpacing_; }
// ------------------------------------------------------------------------
// 最大宽度(用于自动换行)
// ------------------------------------------------------------------------
void setMaxWidth(float maxWidth);
float getMaxWidth() const { return maxWidth_; }
// ------------------------------------------------------------------------
// 尺寸计算
// ------------------------------------------------------------------------
Vec2 getTextSize() const;
float getLineHeight() const;
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
private:
std::string text_;
Ptr<FontAtlas> font_;
Color textColor_ = Colors::White;
int fontSize_ = 16;
HorizontalAlign hAlign_ = HorizontalAlign::Left;
VerticalAlign vAlign_ = VerticalAlign::Top;
bool shadowEnabled_ = false;
Color shadowColor_ = Color(0.0f, 0.0f, 0.0f, 0.5f);
Vec2 shadowOffset_ = Vec2(2.0f, 2.0f);
bool outlineEnabled_ = false;
Color outlineColor_ = Colors::Black;
float outlineWidth_ = 1.0f;
bool multiLine_ = false;
float lineSpacing_ = 1.0f;
float maxWidth_ = 0.0f;
mutable Vec2 cachedSize_ = Vec2::Zero();
mutable bool sizeDirty_ = true;
void updateCache() const;
void drawText(RenderBackend &renderer, const Vec2 &position, const Color &color);
Vec2 calculateDrawPosition() const;
std::vector<std::string> splitLines() const;
};
} // namespace extra2d

View File

@ -1,218 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// ============================================================================
// 进度条组件 - 用于显示进度/百分比
// 适用于血条、能量条、加载进度、经验条等游戏场景
// ============================================================================
class ProgressBar : public Widget {
public:
ProgressBar();
~ProgressBar() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<ProgressBar> create();
static Ptr<ProgressBar> create(float min, float max, float value);
// ------------------------------------------------------------------------
// 数值范围
// ------------------------------------------------------------------------
void setRange(float min, float max);
float getMin() const { return min_; }
float getMax() const { return max_; }
// ------------------------------------------------------------------------
// 当前值
// ------------------------------------------------------------------------
void setValue(float value);
float getValue() const { return value_; }
// ------------------------------------------------------------------------
// 获取百分比 (0.0 - 1.0)
// ------------------------------------------------------------------------
float getPercent() const;
// ------------------------------------------------------------------------
// 进度条方向
// ------------------------------------------------------------------------
enum class Direction { LeftToRight, RightToLeft, BottomToTop, TopToBottom };
void setDirection(Direction dir);
Direction getDirection() const { return direction_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setBackgroundColor(const Color &color);
Color getBackgroundColor() const { return bgColor_; }
void setFillColor(const Color &color);
Color getFillColor() const { return fillColor_; }
// 渐变填充色(从 fillColor_ 到 fillColorEnd_
void setGradientFillEnabled(bool enabled);
bool isGradientFillEnabled() const { return gradientEnabled_; }
void setFillColorEnd(const Color &color);
Color getFillColorEnd() const { return fillColorEnd_; }
// ------------------------------------------------------------------------
// 分段颜色(根据百分比自动切换颜色)
// ------------------------------------------------------------------------
void setSegmentedColorsEnabled(bool enabled);
bool isSegmentedColorsEnabled() const { return segmentedColorsEnabled_; }
// 设置分段阈值和颜色,例如:>70%绿色, >30%黄色, 其他红色
void addColorSegment(float percentThreshold, const Color &color);
void clearColorSegments();
// ------------------------------------------------------------------------
// 圆角设置
// ------------------------------------------------------------------------
void setCornerRadius(float radius);
float getCornerRadius() const { return cornerRadius_; }
void setRoundedCornersEnabled(bool enabled);
bool isRoundedCornersEnabled() const { return roundedCornersEnabled_; }
// ------------------------------------------------------------------------
// 边框设置
// ------------------------------------------------------------------------
void setBorderEnabled(bool enabled);
bool isBorderEnabled() const { return borderEnabled_; }
void setBorderColor(const Color &color);
Color getBorderColor() const { return borderColor_; }
void setBorderWidth(float width);
float getBorderWidth() const { return borderWidth_; }
// ------------------------------------------------------------------------
// 内边距(填充与边框的距离)
// ------------------------------------------------------------------------
void setPadding(float padding);
float getPadding() const { return padding_; }
// ------------------------------------------------------------------------
// 文本显示
// ------------------------------------------------------------------------
void setTextEnabled(bool enabled);
bool isTextEnabled() const { return textEnabled_; }
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
// 文本格式:"{value}/{max}", "{percent}%", "{value:.1f}" 等
void setTextFormat(const std::string &format);
const std::string &getTextFormat() const { return textFormat_; }
// ------------------------------------------------------------------------
// 动画效果
// ------------------------------------------------------------------------
void setAnimatedChangeEnabled(bool enabled);
bool isAnimatedChangeEnabled() const { return animatedChangeEnabled_; }
void setAnimationSpeed(float speed); // 每秒变化量
float getAnimationSpeed() const { return animationSpeed_; }
// 延迟显示效果如LOL血条
void setDelayedDisplayEnabled(bool enabled);
bool isDelayedDisplayEnabled() const { return delayedDisplayEnabled_; }
void setDelayTime(float seconds);
float getDelayTime() const { return delayTime_; }
void setDelayedFillColor(const Color &color);
Color getDelayedFillColor() const { return delayedFillColor_; }
// ------------------------------------------------------------------------
// 条纹效果
// ------------------------------------------------------------------------
void setStripedEnabled(bool enabled);
bool isStripedEnabled() const { return stripedEnabled_; }
void setStripeColor(const Color &color);
Color getStripeColor() const { return stripeColor_; }
void setStripeSpeed(float speed); // 条纹移动速度
float getStripeSpeed() const { return stripeSpeed_; }
Rect getBoundingBox() const override;
protected:
void onUpdate(float deltaTime) override;
void onDrawWidget(RenderBackend &renderer) override;
private:
// 数值
float min_ = 0.0f;
float max_ = 100.0f;
float value_ = 50.0f;
// 方向
Direction direction_ = Direction::LeftToRight;
// 颜色
Color bgColor_ = Color(0.2f, 0.2f, 0.2f, 1.0f);
Color fillColor_ = Color(0.0f, 0.8f, 0.2f, 1.0f);
Color fillColorEnd_ = Color(0.0f, 0.6f, 0.1f, 1.0f);
bool gradientEnabled_ = false;
// 分段颜色
bool segmentedColorsEnabled_ = false;
std::vector<std::pair<float, Color>> colorSegments_;
// 圆角
float cornerRadius_ = 4.0f;
bool roundedCornersEnabled_ = true;
// 边框
bool borderEnabled_ = false;
Color borderColor_ = Colors::White;
float borderWidth_ = 1.0f;
// 内边距
float padding_ = 2.0f;
// 文本
bool textEnabled_ = false;
Ptr<FontAtlas> font_;
Color textColor_ = Colors::White;
std::string textFormat_ = "{percent:.0f}%";
// 动画
bool animatedChangeEnabled_ = false;
float animationSpeed_ = 100.0f;
float displayValue_ = 50.0f; // 用于动画的显示值
// 延迟显示
bool delayedDisplayEnabled_ = false;
float delayTime_ = 0.3f;
float delayTimer_ = 0.0f;
float delayedValue_ = 50.0f;
Color delayedFillColor_ = Color(1.0f, 0.0f, 0.0f, 0.5f);
// 条纹
bool stripedEnabled_ = false;
Color stripeColor_ = Color(1.0f, 1.0f, 1.0f, 0.2f);
float stripeSpeed_ = 50.0f;
float stripeOffset_ = 0.0f;
Color getCurrentFillColor() const;
std::string formatText() const;
void drawRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius);
void fillRoundedRect(RenderBackend &renderer, const Rect &rect, const Color &color, float radius);
void drawStripes(RenderBackend &renderer, const Rect &rect);
};
} // namespace extra2d

View File

@ -1,123 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// ============================================================================
// 单选按钮组件
// ============================================================================
class RadioButton : public Widget {
public:
RadioButton();
~RadioButton() override = default;
static Ptr<RadioButton> create();
static Ptr<RadioButton> create(const std::string &label);
// ------------------------------------------------------------------------
// 选择状态
// ------------------------------------------------------------------------
void setSelected(bool selected);
bool isSelected() const { return selected_; }
// ------------------------------------------------------------------------
// 标签设置
// ------------------------------------------------------------------------
void setLabel(const std::string &label);
const std::string &getLabel() const { return label_; }
// ------------------------------------------------------------------------
// 字体设置
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字颜色
// ------------------------------------------------------------------------
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
// ------------------------------------------------------------------------
// 圆形尺寸
// ------------------------------------------------------------------------
void setCircleSize(float size);
float getCircleSize() const { return circleSize_; }
// ------------------------------------------------------------------------
// 间距
// ------------------------------------------------------------------------
void setSpacing(float spacing);
float getSpacing() const { return spacing_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setSelectedColor(const Color &color);
Color getSelectedColor() const { return selectedColor_; }
void setUnselectedColor(const Color &color);
Color getUnselectedColor() const { return unselectedColor_; }
void setDotColor(const Color &color);
Color getDotColor() const { return dotColor_; }
// ------------------------------------------------------------------------
// 分组
// ------------------------------------------------------------------------
void setGroupId(int groupId);
int getGroupId() const { return groupId_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnStateChange(Function<void(bool)> callback);
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
bool onMousePress(const MouseEvent &event) override;
bool onMouseRelease(const MouseEvent &event) override;
private:
bool selected_ = false;
std::string label_;
Ptr<FontAtlas> font_;
Color textColor_ = Colors::White;
float circleSize_ = 20.0f;
float spacing_ = 8.0f;
Color selectedColor_ = Color(0.2f, 0.6f, 1.0f, 1.0f);
Color unselectedColor_ = Color(0.3f, 0.3f, 0.3f, 1.0f);
Color dotColor_ = Colors::White;
int groupId_ = 0;
bool pressed_ = false;
Function<void(bool)> onStateChange_;
};
// ============================================================================
// 单选按钮组管理器
// ============================================================================
class RadioButtonGroup {
public:
void addButton(RadioButton *button);
void removeButton(RadioButton *button);
void selectButton(RadioButton *button);
RadioButton *getSelectedButton() const { return selectedButton_; }
void setOnSelectionChange(Function<void(RadioButton*)> callback);
private:
std::vector<RadioButton*> buttons_;
RadioButton *selectedButton_ = nullptr;
Function<void(RadioButton*)> onSelectionChange_;
};
} // namespace extra2d

View File

@ -1,155 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
namespace extra2d {
// ============================================================================
// 滑动条组件
// ============================================================================
class Slider : public Widget {
public:
Slider();
~Slider() override = default;
static Ptr<Slider> create();
static Ptr<Slider> create(float min, float max, float value);
// ------------------------------------------------------------------------
// 数值范围
// ------------------------------------------------------------------------
void setRange(float min, float max);
float getMin() const { return min_; }
float getMax() const { return max_; }
// ------------------------------------------------------------------------
// 当前值
// ------------------------------------------------------------------------
void setValue(float value);
float getValue() const { return value_; }
// ------------------------------------------------------------------------
// 步进值
// ------------------------------------------------------------------------
void setStep(float step);
float getStep() const { return step_; }
// ------------------------------------------------------------------------
// 方向
// ------------------------------------------------------------------------
void setVertical(bool vertical);
bool isVertical() const { return vertical_; }
// ------------------------------------------------------------------------
// 轨道尺寸
// ------------------------------------------------------------------------
void setTrackSize(float size);
float getTrackSize() const { return trackSize_; }
// ------------------------------------------------------------------------
// 滑块尺寸
// ------------------------------------------------------------------------
void setThumbSize(float size);
float getThumbSize() const { return thumbSize_; }
// ------------------------------------------------------------------------
// 颜色设置
// ------------------------------------------------------------------------
void setTrackColor(const Color &color);
Color getTrackColor() const { return trackColor_; }
void setFillColor(const Color &color);
Color getFillColor() const { return fillColor_; }
void setThumbColor(const Color &color);
Color getThumbColor() const { return thumbColor_; }
void setThumbHoverColor(const Color &color);
Color getThumbHoverColor() const { return thumbHoverColor_; }
void setThumbPressedColor(const Color &color);
Color getThumbPressedColor() const { return thumbPressedColor_; }
// ------------------------------------------------------------------------
// 显示设置
// ------------------------------------------------------------------------
void setShowThumb(bool show);
bool isShowThumb() const { return showThumb_; }
void setShowFill(bool show);
bool isShowFill() const { return showFill_; }
// ------------------------------------------------------------------------
// 文本显示
// ------------------------------------------------------------------------
void setTextEnabled(bool enabled);
bool isTextEnabled() const { return textEnabled_; }
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
void setTextColor(const Color &color);
Color getTextColor() const { return textColor_; }
void setTextFormat(const std::string &format);
const std::string &getTextFormat() const { return textFormat_; }
// ------------------------------------------------------------------------
// 回调设置
// ------------------------------------------------------------------------
void setOnValueChange(Function<void(float)> callback);
void setOnDragStart(Function<void()> callback);
void setOnDragEnd(Function<void()> callback);
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
bool onMousePress(const MouseEvent &event) override;
bool onMouseRelease(const MouseEvent &event) override;
bool onMouseMove(const MouseEvent &event) override;
void onMouseEnter() override;
void onMouseLeave() override;
private:
float min_ = 0.0f;
float max_ = 100.0f;
float value_ = 50.0f;
float step_ = 0.0f;
bool vertical_ = false;
float trackSize_ = 6.0f;
float thumbSize_ = 16.0f;
Color trackColor_ = Color(0.3f, 0.3f, 0.3f, 1.0f);
Color fillColor_ = Color(0.2f, 0.6f, 1.0f, 1.0f);
Color thumbColor_ = Color(0.8f, 0.8f, 0.8f, 1.0f);
Color thumbHoverColor_ = Color(1.0f, 1.0f, 1.0f, 1.0f);
Color thumbPressedColor_ = Color(0.6f, 0.6f, 0.6f, 1.0f);
bool showThumb_ = true;
bool showFill_ = true;
bool textEnabled_ = false;
Ptr<FontAtlas> font_;
Color textColor_ = Colors::White;
std::string textFormat_ = "{value:.0f}";
bool dragging_ = false;
bool hovered_ = false;
Function<void(float)> onValueChange_;
Function<void()> onDragStart_;
Function<void()> onDragEnd_;
float valueToPosition(float value) const;
float positionToValue(float pos) const;
Rect getThumbRect() const;
Rect getTrackRect() const;
std::string formatText() const;
float snapToStep(float value) const;
};
} // namespace extra2d

View File

@ -1,121 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/font.h>
#include <extra2d/ui/widget.h>
#include <cstdarg>
#include <cstdio>
#include <string>
namespace extra2d {
// ============================================================================
// 文本组件 - 继承自 Widget 的 UI 组件
// ============================================================================
class Text : public Widget {
public:
// ------------------------------------------------------------------------
// 对齐方式枚举
// ------------------------------------------------------------------------
enum class Alignment { Left, Center, Right };
enum class VerticalAlignment { Top, Middle, Bottom };
Text();
explicit Text(const std::string &text);
~Text() override = default;
// ------------------------------------------------------------------------
// 静态创建方法
// ------------------------------------------------------------------------
static Ptr<Text> create();
static Ptr<Text> create(const std::string &text);
static Ptr<Text> create(const std::string &text, Ptr<FontAtlas> font);
// ------------------------------------------------------------------------
// 格式化创建方法(类似 printf
// 使用示例:
// auto text = Text::createFormat("FPS: %d", 60);
// auto text = Text::createFormat(font, "得分: %d", score);
// ------------------------------------------------------------------------
static Ptr<Text> createFormat(const char *fmt, ...);
static Ptr<Text> createFormat(Ptr<FontAtlas> font, const char *fmt, ...);
// ------------------------------------------------------------------------
// 文字内容
// ------------------------------------------------------------------------
void setText(const std::string &text);
const std::string &getText() const { return text_; }
// ------------------------------------------------------------------------
// 格式化文本设置(类似 printf
// 使用示例:
// text->setFormat("FPS: %d", 60);
// text->setFormat("位置: (%.1f, %.1f)", x, y);
// text->setFormat("生命值: %d/100", hp);
// ------------------------------------------------------------------------
void setFormat(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[256];
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
text_ = buffer;
sizeDirty_ = true;
updateSpatialIndex();
}
// ------------------------------------------------------------------------
// 字体
// ------------------------------------------------------------------------
void setFont(Ptr<FontAtlas> font);
Ptr<FontAtlas> getFont() const { return font_; }
// ------------------------------------------------------------------------
// 文字属性
// ------------------------------------------------------------------------
void setTextColor(const Color &color);
Color getTextColor() const { return color_; }
void setFontSize(int size);
int getFontSize() const { return fontSize_; }
// ------------------------------------------------------------------------
// 对齐方式
// ------------------------------------------------------------------------
void setAlignment(Alignment align);
Alignment getAlignment() const { return alignment_; }
// ------------------------------------------------------------------------
// 垂直对齐方式
// ------------------------------------------------------------------------
void setVerticalAlignment(VerticalAlignment align);
VerticalAlignment getVerticalAlignment() const { return verticalAlignment_; }
// ------------------------------------------------------------------------
// 尺寸计算
// ------------------------------------------------------------------------
Vec2 getTextSize() const;
float getLineHeight() const;
Rect getBoundingBox() const override;
protected:
void onDrawWidget(RenderBackend &renderer) override;
private:
std::string text_;
Ptr<FontAtlas> font_;
Color color_ = Colors::White;
int fontSize_ = 16;
Alignment alignment_ = Alignment::Left;
VerticalAlignment verticalAlignment_ = VerticalAlignment::Top;
mutable Vec2 cachedSize_ = Vec2::Zero();
mutable bool sizeDirty_ = true;
void updateCache() const;
Vec2 calculateDrawPosition() const;
};
} // namespace extra2d

View File

@ -1,111 +0,0 @@
#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/platform/input.h>
#include <extra2d/scene/node.h>
namespace extra2d {
// ============================================================================
// 鼠标事件结构
// ============================================================================
struct MouseEvent {
MouseButton button;
float x;
float y;
int mods; // 修饰键状态
};
// ============================================================================
// 坐标空间枚举 - 定义 UI 组件的渲染坐标空间
// ============================================================================
enum class CoordinateSpace {
Screen, // 屏幕空间 - 固定位置,不随相机移动
World, // 世界空间 - 随相机移动(默认行为)
Camera, // 相机空间 - 相对于相机位置的偏移
};
// ============================================================================
// Widget 基类 - UI 组件的基础
// ============================================================================
class Widget : public Node {
public:
Widget();
~Widget() override = default;
void setSize(const Size &size);
void setSize(float width, float height);
Size getSize() const { return size_; }
Rect getBoundingBox() const override;
// ------------------------------------------------------------------------
// 坐标空间设置
// ------------------------------------------------------------------------
void setCoordinateSpace(CoordinateSpace space);
CoordinateSpace getCoordinateSpace() const { return coordinateSpace_; }
// ------------------------------------------------------------------------
// 屏幕空间位置设置(仅在 Screen 空间下有效)
// ------------------------------------------------------------------------
void setScreenPosition(const Vec2 &pos);
void setScreenPosition(float x, float y);
Vec2 getScreenPosition() const { return screenPosition_; }
// ------------------------------------------------------------------------
// 相机空间偏移设置(仅在 Camera 空间下有效)
// ------------------------------------------------------------------------
void setCameraOffset(const Vec2 &offset);
void setCameraOffset(float x, float y);
Vec2 getCameraOffset() const { return cameraOffset_; }
// ------------------------------------------------------------------------
// 鼠标事件处理(子类可重写)
// ------------------------------------------------------------------------
virtual bool onMousePress(const MouseEvent &event) { return false; }
virtual bool onMouseRelease(const MouseEvent &event) { return false; }
virtual bool onMouseMove(const MouseEvent &event) { return false; }
virtual void onMouseEnter() {}
virtual void onMouseLeave() {}
// ------------------------------------------------------------------------
// 启用/禁用状态
// ------------------------------------------------------------------------
void setEnabled(bool enabled) { enabled_ = enabled; }
bool isEnabled() const { return enabled_; }
// ------------------------------------------------------------------------
// 焦点状态
// ------------------------------------------------------------------------
void setFocused(bool focused) { focused_ = focused; }
bool isFocused() const { return focused_; }
protected:
// 供子类使用的辅助方法
bool isPointInside(float x, float y) const {
return getBoundingBox().containsPoint(Point(x, y));
}
// 获取实际渲染位置(根据坐标空间计算)
Vec2 getRenderPosition() const;
// 子类重写此方法以支持自定义渲染
virtual void onDrawWidget(RenderBackend &renderer) {}
// 重写 Node 的 onDraw 以处理坐标空间
void onDraw(RenderBackend &renderer) override;
private:
Size size_ = Size::Zero();
bool enabled_ = true;
bool focused_ = false;
bool hovered_ = false;
// 坐标空间相关
CoordinateSpace coordinateSpace_ = CoordinateSpace::World;
Vec2 screenPosition_ = Vec2::Zero(); // 屏幕空间位置
Vec2 cameraOffset_ = Vec2::Zero(); // 相机空间偏移
};
} // namespace extra2d

View File

@ -1,217 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <functional>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// 存档类型枚举
// ============================================================================
enum class SaveDataType {
Account, // 用户存档(与特定用户关联)
Common, // 公共存档(所有用户共享)
Cache, // 缓存数据(可删除)
Device, // 设备存档
Temporary, // 临时数据
};
// ============================================================================
// 用户ID结构封装 Switch AccountUid
// ============================================================================
struct UserId {
uint64_t uid[2] = {0, 0};
bool isValid() const { return uid[0] != 0 || uid[1] != 0; }
bool operator==(const UserId &other) const {
return uid[0] == other.uid[0] && uid[1] == other.uid[1];
}
bool operator!=(const UserId &other) const { return !(*this == other); }
};
// ============================================================================
// DataStore 类 - 数据持久化(支持 Switch 存档系统)
// ============================================================================
class DataStore {
public:
DataStore();
~DataStore();
// ------------------------------------------------------------------------
// 文件操作
// ------------------------------------------------------------------------
/// 加载 INI 文件
bool load(const std::string &filename);
/// 保存到 INI 文件
bool save(const std::string &filename);
/// 获取当前文件名
const std::string &getFilename() const { return filename_; }
// ------------------------------------------------------------------------
// Switch 存档系统支持
// ------------------------------------------------------------------------
/**
* @brief Switch
* @param type
* @param userId IDAccount
* @param mountName "save"
* @return
*/
bool mountSaveData(SaveDataType type = SaveDataType::Account,
const UserId &userId = UserId(),
const std::string &mountName = "save");
/**
* @brief
* @param mountName
*/
void unmountSaveData(const std::string &mountName = "save");
/**
* @brief
* @param mountName
* @return
*/
bool commitSaveData(const std::string &mountName = "save");
/**
* @brief
*/
bool isSaveDataMounted() const { return saveDataMounted_; }
/**
* @brief
*/
std::string getSaveDataPath(const std::string &path = "") const;
// ------------------------------------------------------------------------
// 用户账户管理
// ------------------------------------------------------------------------
/**
* @brief ID
* @return IDID
*/
static UserId getCurrentUserId();
/**
* @brief ID
*/
void setDefaultUserId(const UserId &userId) { defaultUserId_ = userId; }
/**
* @brief ID
*/
UserId getDefaultUserId() const { return defaultUserId_; }
// ------------------------------------------------------------------------
// 数据读写
// ------------------------------------------------------------------------
/// 获取字符串值
std::string getString(const std::string &section, const std::string &key,
const std::string &defaultValue = "");
/// 获取整数值
int getInt(const std::string &section, const std::string &key,
int defaultValue = 0);
/// 获取浮点数值
float getFloat(const std::string &section, const std::string &key,
float defaultValue = 0.0f);
/// 获取布尔值
bool getBool(const std::string &section, const std::string &key,
bool defaultValue = false);
/// 设置字符串值
void setString(const std::string &section, const std::string &key,
const std::string &value);
/// 设置整数值
void setInt(const std::string &section, const std::string &key, int value);
/// 设置浮点数值
void setFloat(const std::string &section, const std::string &key,
float value);
/// 设置布尔值
void setBool(const std::string &section, const std::string &key, bool value);
/// 删除键
void removeKey(const std::string &section, const std::string &key);
/// 删除整个 section
void removeSection(const std::string &section);
/// 检查键是否存在
bool hasKey(const std::string &section, const std::string &key);
/// 检查 section 是否存在
bool hasSection(const std::string &section);
/// 清除所有数据
void clear();
// ------------------------------------------------------------------------
// 事务支持
// ------------------------------------------------------------------------
/**
* @brief
*/
void beginTransaction();
/**
* @brief
* @return
*/
bool commit();
/**
* @brief
*/
void rollback();
/**
* @brief
*/
bool isInTransaction() const { return inTransaction_; }
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/// 获取所有 section 名称
std::vector<std::string> getAllSections() const;
/// 获取指定 section 的所有 key
std::vector<std::string> getAllKeys(const std::string &section) const;
/// 从存档加载(自动处理挂载路径)
bool loadFromSave(const std::string &path);
/// 保存到存档(自动处理挂载路径和提交)
bool saveToSave(const std::string &path);
private:
class Impl;
UniquePtr<Impl> impl_;
std::string filename_;
std::string mountName_;
UserId defaultUserId_;
bool saveDataMounted_ = false;
bool inTransaction_ = false;
bool dirty_ = false;
// 内部辅助方法
bool internalSave(const std::string &filename);
};
} // namespace extra2d

View File

@ -1,492 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <extra2d/utils/logger.h>
#include <atomic>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <mutex>
#include <new>
#include <type_traits>
#include <vector>
namespace extra2d {
// ============================================================================
// 对象池 - 自动管理的高性能内存池
// 特性:
// - 自动内存对齐
// - 侵入式空闲链表(零额外内存开销)
// - 线程本地缓存(减少锁竞争)
// - 自动容量管理(自动扩展/收缩)
// - 自动预热
// - 异常安全
// ============================================================================
// 线程本地缓存配置
struct PoolConfig {
static constexpr size_t DEFAULT_BLOCK_SIZE = 64;
static constexpr size_t THREAD_CACHE_SIZE = 16;
static constexpr size_t SHRINK_THRESHOLD_MS = 30000;
static constexpr double SHRINK_RATIO = 0.5;
};
template <typename T, size_t BlockSize = PoolConfig::DEFAULT_BLOCK_SIZE>
class ObjectPool {
public:
static_assert(std::is_default_constructible_v<T>, "T must be default constructible");
static_assert(std::is_destructible_v<T>, "T must be destructible");
static_assert(BlockSize > 0, "BlockSize must be greater than 0");
static_assert(alignof(T) <= alignof(std::max_align_t),
"Alignment requirement too high");
ObjectPool()
: freeListHead_(nullptr)
, blocks_()
, allocatedCount_(0)
, totalCapacity_(0)
, isDestroyed_(false)
, lastShrinkCheck_(0)
, prewarmed_(false) {
}
~ObjectPool() {
clear();
}
ObjectPool(const ObjectPool&) = delete;
ObjectPool& operator=(const ObjectPool&) = delete;
ObjectPool(ObjectPool&&) noexcept = delete;
ObjectPool& operator=(ObjectPool&&) noexcept = delete;
/**
* @brief
* @return nullptr
*/
T* allocate() {
auto& cache = getThreadCache();
if (T* obj = cache.pop()) {
new (obj) T();
allocatedCount_.fetch_add(1, std::memory_order_relaxed);
return obj;
}
std::lock_guard<std::mutex> lock(mutex_);
if (isDestroyed_) {
return nullptr;
}
if (!prewarmed_) {
prewarmInternal();
}
if (!freeListHead_) {
growInternal();
}
T* obj = popFreeList();
if (obj) {
new (obj) T();
allocatedCount_.fetch_add(1, std::memory_order_relaxed);
}
return obj;
}
/**
* @brief
*/
template <typename... Args>
T* allocate(Args&&... args) {
auto& cache = getThreadCache();
if (T* obj = cache.pop()) {
new (obj) T(std::forward<Args>(args)...);
allocatedCount_.fetch_add(1, std::memory_order_relaxed);
return obj;
}
std::lock_guard<std::mutex> lock(mutex_);
if (isDestroyed_) {
return nullptr;
}
if (!prewarmed_) {
prewarmInternal();
}
if (!freeListHead_) {
growInternal();
}
T* obj = popFreeList();
if (obj) {
new (obj) T(std::forward<Args>(args)...);
allocatedCount_.fetch_add(1, std::memory_order_relaxed);
}
return obj;
}
/**
* @brief
* @param obj
* @return true
*/
bool deallocate(T* obj) {
if (!obj) {
return false;
}
try {
obj->~T();
} catch (const std::exception& e) {
Logger::log(LogLevel::Error, "ObjectPool: Exception in destructor: {}", e.what());
} catch (...) {
Logger::log(LogLevel::Error, "ObjectPool: Unknown exception in destructor");
}
auto& cache = getThreadCache();
if (cache.push(obj)) {
allocatedCount_.fetch_sub(1, std::memory_order_relaxed);
return true;
}
std::lock_guard<std::mutex> lock(mutex_);
if (!isDestroyed_) {
pushFreeList(obj);
allocatedCount_.fetch_sub(1, std::memory_order_relaxed);
tryAutoShrink();
return true;
}
return false;
}
/**
* @brief
*/
size_t allocatedCount() const {
return allocatedCount_.load(std::memory_order_relaxed);
}
/**
* @brief
*/
size_t capacity() const {
return totalCapacity_.load(std::memory_order_relaxed);
}
/**
* @brief 使
*/
size_t memoryUsage() const {
std::lock_guard<std::mutex> lock(mutex_);
return blocks_.size() * BlockSize * sizeof(T);
}
/**
* @brief
*/
void clear() {
std::lock_guard<std::mutex> lock(mutex_);
isDestroyed_ = true;
for (auto& block : blocks_) {
alignedFree(block);
}
blocks_.clear();
freeListHead_ = nullptr;
totalCapacity_.store(0, std::memory_order_relaxed);
allocatedCount_.store(0, std::memory_order_relaxed);
}
private:
struct FreeNode {
FreeNode* next;
};
struct ThreadCache {
T* objects[PoolConfig::THREAD_CACHE_SIZE];
size_t count = 0;
T* pop() {
if (count > 0) {
return objects[--count];
}
return nullptr;
}
bool push(T* obj) {
if (count < PoolConfig::THREAD_CACHE_SIZE) {
objects[count++] = obj;
return true;
}
return false;
}
void clear() {
count = 0;
}
};
static ThreadCache& getThreadCache() {
thread_local ThreadCache cache;
return cache;
}
static constexpr size_t Alignment = alignof(T);
static constexpr size_t AlignedSize = ((sizeof(T) + Alignment - 1) / Alignment) * Alignment;
static void* alignedAlloc(size_t size) {
#ifdef _WIN32
return _aligned_malloc(size, Alignment);
#else
return std::aligned_alloc(Alignment, size);
#endif
}
static void alignedFree(void* ptr) {
#ifdef _WIN32
_aligned_free(ptr);
#else
std::free(ptr);
#endif
}
void prewarmInternal() {
if (!freeListHead_) {
growInternal();
}
prewarmed_ = true;
}
void growInternal() {
size_t blockSize = AlignedSize > sizeof(FreeNode) ? AlignedSize : sizeof(FreeNode);
size_t totalSize = blockSize * BlockSize;
void* block = alignedAlloc(totalSize);
if (!block) {
Logger::log(LogLevel::Error, "ObjectPool: Failed to allocate memory block");
return;
}
blocks_.push_back(block);
totalCapacity_.fetch_add(BlockSize, std::memory_order_relaxed);
char* ptr = static_cast<char*>(block);
for (size_t i = 0; i < BlockSize; ++i) {
pushFreeList(reinterpret_cast<T*>(ptr + i * blockSize));
}
}
void pushFreeList(T* obj) {
FreeNode* node = reinterpret_cast<FreeNode*>(obj);
node->next = freeListHead_;
freeListHead_ = node;
}
T* popFreeList() {
if (!freeListHead_) {
return nullptr;
}
FreeNode* node = freeListHead_;
freeListHead_ = freeListHead_->next;
return reinterpret_cast<T*>(node);
}
void tryAutoShrink() {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count();
if (elapsed - lastShrinkCheck_ < PoolConfig::SHRINK_THRESHOLD_MS) {
return;
}
lastShrinkCheck_ = elapsed;
size_t allocated = allocatedCount_.load(std::memory_order_relaxed);
size_t capacity = totalCapacity_.load(std::memory_order_relaxed);
if (capacity > BlockSize &&
static_cast<double>(allocated) / capacity < PoolConfig::SHRINK_RATIO) {
shrinkInternal();
}
}
void shrinkInternal() {
size_t toFree = 0;
size_t freeCount = 0;
FreeNode* node = freeListHead_;
while (node) {
++freeCount;
node = node->next;
}
if (freeCount < BlockSize) {
return;
}
size_t blocksToKeep = blocks_.size();
if (allocatedCount_.load(std::memory_order_relaxed) > 0) {
blocksToKeep = (allocatedCount_.load() + BlockSize - 1) / BlockSize;
blocksToKeep = std::max(blocksToKeep, size_t(1));
}
if (blocksToKeep >= blocks_.size()) {
return;
}
size_t blocksToRemove = blocks_.size() - blocksToKeep;
for (size_t i = 0; i < blocksToRemove; ++i) {
if (blocks_.empty()) break;
void* block = blocks_.back();
blocks_.pop_back();
alignedFree(block);
totalCapacity_.fetch_sub(BlockSize, std::memory_order_relaxed);
}
rebuildFreeList();
}
void rebuildFreeList() {
freeListHead_ = nullptr;
size_t blockSize = AlignedSize > sizeof(FreeNode) ? AlignedSize : sizeof(FreeNode);
for (void* block : blocks_) {
char* ptr = static_cast<char*>(block);
for (size_t i = 0; i < BlockSize; ++i) {
pushFreeList(reinterpret_cast<T*>(ptr + i * blockSize));
}
}
}
mutable std::mutex mutex_;
FreeNode* freeListHead_;
std::vector<void*> blocks_;
std::atomic<size_t> allocatedCount_;
std::atomic<size_t> totalCapacity_;
bool isDestroyed_;
uint64_t lastShrinkCheck_;
bool prewarmed_;
};
// ============================================================================
// 智能指针支持的内存池分配器
// ============================================================================
template <typename T, size_t BlockSize = PoolConfig::DEFAULT_BLOCK_SIZE>
class PooledAllocator {
public:
using PoolType = ObjectPool<T, BlockSize>;
PooledAllocator() : pool_(std::make_shared<PoolType>()) {}
explicit PooledAllocator(std::shared_ptr<PoolType> pool) : pool_(pool) {}
/**
* @brief 使
*/
template <typename... Args>
Ptr<T> makeShared(Args&&... args) {
std::weak_ptr<PoolType> weakPool = pool_;
T* obj = pool_->allocate(std::forward<Args>(args)...);
if (!obj) {
return nullptr;
}
return Ptr<T>(obj, Deleter{weakPool});
}
/**
* @brief
*/
std::shared_ptr<PoolType> getPool() const {
return pool_;
}
private:
struct Deleter {
std::weak_ptr<PoolType> pool;
void operator()(T* obj) const {
if (auto sharedPool = pool.lock()) {
if (!sharedPool->deallocate(obj)) {
Logger::log(LogLevel::Warn, "PooledAllocator: Pool destroyed, memory leaked");
}
} else {
Logger::log(LogLevel::Warn, "PooledAllocator: Pool expired during deallocation");
}
}
};
std::shared_ptr<PoolType> pool_;
};
// ============================================================================
// 全局内存池管理器 - 自动管理所有池的生命周期
// ============================================================================
class ObjectPoolManager {
public:
static ObjectPoolManager& getInstance() {
static ObjectPoolManager instance;
return instance;
}
/**
* @brief
*/
template <typename T, size_t BlockSize = PoolConfig::DEFAULT_BLOCK_SIZE>
std::shared_ptr<ObjectPool<T, BlockSize>> getPool() {
static auto pool = std::make_shared<ObjectPool<T, BlockSize>>();
return pool;
}
/**
* @brief 使
*/
template <typename T, size_t BlockSize = PoolConfig::DEFAULT_BLOCK_SIZE, typename... Args>
Ptr<T> makePooled(Args&&... args) {
auto pool = getPool<T, BlockSize>();
std::weak_ptr<ObjectPool<T, BlockSize>> weakPool = pool;
T* obj = pool->allocate(std::forward<Args>(args)...);
if (!obj) {
return nullptr;
}
return Ptr<T>(obj, [weakPool](T* p) {
if (auto sharedPool = weakPool.lock()) {
if (!sharedPool->deallocate(p)) {
Logger::log(LogLevel::Warn, "ObjectPoolManager: Pool destroyed during deallocation");
}
} else {
Logger::log(LogLevel::Warn, "ObjectPoolManager: Pool expired");
}
});
}
private:
ObjectPoolManager() = default;
~ObjectPoolManager() = default;
ObjectPoolManager(const ObjectPoolManager&) = delete;
ObjectPoolManager& operator=(const ObjectPoolManager&) = delete;
};
// ============================================================================
// 内存池宏定义(便于使用)
// ============================================================================
#define E2D_DECLARE_POOL(T, BlockSize) \
static extra2d::ObjectPool<T, BlockSize>& getPool() { \
static extra2d::ObjectPool<T, BlockSize> pool; \
return pool; \
}
#define E2D_MAKE_POOLED(T, ...) \
extra2d::ObjectPoolManager::getInstance().makePooled<T>(__VA_ARGS__)
} // namespace extra2d

View File

@ -1,85 +0,0 @@
#pragma once
#include <extra2d/core/types.h>
#include <random>
namespace extra2d {
// ============================================================================
// Random 类 - 随机数生成器
// ============================================================================
class Random {
public:
/// 获取单例实例
static Random &getInstance();
/// 设置随机种子
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::getInstance().getFloat(); }
/// 获取 [min, max] 范围内的随机浮点数
inline float randomFloat(float min, float max) {
return Random::getInstance().getFloat(min, max);
}
/// 获取 [0, max] 范围内的随机整数
inline int randomInt(int max) { return Random::getInstance().getInt(max); }
/// 获取 [min, max] 范围内的随机整数
inline int randomInt(int min, int max) {
return Random::getInstance().getInt(min, max);
}
/// 获取随机布尔值
inline bool randomBool() { return Random::getInstance().getBool(); }
/// 获取随机布尔值(带概率)
inline bool randomBool(float probability) {
return Random::getInstance().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

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,49 +0,0 @@
#include "extra2d/action/action.h"
#include "extra2d/scene/node.h"
namespace extra2d {
Action::Action() : tag_(-1), flags_(0) {}
bool Action::isDone() const {
return state_ == ActionState::Completed;
}
void Action::startWithTarget(Node* target) {
target_ = target;
originalTarget_ = target;
state_ = ActionState::Running;
onStart();
}
void Action::stop() {
target_ = nullptr;
state_ = ActionState::Completed;
}
void Action::step(float dt) {
(void)dt;
}
void Action::update(float time) {
(void)time;
}
void Action::pause() {
if (state_ == ActionState::Running) {
state_ = ActionState::Paused;
}
}
void Action::resume() {
if (state_ == ActionState::Paused) {
state_ = ActionState::Running;
}
}
void Action::restart() {
state_ = ActionState::Running;
onStart();
}
} // namespace extra2d

View File

@ -1,683 +0,0 @@
#include "extra2d/action/action_ease.h"
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
namespace extra2d {
// ============================================================================
// ActionEase 基类
// ============================================================================
ActionEase::~ActionEase() {
delete innerAction_;
}
bool ActionEase::initWithAction(ActionInterval* action) {
if (!action) {
return false;
}
innerAction_ = action;
duration_ = action->getDuration();
return true;
}
void ActionEase::startWithTarget(Node* target) {
ActionInterval::startWithTarget(target);
innerAction_->startWithTarget(target);
}
void ActionEase::stop() {
innerAction_->stop();
ActionInterval::stop();
}
void ActionEase::update(float time) {
innerAction_->update(time);
}
// ============================================================================
// 指数缓动
// ============================================================================
EaseExponentialIn* EaseExponentialIn::create(ActionInterval* action) {
auto* ease = new EaseExponentialIn();
ease->initWithAction(action);
return ease;
}
void EaseExponentialIn::update(float time) {
innerAction_->update(easeInExpo(time));
}
ActionInterval* EaseExponentialIn::clone() const {
return EaseExponentialIn::create(innerAction_->clone());
}
ActionInterval* EaseExponentialIn::reverse() const {
return EaseExponentialOut::create(innerAction_->reverse());
}
EaseExponentialOut* EaseExponentialOut::create(ActionInterval* action) {
auto* ease = new EaseExponentialOut();
ease->initWithAction(action);
return ease;
}
void EaseExponentialOut::update(float time) {
innerAction_->update(easeOutExpo(time));
}
ActionInterval* EaseExponentialOut::clone() const {
return EaseExponentialOut::create(innerAction_->clone());
}
ActionInterval* EaseExponentialOut::reverse() const {
return EaseExponentialIn::create(innerAction_->reverse());
}
EaseExponentialInOut* EaseExponentialInOut::create(ActionInterval* action) {
auto* ease = new EaseExponentialInOut();
ease->initWithAction(action);
return ease;
}
void EaseExponentialInOut::update(float time) {
innerAction_->update(easeInOutExpo(time));
}
ActionInterval* EaseExponentialInOut::clone() const {
return EaseExponentialInOut::create(innerAction_->clone());
}
ActionInterval* EaseExponentialInOut::reverse() const {
return EaseExponentialInOut::create(innerAction_->reverse());
}
// ============================================================================
// 正弦缓动
// ============================================================================
EaseSineIn* EaseSineIn::create(ActionInterval* action) {
auto* ease = new EaseSineIn();
ease->initWithAction(action);
return ease;
}
void EaseSineIn::update(float time) {
innerAction_->update(easeInSine(time));
}
ActionInterval* EaseSineIn::clone() const {
return EaseSineIn::create(innerAction_->clone());
}
ActionInterval* EaseSineIn::reverse() const {
return EaseSineOut::create(innerAction_->reverse());
}
EaseSineOut* EaseSineOut::create(ActionInterval* action) {
auto* ease = new EaseSineOut();
ease->initWithAction(action);
return ease;
}
void EaseSineOut::update(float time) {
innerAction_->update(easeOutSine(time));
}
ActionInterval* EaseSineOut::clone() const {
return EaseSineOut::create(innerAction_->clone());
}
ActionInterval* EaseSineOut::reverse() const {
return EaseSineIn::create(innerAction_->reverse());
}
EaseSineInOut* EaseSineInOut::create(ActionInterval* action) {
auto* ease = new EaseSineInOut();
ease->initWithAction(action);
return ease;
}
void EaseSineInOut::update(float time) {
innerAction_->update(easeInOutSine(time));
}
ActionInterval* EaseSineInOut::clone() const {
return EaseSineInOut::create(innerAction_->clone());
}
ActionInterval* EaseSineInOut::reverse() const {
return EaseSineInOut::create(innerAction_->reverse());
}
// ============================================================================
// 弹性缓动
// ============================================================================
EaseElasticIn* EaseElasticIn::create(ActionInterval* action, float period) {
auto* ease = new EaseElasticIn();
ease->initWithAction(action);
ease->period_ = period;
return ease;
}
void EaseElasticIn::update(float time) {
float newT = 0.0f;
if (time == 0.0f || time == 1.0f) {
newT = time;
} else {
float s = period_ / 4.0f;
time = time - 1.0f;
newT = -std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
}
innerAction_->update(newT);
}
ActionInterval* EaseElasticIn::clone() const {
return EaseElasticIn::create(innerAction_->clone(), period_);
}
ActionInterval* EaseElasticIn::reverse() const {
return EaseElasticOut::create(innerAction_->reverse(), period_);
}
EaseElasticOut* EaseElasticOut::create(ActionInterval* action, float period) {
auto* ease = new EaseElasticOut();
ease->initWithAction(action);
ease->period_ = period;
return ease;
}
void EaseElasticOut::update(float time) {
float newT = 0.0f;
if (time == 0.0f || time == 1.0f) {
newT = time;
} else {
float s = period_ / 4.0f;
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) + 1.0f;
}
innerAction_->update(newT);
}
ActionInterval* EaseElasticOut::clone() const {
return EaseElasticOut::create(innerAction_->clone(), period_);
}
ActionInterval* EaseElasticOut::reverse() const {
return EaseElasticIn::create(innerAction_->reverse(), period_);
}
EaseElasticInOut* EaseElasticInOut::create(ActionInterval* action, float period) {
auto* ease = new EaseElasticInOut();
ease->initWithAction(action);
ease->period_ = period;
return ease;
}
void EaseElasticInOut::update(float time) {
float newT = 0.0f;
if (time == 0.0f || time == 1.0f) {
newT = time;
} else {
time = time * 2.0f;
if (period_ == 0.0f) {
period_ = 0.3f * 1.5f;
}
float s = period_ / 4.0f;
if (time < 1.0f) {
time -= 1.0f;
newT = -0.5f * std::pow(2.0f, 10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_);
} else {
time -= 1.0f;
newT = std::pow(2.0f, -10.0f * time) * std::sin((time - s) * M_PI * 2.0f / period_) * 0.5f + 1.0f;
}
}
innerAction_->update(newT);
}
ActionInterval* EaseElasticInOut::clone() const {
return EaseElasticInOut::create(innerAction_->clone(), period_);
}
ActionInterval* EaseElasticInOut::reverse() const {
return EaseElasticInOut::create(innerAction_->reverse(), period_);
}
// ============================================================================
// 弹跳缓动
// ============================================================================
EaseBounceIn* EaseBounceIn::create(ActionInterval* action) {
auto* ease = new EaseBounceIn();
ease->initWithAction(action);
return ease;
}
void EaseBounceIn::update(float time) {
innerAction_->update(easeInBounce(time));
}
ActionInterval* EaseBounceIn::clone() const {
return EaseBounceIn::create(innerAction_->clone());
}
ActionInterval* EaseBounceIn::reverse() const {
return EaseBounceOut::create(innerAction_->reverse());
}
EaseBounceOut* EaseBounceOut::create(ActionInterval* action) {
auto* ease = new EaseBounceOut();
ease->initWithAction(action);
return ease;
}
void EaseBounceOut::update(float time) {
innerAction_->update(easeOutBounce(time));
}
ActionInterval* EaseBounceOut::clone() const {
return EaseBounceOut::create(innerAction_->clone());
}
ActionInterval* EaseBounceOut::reverse() const {
return EaseBounceIn::create(innerAction_->reverse());
}
EaseBounceInOut* EaseBounceInOut::create(ActionInterval* action) {
auto* ease = new EaseBounceInOut();
ease->initWithAction(action);
return ease;
}
void EaseBounceInOut::update(float time) {
innerAction_->update(easeInOutBounce(time));
}
ActionInterval* EaseBounceInOut::clone() const {
return EaseBounceInOut::create(innerAction_->clone());
}
ActionInterval* EaseBounceInOut::reverse() const {
return EaseBounceInOut::create(innerAction_->reverse());
}
// ============================================================================
// 回震缓动
// ============================================================================
EaseBackIn* EaseBackIn::create(ActionInterval* action) {
auto* ease = new EaseBackIn();
ease->initWithAction(action);
return ease;
}
void EaseBackIn::update(float time) {
innerAction_->update(easeInBack(time));
}
ActionInterval* EaseBackIn::clone() const {
return EaseBackIn::create(innerAction_->clone());
}
ActionInterval* EaseBackIn::reverse() const {
return EaseBackOut::create(innerAction_->reverse());
}
EaseBackOut* EaseBackOut::create(ActionInterval* action) {
auto* ease = new EaseBackOut();
ease->initWithAction(action);
return ease;
}
void EaseBackOut::update(float time) {
innerAction_->update(easeOutBack(time));
}
ActionInterval* EaseBackOut::clone() const {
return EaseBackOut::create(innerAction_->clone());
}
ActionInterval* EaseBackOut::reverse() const {
return EaseBackIn::create(innerAction_->reverse());
}
EaseBackInOut* EaseBackInOut::create(ActionInterval* action) {
auto* ease = new EaseBackInOut();
ease->initWithAction(action);
return ease;
}
void EaseBackInOut::update(float time) {
innerAction_->update(easeInOutBack(time));
}
ActionInterval* EaseBackInOut::clone() const {
return EaseBackInOut::create(innerAction_->clone());
}
ActionInterval* EaseBackInOut::reverse() const {
return EaseBackInOut::create(innerAction_->reverse());
}
// ============================================================================
// 二次缓动
// ============================================================================
EaseQuadIn* EaseQuadIn::create(ActionInterval* action) {
auto* ease = new EaseQuadIn();
ease->initWithAction(action);
return ease;
}
void EaseQuadIn::update(float time) {
innerAction_->update(easeInQuad(time));
}
ActionInterval* EaseQuadIn::clone() const {
return EaseQuadIn::create(innerAction_->clone());
}
ActionInterval* EaseQuadIn::reverse() const {
return EaseQuadOut::create(innerAction_->reverse());
}
EaseQuadOut* EaseQuadOut::create(ActionInterval* action) {
auto* ease = new EaseQuadOut();
ease->initWithAction(action);
return ease;
}
void EaseQuadOut::update(float time) {
innerAction_->update(easeOutQuad(time));
}
ActionInterval* EaseQuadOut::clone() const {
return EaseQuadOut::create(innerAction_->clone());
}
ActionInterval* EaseQuadOut::reverse() const {
return EaseQuadIn::create(innerAction_->reverse());
}
EaseQuadInOut* EaseQuadInOut::create(ActionInterval* action) {
auto* ease = new EaseQuadInOut();
ease->initWithAction(action);
return ease;
}
void EaseQuadInOut::update(float time) {
innerAction_->update(easeInOutQuad(time));
}
ActionInterval* EaseQuadInOut::clone() const {
return EaseQuadInOut::create(innerAction_->clone());
}
ActionInterval* EaseQuadInOut::reverse() const {
return EaseQuadInOut::create(innerAction_->reverse());
}
// ============================================================================
// 三次缓动
// ============================================================================
EaseCubicIn* EaseCubicIn::create(ActionInterval* action) {
auto* ease = new EaseCubicIn();
ease->initWithAction(action);
return ease;
}
void EaseCubicIn::update(float time) {
innerAction_->update(easeInCubic(time));
}
ActionInterval* EaseCubicIn::clone() const {
return EaseCubicIn::create(innerAction_->clone());
}
ActionInterval* EaseCubicIn::reverse() const {
return EaseCubicOut::create(innerAction_->reverse());
}
EaseCubicOut* EaseCubicOut::create(ActionInterval* action) {
auto* ease = new EaseCubicOut();
ease->initWithAction(action);
return ease;
}
void EaseCubicOut::update(float time) {
innerAction_->update(easeOutCubic(time));
}
ActionInterval* EaseCubicOut::clone() const {
return EaseCubicOut::create(innerAction_->clone());
}
ActionInterval* EaseCubicOut::reverse() const {
return EaseCubicIn::create(innerAction_->reverse());
}
EaseCubicInOut* EaseCubicInOut::create(ActionInterval* action) {
auto* ease = new EaseCubicInOut();
ease->initWithAction(action);
return ease;
}
void EaseCubicInOut::update(float time) {
innerAction_->update(easeInOutCubic(time));
}
ActionInterval* EaseCubicInOut::clone() const {
return EaseCubicInOut::create(innerAction_->clone());
}
ActionInterval* EaseCubicInOut::reverse() const {
return EaseCubicInOut::create(innerAction_->reverse());
}
// ============================================================================
// 四次缓动
// ============================================================================
EaseQuartIn* EaseQuartIn::create(ActionInterval* action) {
auto* ease = new EaseQuartIn();
ease->initWithAction(action);
return ease;
}
void EaseQuartIn::update(float time) {
innerAction_->update(easeInQuart(time));
}
ActionInterval* EaseQuartIn::clone() const {
return EaseQuartIn::create(innerAction_->clone());
}
ActionInterval* EaseQuartIn::reverse() const {
return EaseQuartOut::create(innerAction_->reverse());
}
EaseQuartOut* EaseQuartOut::create(ActionInterval* action) {
auto* ease = new EaseQuartOut();
ease->initWithAction(action);
return ease;
}
void EaseQuartOut::update(float time) {
innerAction_->update(easeOutQuart(time));
}
ActionInterval* EaseQuartOut::clone() const {
return EaseQuartOut::create(innerAction_->clone());
}
ActionInterval* EaseQuartOut::reverse() const {
return EaseQuartIn::create(innerAction_->reverse());
}
EaseQuartInOut* EaseQuartInOut::create(ActionInterval* action) {
auto* ease = new EaseQuartInOut();
ease->initWithAction(action);
return ease;
}
void EaseQuartInOut::update(float time) {
innerAction_->update(easeInOutQuart(time));
}
ActionInterval* EaseQuartInOut::clone() const {
return EaseQuartInOut::create(innerAction_->clone());
}
ActionInterval* EaseQuartInOut::reverse() const {
return EaseQuartInOut::create(innerAction_->reverse());
}
// ============================================================================
// 五次缓动
// ============================================================================
EaseQuintIn* EaseQuintIn::create(ActionInterval* action) {
auto* ease = new EaseQuintIn();
ease->initWithAction(action);
return ease;
}
void EaseQuintIn::update(float time) {
innerAction_->update(easeInQuint(time));
}
ActionInterval* EaseQuintIn::clone() const {
return EaseQuintIn::create(innerAction_->clone());
}
ActionInterval* EaseQuintIn::reverse() const {
return EaseQuintOut::create(innerAction_->reverse());
}
EaseQuintOut* EaseQuintOut::create(ActionInterval* action) {
auto* ease = new EaseQuintOut();
ease->initWithAction(action);
return ease;
}
void EaseQuintOut::update(float time) {
innerAction_->update(easeOutQuint(time));
}
ActionInterval* EaseQuintOut::clone() const {
return EaseQuintOut::create(innerAction_->clone());
}
ActionInterval* EaseQuintOut::reverse() const {
return EaseQuintIn::create(innerAction_->reverse());
}
EaseQuintInOut* EaseQuintInOut::create(ActionInterval* action) {
auto* ease = new EaseQuintInOut();
ease->initWithAction(action);
return ease;
}
void EaseQuintInOut::update(float time) {
innerAction_->update(easeInOutQuint(time));
}
ActionInterval* EaseQuintInOut::clone() const {
return EaseQuintInOut::create(innerAction_->clone());
}
ActionInterval* EaseQuintInOut::reverse() const {
return EaseQuintInOut::create(innerAction_->reverse());
}
// ============================================================================
// 圆形缓动
// ============================================================================
EaseCircleIn* EaseCircleIn::create(ActionInterval* action) {
auto* ease = new EaseCircleIn();
ease->initWithAction(action);
return ease;
}
void EaseCircleIn::update(float time) {
innerAction_->update(easeInCirc(time));
}
ActionInterval* EaseCircleIn::clone() const {
return EaseCircleIn::create(innerAction_->clone());
}
ActionInterval* EaseCircleIn::reverse() const {
return EaseCircleOut::create(innerAction_->reverse());
}
EaseCircleOut* EaseCircleOut::create(ActionInterval* action) {
auto* ease = new EaseCircleOut();
ease->initWithAction(action);
return ease;
}
void EaseCircleOut::update(float time) {
innerAction_->update(easeOutCirc(time));
}
ActionInterval* EaseCircleOut::clone() const {
return EaseCircleOut::create(innerAction_->clone());
}
ActionInterval* EaseCircleOut::reverse() const {
return EaseCircleIn::create(innerAction_->reverse());
}
EaseCircleInOut* EaseCircleInOut::create(ActionInterval* action) {
auto* ease = new EaseCircleInOut();
ease->initWithAction(action);
return ease;
}
void EaseCircleInOut::update(float time) {
innerAction_->update(easeInOutCirc(time));
}
ActionInterval* EaseCircleInOut::clone() const {
return EaseCircleInOut::create(innerAction_->clone());
}
ActionInterval* EaseCircleInOut::reverse() const {
return EaseCircleInOut::create(innerAction_->reverse());
}
// ============================================================================
// 自定义缓动
// ============================================================================
EaseCustom* EaseCustom::create(ActionInterval* action, EaseFunction easeFunc) {
auto* ease = new EaseCustom();
ease->initWithAction(action);
ease->easeFunc_ = easeFunc;
return ease;
}
void EaseCustom::update(float time) {
if (easeFunc_) {
innerAction_->update(easeFunc_(time));
} else {
innerAction_->update(time);
}
}
ActionInterval* EaseCustom::clone() const {
return EaseCustom::create(innerAction_->clone(), easeFunc_);
}
ActionInterval* EaseCustom::reverse() const {
return EaseCustom::create(innerAction_->reverse(), easeFunc_);
}
} // namespace extra2d

View File

@ -1,30 +0,0 @@
#include "extra2d/action/action_instant.h"
#include "extra2d/scene/node.h"
namespace extra2d {
ActionInstant::ActionInstant() {
duration_ = 0.0f;
}
bool ActionInstant::isDone() const {
return done_;
}
void ActionInstant::startWithTarget(Node* target) {
FiniteTimeAction::startWithTarget(target);
done_ = false;
}
void ActionInstant::step(float dt) {
(void)dt;
if (state_ != ActionState::Running) {
return;
}
execute();
done_ = true;
state_ = ActionState::Completed;
onComplete();
}
} // namespace extra2d

View File

@ -1,202 +0,0 @@
#include "extra2d/action/action_instant_actions.h"
#include "extra2d/scene/node.h"
namespace extra2d {
// ============================================================================
// 回调动作
// ============================================================================
CallFunc* CallFunc::create(const Callback& callback) {
auto* action = new CallFunc();
action->callback_ = callback;
return action;
}
void CallFunc::execute() {
if (callback_) {
callback_();
}
}
ActionInstant* CallFunc::clone() const {
return CallFunc::create(callback_);
}
ActionInstant* CallFunc::reverse() const {
return CallFunc::create(callback_);
}
// CallFuncN
CallFuncN* CallFuncN::create(const Callback& callback) {
auto* action = new CallFuncN();
action->callback_ = callback;
return action;
}
void CallFuncN::execute() {
if (callback_ && target_) {
callback_(target_);
}
}
ActionInstant* CallFuncN::clone() const {
return CallFuncN::create(callback_);
}
ActionInstant* CallFuncN::reverse() const {
return CallFuncN::create(callback_);
}
// ============================================================================
// 位置动作
// ============================================================================
Place* Place::create(const Vec2& position) {
auto* action = new Place();
action->position_ = position;
return action;
}
void Place::execute() {
if (target_) {
target_->setPosition(position_);
}
}
ActionInstant* Place::clone() const {
return Place::create(position_);
}
ActionInstant* Place::reverse() const {
return Place::create(position_);
}
// ============================================================================
// 翻转动作
// ============================================================================
FlipX* FlipX::create(bool flipX) {
auto* action = new FlipX();
action->flipX_ = flipX;
return action;
}
void FlipX::execute() {
if (target_) {
target_->setFlipX(flipX_);
}
}
ActionInstant* FlipX::clone() const {
return FlipX::create(flipX_);
}
ActionInstant* FlipX::reverse() const {
return FlipX::create(!flipX_);
}
// FlipY
FlipY* FlipY::create(bool flipY) {
auto* action = new FlipY();
action->flipY_ = flipY;
return action;
}
void FlipY::execute() {
if (target_) {
target_->setFlipY(flipY_);
}
}
ActionInstant* FlipY::clone() const {
return FlipY::create(flipY_);
}
ActionInstant* FlipY::reverse() const {
return FlipY::create(!flipY_);
}
// ============================================================================
// 可见性动作
// ============================================================================
Show* Show::create() {
return new Show();
}
void Show::execute() {
if (target_) {
target_->setVisible(true);
}
}
ActionInstant* Show::clone() const {
return Show::create();
}
ActionInstant* Show::reverse() const {
return Hide::create();
}
// Hide
Hide* Hide::create() {
return new Hide();
}
void Hide::execute() {
if (target_) {
target_->setVisible(false);
}
}
ActionInstant* Hide::clone() const {
return Hide::create();
}
ActionInstant* Hide::reverse() const {
return Show::create();
}
// ToggleVisibility
ToggleVisibility* ToggleVisibility::create() {
return new ToggleVisibility();
}
void ToggleVisibility::execute() {
if (target_) {
target_->setVisible(!target_->isVisible());
}
}
ActionInstant* ToggleVisibility::clone() const {
return ToggleVisibility::create();
}
ActionInstant* ToggleVisibility::reverse() const {
return ToggleVisibility::create();
}
// ============================================================================
// 节点管理动作
// ============================================================================
RemoveSelf* RemoveSelf::create() {
return new RemoveSelf();
}
void RemoveSelf::execute() {
if (target_) {
target_->removeFromParent();
}
}
ActionInstant* RemoveSelf::clone() const {
return RemoveSelf::create();
}
ActionInstant* RemoveSelf::reverse() const {
return RemoveSelf::create();
}
} // namespace extra2d

View File

@ -1,56 +0,0 @@
#include "extra2d/action/action_interval.h"
#include "extra2d/scene/node.h"
namespace extra2d {
ActionInterval::ActionInterval(float duration)
: FiniteTimeAction(duration) {
}
bool ActionInterval::isDone() const {
return elapsed_ >= duration_;
}
void ActionInterval::startWithTarget(Node* target) {
FiniteTimeAction::startWithTarget(target);
elapsed_ = 0.0f;
firstTick_ = true;
onStart();
}
void ActionInterval::stop() {
FiniteTimeAction::stop();
}
void ActionInterval::step(float dt) {
if (state_ != ActionState::Running) {
return;
}
if (firstTick_) {
firstTick_ = false;
elapsed_ = 0.0f;
} else {
elapsed_ += dt;
}
float progress = 0.0f;
if (duration_ > 0.0f) {
progress = std::min(1.0f, elapsed_ / duration_);
} else {
progress = 1.0f;
}
if (easeFunc_) {
progress = easeFunc_(progress);
}
onUpdate(progress);
if (progress >= 1.0f) {
state_ = ActionState::Completed;
onComplete();
}
}
} // namespace extra2d

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