# Frostbite2D 引擎架构说明 ## 1. 整体架构图 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 用户应用层 (main.cpp) │ │ 创建配置 → 初始化应用 → 游戏循环 → 清理 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 应用程序层 (Application) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 单例管理 │ │ 模块系统 │ │ 时间管理 │ │ 窗口管理 │ │ │ │ get() │ │ use/init │ │ deltaTime() │ │ Window │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ │ ┌───────────┴───────────┐ │ │ ▼ ▼ │ │ mainLoop() ────────► update()/render() │ └─────────────────────────────────────────────────────────────────────────────┘ │ ┌────────────────────────────┼────────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │ 渲染系统 │ │ 着色器系统 │ │ 输入系统 │ │ (GLRenderer) │◄────►│ (ShaderManager) │ │ (SDL Events) │ └─────────────────┘ └─────────────────────┘ └─────────────────────┘ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 渲染核心层 │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ │ │ │ 2D图形绘制 │ │ 精灵批处理 │ │ 字体渲染 │ │ 相机 │ │ │ │ drawRect() │ │ GLSpriteBatch │ │ GLFontAtlas │ │ Camera │ │ │ │ fillCircle() │ │ 10000 sprites │ │ stb_truetype │ │ view/proj │ │ │ │ drawLine() │ │ drawSprite() │ │ cache glyphs │ │ move/zoom │ │ │ │ drawText() │ │ endBatch() │ │ measureText() │ │ │ │ │ └────────────────┘ └────────────────┘ └────────────────┘ └───────────┘ │ │ │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ │ │ 纹理管理 │ │ 着色器实现 │ │ OpenGL资源 │ │ │ │ GLTexture │ │ GLShader │ │ VAO/VBO │ │ │ │ load from file│ │ vertex/frag │ │ shape/line │ │ │ └────────────────┘ └────────────────┘ └────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 平台抽象层 │ │ ┌─────────────────────────┐ ┌─────────────────────────────────────┐ │ │ │ Window 窗口 │ │ SDL2 跨平台库 │ │ │ │ - 创建/销毁窗口 │ │ 窗口管理 | 事件处理 | OpenGL上下文 │ │ │ │ - OpenGL 上下文 │ │ │ │ │ │ - 事件轮询 │ │ 支持: Windows | Linux | macOS │ │ │ │ - 交换缓冲区 │ │ Android | iOS | Switch │ │ │ └─────────────────────────┘ └─────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第三方库 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ OpenGL │ │ SDL2 │ │ GLAD │ │ GLM │ │ stb_truetype │ │ │ │ ES 3.2 │ │ 2.32.2 │ │ Loader │ │ 1.0.3 │ │ rect_pack │ │ │ │ 图形API │ │ 窗口/输入 │ │ 函数加载 │ │ 数学库 │ │ 字体渲染 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ## 2. 模块详细说明 ### 2.1 应用程序层 (Application) ``` ┌─────────────────────────────────────────┐ │ Application 单例 │ ├─────────────────────────────────────────┤ │ + get() : Application& │ │ + init(config) : bool │ │ + run() : void │ │ + quit() : void │ │ + deltaTime() : float │ │ + fps() : int │ ├─────────────────────────────────────────┤ │ - window_ : Window* │ │ - modules_ : vector │ │ - running_ : bool │ │ - deltaTime_ : float │ │ - currentFps_ : int │ └─────────────────────────────────────────┘ ``` **生命周期流程:** ``` main() │ ├─► AppConfig config = AppConfig::createDefault() │ ├─► Application::get().init(config) │ ├─► 创建 Window │ ├─► 初始化 SDL │ └─► 初始化 GLAD (OpenGL 函数加载) │ ├─► ShaderManager::getInstance().init(factory) │ ├─► 加载 sprite shader │ └─► 加载 shape shader │ ├─► GLRenderer.init(window) │ ├─► 创建 VAO/VBO │ ├─► 初始化 SpriteBatch │ └─► 设置 OpenGL 状态 │ ├─► 游戏主循环 │ ├─► 处理输入事件 (SDL_PollEvent) │ ├─► renderer.beginFrame(color) // 清除缓冲区 │ ├─► 绘制图形 │ │ ├─► fillRect() 填充矩形 │ │ ├─► fillCircle() 填充圆形 │ │ ├─► drawLine() 绘制线条 │ │ ├─► drawText() 绘制文字 │ │ └─► ... │ ├─► renderer.endFrame() // 提交批次 │ └─► SDL_GL_SwapWindow() // 显示到屏幕 │ ├─► 清理资源 │ ├─► renderer.shutdown() │ ├─► ShaderManager::shutdown() │ └─► Application::shutdown() │ └─► return 0 ``` ### 2.2 渲染系统 (GLRenderer) **核心功能:** | 功能类别 | 方法 | 说明 | |---------|------|------| | **帧管理** | `beginFrame()` / `endFrame()` | 开始/结束渲染帧 | | **2D形状** | `fillRect()` / `drawRect()` | 填充/描边矩形 | | **圆形** | `fillCircle()` / `drawCircle()` | 填充/描边圆形 | | **线条** | `drawLine()` | 绘制线段 | | **三角形** | `fillTriangle()` / `drawTriangle()` | 填充/描边三角形 | | **多边形** | `fillPolygon()` / `drawPolygon()` | 填充/描边多边形 | | **精灵** | `drawSprite()` | 绘制纹理精灵 | | **文字** | `drawText()` | 渲染文字 | | **变换** | `pushTransform()` / `popTransform()` | 矩阵变换栈 | | **视口** | `setViewport()` | 设置渲染区域 | | **混合** | `setBlendMode()` | 设置混合模式 | **渲染管线:** ``` ┌──────────────┐ ┌────────────────────────────────────────────────┐ │ drawRect() │────►│ │ └──────────────┘ │ 形状批处理缓冲区 │ ┌──────────────┐ │ shapeVertexCache_[MAX_SHAPE_VERTICES] │ │ fillCircle() │────►│ │ └──────────────┘ │ 顶点格式: {x, y, r, g, b, a} │ ┌──────────────┐ │ │ │fillTriangle()│────►│ 当缓冲区满或模式改变时: flushShapeBatch() │ └──────────────┘ │ │ └────────────────────┬───────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────┐ │ 线条批处理缓冲区 │ │ lineVertexCache_[MAX_LINE_VERTICES] │ │ │ │ 绘制模式: GL_LINES (每线条2顶点) │ │ 支持线宽设置 │ └────────────────────┬───────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────┐ │ 精灵批处理系统 │ │ GLSpriteBatch (10000精灵) │ │ │ │ 图集纹理 → 顶点数据 → VBO → GPU 批量绘制 │ │ │ │ beginSpriteBatch() → drawSprite() → endBatch()│ └────────────────────┬───────────────────────────┘ │ ▼ ┌────────────────────────────────────────────────┐ │ OpenGL 渲染 │ │ │ │ glDrawArrays(GL_TRIANGLES, ...) │ │ glDrawArrays(GL_LINES, ...) │ └────────────────────────────────────────────────┘ ``` ### 2.3 着色器系统 (ShaderManager) ``` ┌─────────────────────────────────────────────────────────────────┐ │ ShaderManager 单例 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌────────────────────────────────────┐ │ │ │ IShader │◄───┤ GLShader (OpenGL实现) │ │ │ │ 接口 │ │ - 编译 vertex/fragment shader │ │ │ │ │ │ - 创建 program │ │ │ │ bind() │ │ - 设置 uniform │ │ │ │ setUniform() │ │ - 绑定/解绑 │ │ │ └──────────────┘ └────────────────────────────────────┘ │ │ ▲ │ │ │ │ │ ┌──────────────┐ ┌────────────────────────────────────┐ │ │ │ IShaderFactory│◄──┤ GLShaderFactory │ │ │ │ 工厂接口 │ │ - createShader() │ │ │ │ │ │ - 创建 OpenGL Shader 实例 │ │ │ └──────────────┘ └────────────────────────────────────┘ │ │ │ │ 管理: unordered_map shaders_ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` **内置着色器:** | 着色器 | 文件 | 用途 | |-------|------|------| | **sprite** | sprite.vert / sprite.frag | 纹理精灵渲染 (支持颜色混合) | | **shape** | shape.vert / shape.frag | 2D形状渲染 (顶点颜色) | ### 2.4 字体渲染 (GLFontAtlas) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 字体图集系统 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 初始化流程: │ │ ┌───────────┐ ┌───────────┐ ┌──────────────────────┐ │ │ │ 加载字体 │───►│ 初始化stb │───►│ 创建 1024x1024 图集 │ │ │ │ 文件(.ttf)│ │ _truetype │ │ 纹理 (RGBA) │ │ │ └───────────┘ └───────────┘ └──────────────────────┘ │ │ │ │ │ 渲染字符时: │ │ │ ┌───────────┐ ┌───────────┐ ┌────────▼──────────┐ │ │ │ 字符查缓存 │───►│ 缓存未命中 │───►│ stbtt_MakeCodepoint│ │ │ │ │ │ │ │ _Bitmap() 栅格化 │ │ │ └─────┬─────┘ └───────────┘ └────────┬──────────┘ │ │ │ │ │ │ │ ┌───────────┐ ┌─────────▼──────────┐ │ │ └────────►│ 返回字形 │◄───│ stb_rect_pack 打包 │ │ │ │ 信息 │ │ 到图集纹理 │ │ │ └───────────┘ └────────────────────┘ │ │ │ │ Glyph 信息: │ │ - 尺寸 (width, height) │ │ - 偏移 (bearingX, bearingY) │ │ - 步进 (advance) │ │ - 纹理坐标 (u0, v0, u1, v1) │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 2.5 相机系统 (Camera) ``` ┌─────────────────────────────────────────┐ │ Camera 相机 │ ├─────────────────────────────────────────┤ │ │ │ 视口配置: │ │ ┌─────────────────────────────────┐ │ │ │ left = 0 │ │ │ │ right = 800 ─────────────── │ │ │ │ top = 0 │ │ │ │ │ │ bottom = 600 │ 世界坐标 │ │ │ │ │ │ │ │ │ │ │ 默认位置(0,0) │ │ │ │ │ │ 看向左上角 └─────────────┘ │ │ │ │ 视口 (0,0) │ │ │ └─────────────────────────────────┘ │ │ │ │ 变换矩阵: │ │ ┌───────────────┐ │ │ │ viewMatrix │ 视图矩阵 (相机位置) │ │ ├───────────────┤ │ │ │ projMatrix │ 正交投影矩阵 │ │ ├───────────────┤ │ │ │ viewProj │ view * projection │ │ └───────────────┘ │ │ │ │ 控制: │ │ - move(x, y) 移动相机 │ │ - setZoom(z) 设置缩放 │ │ - setPosition() 设置位置 │ │ │ └─────────────────────────────────────────┘ ``` ### 2.6 模块系统 (Module) ``` ┌─────────────────────────────────────────┐ │ Module 模块基类 │ ├─────────────────────────────────────────┤ │ + setupModule() 初始化 │ │ + destroyModule() 销毁 │ │ + onUpdate() 每帧更新 │ │ + beforeRender() 渲染前 │ │ + onRender() 渲染时 │ │ + afterRender() 渲染后 │ │ + handleEvent() 事件处理 │ │ + getName() 模块名称 │ │ + getPriority() 优先级 (越小越优先) │ └─────────────────────────────────────────┘ ▲ │ 继承 ┌──────────────┼──────────────┐ │ │ │ ┌───┴───┐ ┌─────┴─────┐ ┌────┴────┐ │渲染模块│ │ 物理模块 │ │音频模块 │ │ │ │ │ │ │ └───────┘ └───────────┘ └─────────┘ ``` ## 3. 数据流图 ### 3.1 一帧的渲染流程 ``` ┌──────────────────────────────────────────────────────────────────────┐ │ 游戏主循环 │ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ① 处理输入事件 │ │ SDL_PollEvent() → 键盘/鼠标事件 → 更新相机/游戏逻辑 │ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ② 开始新帧 (beginFrame) │ │ glClear() 清除颜色缓冲区 + 重置渲染统计 │ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ③ 设置渲染状态 │ │ setViewport() + setViewProjection(camera.getViewProjectionMatrix)│ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ④ 绘制各种图形 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ fillRect() │ │fillCircle() │ │ drawLine() │ │drawSprite() │ │ │ │ │ │ │ │ │ │ │ │ │ │ 顶点数据 ──►│ │ 顶点数据 ──►│ │ 顶点数据 ──►│ │ 精灵数据 ──►│ │ │ │ 形状缓冲区 │ │ 形状缓冲区 │ │ 线条缓冲区 │ │ 精灵批次 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ⑤ 结束帧 (endFrame) │ │ flushShapeBatch() + flushLineBatch() + endSpriteBatch() │ │ 提交所有待渲染数据到 GPU │ └─────────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ ⑥ 交换缓冲区 │ │ SDL_GL_SwapWindow() 将渲染结果显示到屏幕 │ └──────────────────────────────────────────────────────────────────────┘ ``` ### 3.2 资源加载流程 ``` 纹理加载: ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 文件路径 │───►│ stb_image│───►│ 像素数据 │───►│ GLTexture │ │ .png/.jpg│ │ 解码 │ │ RGBA │ │ glTexImage2D └──────────┘ └──────────┘ └──────────┘ └──────────┘ 字体加载: ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ .ttf文件 │───►│读取到内存│───►│stbtt_Init│───►│GLFontAtlas│ │ │ │ │ │Font() │ │ 创建图集 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ 着色器加载: ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │.vert文件 │───►│读取源码 │───►│glCompile │───►│glLink │ │.frag文件 │───►│ │ │Shader() │ │Program │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ``` ## 4. 项目目录结构 ``` Frostbite2D/ ├── xmake.lua # 主构建配置 ├── platform/ │ └── windows.lua # Windows 平台配置 ├── shaders/ │ ├── shape.vert # 形状着色器 - 顶点 │ ├── shape.frag # 形状着色器 - 片段 │ ├── sprite.vert # 精灵着色器 - 顶点 │ └── sprite.frag # 精灵着色器 - 片段 └── Fostbite2D/ ├── include/ │ ├── fostbite2D/ │ │ ├── app/ │ │ │ └── application.h # 应用主类 │ │ ├── config/ │ │ │ ├── app_config.h # 应用配置 │ │ │ └── platform_config.h # 平台配置 │ │ ├── core/ │ │ │ ├── color.h # 颜色类 │ │ │ ├── math_types.h # 数学类型 │ │ │ └── types.h # 基础类型定义 │ │ ├── module/ │ │ │ └── module.h # 模块基类 │ │ ├── platform/ │ │ │ └── window.h # 窗口类 │ │ └── render/ │ │ ├── camera.h # 相机 │ │ ├── font.h # 字体接口 │ │ ├── texture.h # 纹理接口 │ │ ├── opengl/ │ │ │ ├── gl_font_atlas.h # OpenGL字体图集 │ │ │ ├── gl_renderer.h # OpenGL渲染器 │ │ │ ├── gl_shader.h # OpenGL着色器 │ │ │ ├── gl_sprite_batch.h # 精灵批处理 │ │ │ └── gl_texture.h # OpenGL纹理 │ │ └── shader/ │ │ ├── shader_interface.h # 着色器接口 │ │ └── shader_manager.h # 着色器管理器 │ ├── glad/ │ │ └── glad.h # OpenGL 加载器 │ ├── KHR/ │ │ └── khrplatform.h # Khronos 平台定义 │ └── stb/ │ ├── stb_image.h # 图片加载 │ ├── stb_rect_pack.h # 矩形打包 │ └── stb_truetype.h # 字体渲染 └── src/ ├── main.cpp # 程序入口 ├── glad/ │ └── glad.c # GLAD 实现 └── fostbite2D/ ├── app/ │ └── application.cpp # Application 实现 ├── config/ │ └── app_config.cpp # 配置实现 ├── platform/ │ └── window.cpp # Window 实现 └── render/ ├── camera.cpp # Camera 实现 ├── texture.cpp # Texture 实现 ├── opengl/ # OpenGL 实现 └── shader/ # Shader 实现 ``` ## 5. 核心类关系图 ``` ┌─────────────────┐ │ Application │ │ 单例 │ └────────┬────────┘ │ ┌───────────────────────────┼───────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Window │◄───────►│ ShaderManager │◄───────►│ GLRenderer │ │ (SDL2) │ │ 单例 │ │ │ └─────────────────┘ └────────┬────────┘ └───────┬─────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ IShader │ │ GLSpriteBatch │ │ 接口 │ │ 精灵批处理 │ └────────┬────────┘ └───────┬─────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ GLShader │ │ GLTexture │ │ OpenGL实现 │ │ 纹理管理 │ └─────────────────┘ └─────────────────┘ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Camera │◄───────►│ GLFontAtlas │◄───────►│ FontAtlas │ │ 2D相机 │ │ 字体图集 │ │ 接口 │ │ view/proj矩阵 │ │ stb_truetype │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ## 6. 关键技术点 ### 6.1 批处理渲染 (Batch Rendering) - **形状批处理**: 8192 个顶点缓冲区,减少 draw call - **线条批处理**: 16384 个顶点,支持线宽变化时 flush - **精灵批处理**: 10000 个精灵,使用单一 draw call ### 6.2 字体图集 (Font Atlas) - 使用 `stb_rect_pack` 进行矩形打包 - 1024x1024 RGBA 纹理存储字形 - 动态缓存:首次使用字符时渲染到图集 ### 6.3 坐标系 - **世界坐标**: Y轴向下 (0,0) 在左上角 - **纹理坐标**: OpenGL 标准,(0,0) 在左下角 - **相机**: 正交投影,可移动/缩放 ### 6.4 渲染状态管理 - 自动处理 OpenGL 状态缓存 - 混合模式切换 (None/Alpha/Additive/Multiply) - 变换矩阵栈支持嵌套变换 ## 7. 使用示例 ```cpp // 1. 初始化 AppConfig config = AppConfig::createDefault(); config.windowConfig.title = "My Game"; Application::get().init(config); // 2. 初始化渲染 GLRenderer renderer; renderer.init(sdlWindow); // 3. 加载字体 GLFontAtlas font("C:/Windows/Fonts/arial.ttf", 24); // 4. 游戏循环 while (running) { // 处理事件... // 开始渲染 renderer.beginFrame(Color(0.1f, 0.1f, 0.15f, 1.0f)); renderer.setViewProjection(camera.getViewProjectionMatrix()); // 绘制图形 renderer.fillRect(Rect(100, 100, 200, 150), Colors::Red); renderer.fillCircle(Vec2(400, 300), 50.0f, Colors::Blue, 32); renderer.drawLine(Vec2(0, 0), Vec2(800, 600), Colors::White, 2.0f); // 绘制文字 renderer.beginSpriteBatch(); renderer.drawText(font, "Hello World!", 100, 100, Colors::White); renderer.endSpriteBatch(); // 结束渲染 renderer.endFrame(); SDL_GL_SwapWindow(sdlWindow); } // 5. 清理 renderer.shutdown(); Application::get().shutdown(); ```