将CMakeLists分成主CMakeLists和分游戏CMakeLists;README里补了单独构建Tom/Demo和资源转换的命令;把残留的Gfx文案改成Core。
This commit is contained in:
parent
964a11a215
commit
b82339b185
118
CMakeLists.txt
118
CMakeLists.txt
|
|
@ -17,12 +17,28 @@ set(CORE_SOURCES
|
||||||
src/Core/Core/FrameBuffer.cpp
|
src/Core/Core/FrameBuffer.cpp
|
||||||
src/Core/Core/Renderer.cpp
|
src/Core/Core/Renderer.cpp
|
||||||
src/Core/Draw2D/DrawContext.cpp
|
src/Core/Draw2D/DrawContext.cpp
|
||||||
|
src/Core/Platform/AlsaAudioInput.cpp
|
||||||
|
src/Core/Platform/AlsaAudioOutput.cpp
|
||||||
|
src/Core/Platform/EvdevButtonInput.cpp
|
||||||
src/Core/Rasterizer/Rasterizer.cpp
|
src/Core/Rasterizer/Rasterizer.cpp
|
||||||
src/Core/Rasterizer/TriangleRasterizer.cpp
|
src/Core/Rasterizer/TriangleRasterizer.cpp
|
||||||
src/Core/Scene/Camera.cpp
|
src/Core/Scene/Camera.cpp
|
||||||
src/Core/Shading/BlinnPhongShader.cpp
|
src/Core/Shading/BlinnPhongShader.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(USE_FRAMEBUFFER)
|
||||||
|
list(APPEND CORE_SOURCES
|
||||||
|
src/Core/Platform/FBDisplay.cpp
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
list(APPEND CORE_SOURCES
|
||||||
|
src/Core/Platform/SDLDisplay.cpp
|
||||||
|
src/Core/Platform/SdlAudioInput.cpp
|
||||||
|
src/Core/Platform/SdlAudioOutput.cpp
|
||||||
|
src/Core/Platform/SdlKeyboardButtonInput.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CORE_INCLUDE_DIRS
|
set(CORE_INCLUDE_DIRS
|
||||||
src/Core/Platform
|
src/Core/Platform
|
||||||
src/Core/Asset
|
src/Core/Asset
|
||||||
|
|
@ -37,22 +53,11 @@ set(CORE_INCLUDE_DIRS
|
||||||
assets/sprite
|
assets/sprite
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
add_library(imx6u_core STATIC ${CORE_SOURCES})
|
||||||
src/Apps/Game/Main.cpp
|
target_include_directories(imx6u_core PUBLIC ${CORE_INCLUDE_DIRS})
|
||||||
${CORE_SOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(USE_FRAMEBUFFER)
|
if(USE_FRAMEBUFFER)
|
||||||
list(APPEND SOURCES src/Core/Platform/FBDisplay.cpp)
|
target_compile_definitions(imx6u_core PUBLIC USE_FRAMEBUFFER)
|
||||||
else()
|
|
||||||
list(APPEND SOURCES src/Core/Platform/SDLDisplay.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(IMX6U-Game ${SOURCES})
|
|
||||||
target_include_directories(IMX6U-Game PRIVATE ${CORE_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
if(USE_FRAMEBUFFER)
|
|
||||||
target_compile_definitions(IMX6U-Game PRIVATE USE_FRAMEBUFFER)
|
|
||||||
else()
|
else()
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
|
@ -67,76 +72,47 @@ else()
|
||||||
set(SDL2_IMAGE_DLL "${CMAKE_CURRENT_SOURCE_DIR}/libs/Win/SDL_image/lib/x86/SDL2_image.dll")
|
set(SDL2_IMAGE_DLL "${CMAKE_CURRENT_SOURCE_DIR}/libs/Win/SDL_image/lib/x86/SDL2_image.dll")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(IMX6U-Game PRIVATE libs/Win/SDL2/include)
|
target_include_directories(imx6u_core PUBLIC libs/Win/SDL2/include)
|
||||||
target_link_directories(IMX6U-Game PRIVATE ${SDL2_LIB_DIR})
|
target_link_directories(imx6u_core PUBLIC ${SDL2_LIB_DIR})
|
||||||
target_link_libraries(IMX6U-Game PRIVATE SDL2main SDL2)
|
target_link_libraries(imx6u_core PUBLIC SDL2main SDL2)
|
||||||
|
|
||||||
add_custom_command(TARGET IMX6U-Game POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
"${SDL2_DLL}"
|
|
||||||
"$<TARGET_FILE_DIR:IMX6U-Game>"
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
find_package(SDL2_image QUIET)
|
find_package(SDL2_image QUIET)
|
||||||
target_link_libraries(IMX6U-Game PRIVATE SDL2::SDL2)
|
target_link_libraries(imx6u_core PUBLIC SDL2::SDL2)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
find_package(ALSA QUIET)
|
||||||
|
if(ALSA_FOUND)
|
||||||
|
target_compile_definitions(imx6u_core PUBLIC PLATFORM_HAS_ALSA)
|
||||||
|
target_include_directories(imx6u_core PUBLIC ${ALSA_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(imx6u_core PUBLIC ${ALSA_LIBRARIES})
|
||||||
|
else()
|
||||||
|
message(STATUS "ALSA was not found; AlsaAudioInput and AlsaAudioOutput will be unavailable backends")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(IMX6U-Game PRIVATE /utf-8 /W3)
|
target_compile_options(imx6u_core PRIVATE /utf-8 /W3)
|
||||||
set_property(TARGET IMX6U-Game PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT USE_FRAMEBUFFER)
|
function(imx6u_configure_app_target target_name)
|
||||||
set(SPRITE_ASSET_TOOL_SOURCES
|
target_link_libraries(${target_name} PRIVATE imx6u_core)
|
||||||
src/Apps/Game/tools/asset_pipeline/SpriteAssetTool.cpp
|
|
||||||
src/Core/Asset/SpriteAssetLoader.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32 AND NOT USE_FRAMEBUFFER)
|
||||||
add_executable(SpriteAssetTool ${SPRITE_ASSET_TOOL_SOURCES})
|
add_custom_command(TARGET ${target_name} POST_BUILD
|
||||||
target_include_directories(SpriteAssetTool PRIVATE
|
|
||||||
src/Core/Asset
|
|
||||||
src/Core/RenderData
|
|
||||||
libs/Win/SDL2/include
|
|
||||||
libs/Win/SDL_image/include
|
|
||||||
)
|
|
||||||
target_link_directories(SpriteAssetTool PRIVATE ${SDL2_LIB_DIR} ${SDL2_IMAGE_LIB_DIR})
|
|
||||||
target_link_libraries(SpriteAssetTool PRIVATE SDL2main SDL2 SDL2_image)
|
|
||||||
|
|
||||||
add_custom_command(TARGET SpriteAssetTool POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
"${SDL2_DLL}"
|
"${SDL2_DLL}"
|
||||||
"$<TARGET_FILE_DIR:SpriteAssetTool>"
|
"$<TARGET_FILE_DIR:${target_name}>"
|
||||||
)
|
)
|
||||||
add_custom_command(TARGET SpriteAssetTool POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
"${SDL2_IMAGE_DLL}"
|
|
||||||
"$<TARGET_FILE_DIR:SpriteAssetTool>"
|
|
||||||
)
|
|
||||||
elseif(SDL2_image_FOUND)
|
|
||||||
add_executable(SpriteAssetTool ${SPRITE_ASSET_TOOL_SOURCES})
|
|
||||||
target_include_directories(SpriteAssetTool PRIVATE
|
|
||||||
src/Core/Asset
|
|
||||||
src/Core/RenderData
|
|
||||||
)
|
|
||||||
target_link_libraries(SpriteAssetTool PRIVATE SDL2::SDL2 SDL2_image::SDL2_image)
|
|
||||||
else()
|
|
||||||
message(STATUS "SpriteAssetTool disabled: SDL2_image was not found")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET SpriteAssetTool)
|
if(MSVC)
|
||||||
add_custom_target(ConvertTomSprites
|
target_compile_options(${target_name} PRIVATE /utf-8 /W3)
|
||||||
COMMAND $<TARGET_FILE:SpriteAssetTool>
|
set_property(TARGET ${target_name} PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||||
--batch
|
|
||||||
"src/Apps/Game/assets/raw"
|
|
||||||
"src/Apps/Game/assets/sprites"
|
|
||||||
--preset tom-800x480
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
DEPENDS SpriteAssetTool
|
|
||||||
COMMENT "Converting PNG assets to board-ready .sprite files"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endfunction()
|
||||||
|
|
||||||
|
add_subdirectory(src/Apps/Game)
|
||||||
|
add_subdirectory(src/Apps/Demo)
|
||||||
|
|
|
||||||
28
README.md
28
README.md
|
|
@ -61,6 +61,17 @@ cmake -B build-win .
|
||||||
cmake --build build-win --config Release
|
cmake --build build-win --config Release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
只构建某个 App:
|
||||||
|
```bash
|
||||||
|
cmake --build build-win --config Release --target IMX6U-Game
|
||||||
|
cmake --build build-win --config Release --target IMX6U-Demo
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 Tom 的 `.sprite` 资源缺失,先运行资源转换目标:
|
||||||
|
```bash
|
||||||
|
cmake --build build-win --config Release --target ConvertTomSprites
|
||||||
|
```
|
||||||
|
|
||||||
运行:
|
运行:
|
||||||
```bash
|
```bash
|
||||||
./build-win/Release/IMX6U-Game.exe
|
./build-win/Release/IMX6U-Game.exe
|
||||||
|
|
@ -80,7 +91,7 @@ cmake --build build-win --config Release
|
||||||
需要系统 SDL2:
|
需要系统 SDL2:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install libsdl2-dev cmake g++
|
sudo apt-get install libsdl2-dev libsdl2-image-dev cmake g++
|
||||||
```
|
```
|
||||||
|
|
||||||
构建:
|
构建:
|
||||||
|
|
@ -89,6 +100,17 @@ cmake -B build-linux .
|
||||||
cmake --build build-linux
|
cmake --build build-linux
|
||||||
```
|
```
|
||||||
|
|
||||||
|
只构建某个 App:
|
||||||
|
```bash
|
||||||
|
cmake --build build-linux --target IMX6U-Game
|
||||||
|
cmake --build build-linux --target IMX6U-Demo
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 Tom 的 `.sprite` 资源缺失,先运行资源转换目标:
|
||||||
|
```bash
|
||||||
|
cmake --build build-linux --target ConvertTomSprites
|
||||||
|
```
|
||||||
|
|
||||||
运行:
|
运行:
|
||||||
```bash
|
```bash
|
||||||
./build-linux/IMX6U-Game
|
./build-linux/IMX6U-Game
|
||||||
|
|
@ -301,8 +323,8 @@ IMX6U-Game/
|
||||||
- 双平台显示后端(SDL2 / Framebuffer)
|
- 双平台显示后端(SDL2 / Framebuffer)
|
||||||
- 离线资源转换工具:PNG sprite -> C++ 头文件,像素字体 -> bitmap atlas/header
|
- 离线资源转换工具:PNG sprite -> C++ 头文件,像素字体 -> bitmap atlas/header
|
||||||
- 基础 2D sprite、SpriteRegion、bitmap font 文本绘制和 tilemap 视口绘制,当前 demo 显示 FPS 文本、测试 sprite 和小型滚动 tilemap
|
- 基础 2D sprite、SpriteRegion、bitmap font 文本绘制和 tilemap 视口绘制,当前 demo 显示 FPS 文本、测试 sprite 和小型滚动 tilemap
|
||||||
- Gfx 目录规范化,代码收敛到 `src/Gfx/`
|
- Core 目录规范化,代码收敛到 `src/Core/`
|
||||||
- `Gfx::DrawContext` 统一绘制入口,封装现有绘制能力
|
- `Core::DrawContext` 统一绘制入口,封装现有绘制能力
|
||||||
- C++11 兼容代码
|
- C++11 兼容代码
|
||||||
- CMake 跨平台构建
|
- CMake 跨平台构建
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
# 应用层与图形库分层设计
|
|
||||||
|
|
||||||
本项目后续包含三个应用层目标:两个游戏和一个启动器;同时还需要沉淀一套可复用的 IMX6U 轻量图形库。为了避免后期耦合和性能返工,必须明确区分“应用层”和“底层库”。
|
|
||||||
|
|
||||||
## 1. 推荐总体结构
|
|
||||||
|
|
||||||
推荐拆成四个逻辑层:
|
|
||||||
|
|
||||||
```text
|
|
||||||
IMX6U-Game/
|
|
||||||
├─ src/
|
|
||||||
│ ├─ Gfx/ # 底层图形库:可复用、无具体游戏规则
|
|
||||||
│ │ ├─ Draw2D/ # DrawContext 统一绘制入口(✅ 已实现)
|
|
||||||
│ │ ├─ Core/ # FrameBuffer、DepthBuffer(✅ 已实现)
|
|
||||||
│ │ ├─ Math/ # 向量、矩阵、数学工具(✅ 已实现)
|
|
||||||
│ │ ├─ Rasterizer/ # 线段、三角形光栅化(✅ 已实现)
|
|
||||||
│ │ ├─ RenderData/ # Color、Triangle 等数据结构(✅ 已实现)
|
|
||||||
│ │ ├─ Scene/ # Camera、Transform(✅ 已实现)
|
|
||||||
│ │ ├─ Shading/ # 着色器(预留)
|
|
||||||
│ │ ├─ Platform/ # SDL2 / fb0 显示适配与独立时间源(✅ 已实现)
|
|
||||||
│ │ └─ Asset/ # 资源加载(✅ 已实现)
|
|
||||||
│ ├─ Apps/
|
|
||||||
│ │ ├─ Demo/ # 当前板端性能 demo;历史上也用于 3D 立方体验证(✅ 已实现)
|
|
||||||
│ │ ├─ Launcher/ # 启动器应用(待实现)
|
|
||||||
│ │ ├─ GameA/ # 第一个游戏(待实现)
|
|
||||||
│ │ └─ GameB/ # 第二个游戏(待实现)
|
|
||||||
│ └─ Shared/ # 可选:应用层共享但不属于 Gfx 的东西
|
|
||||||
│ ├─ Save/ # 存档格式、配置读写
|
|
||||||
│ ├─ UI/ # 启动器和游戏共用 UI 组件
|
|
||||||
│ └─ Assets/ # 应用层资源索引、资源命名约定
|
|
||||||
├─ assets/
|
|
||||||
│ ├─ font/ # 共享像素字体源文件与生成的 font_atlas
|
|
||||||
│ ├─ sprite/ # 当前 demo/test sprite 源文件与生成头文件
|
|
||||||
│ ├─ launcher/
|
|
||||||
│ ├─ game_a/
|
|
||||||
│ ├─ game_b/
|
|
||||||
│ └─ shared/
|
|
||||||
├─ tools/
|
|
||||||
│ ├─ gen_font_atlas.py # TTF -> bitmap font atlas/header
|
|
||||||
│ └─ png_to_header.py # PNG -> uint32_t RGBA header
|
|
||||||
└─ docs/
|
|
||||||
```
|
|
||||||
|
|
||||||
~~当前项目已有 `Core/Math/Platform/Rasterizer/RenderData/Scene` 等目录,短期不必一次性搬迁;但新增代码应按上面的边界收敛。等功能稳定后,再把现有底层代码整体移动到 `src/Gfx/`。~~
|
|
||||||
|
|
||||||
**已完成**:底层代码已整体迁移到 `src/Gfx/`,包括 Core、Math、Rasterizer、RenderData、Scene、Shading、Platform、Asset 和新增的 Draw2D。Demo 入口位于 `src/Apps/Demo/`。
|
|
||||||
|
|
||||||
## 2. 四个层级的职责
|
|
||||||
|
|
||||||
### 2.1 Gfx:底层图形库
|
|
||||||
|
|
||||||
职责:
|
|
||||||
|
|
||||||
- 管理 framebuffer、depthbuffer、渲染上下文。
|
|
||||||
- 提供基础绘制接口:点、线、矩形、四边形、三角形、sprite、SpriteRegion、tilemap、简单文本等。
|
|
||||||
- 提供颜色、矩形、定点数、纹理、裁剪区域等基础数据结构。
|
|
||||||
- 封装 SDL2 / framebuffer 显示提交、输入轮询,并通过独立 `ITimeSource` 提供单调整数毫秒时间。
|
|
||||||
- 使用离线转换后的紧凑资源数据(例如 PNG 转头文件、bitmap font atlas),运行时不直接依赖 PNG/TTF 解码。
|
|
||||||
- 只关心“怎么画得快、怎么提交到屏幕”,不关心具体游戏规则。
|
|
||||||
|
|
||||||
禁止:
|
|
||||||
|
|
||||||
- 不依赖 `GameA`、`GameB`、`Launcher`。
|
|
||||||
- 不包含具体关卡、角色、菜单流程、游戏状态机。
|
|
||||||
- 不直接读取某个游戏专属资源路径。
|
|
||||||
- 不在核心绘制接口中暴露 SDL2 类型。
|
|
||||||
- 不在每帧热路径中执行图片/字体解码;资源转换应在构建前或工具阶段完成。
|
|
||||||
|
|
||||||
### 2.2 Apps/GameA 与 Apps/GameB:两个游戏
|
|
||||||
|
|
||||||
职责:
|
|
||||||
|
|
||||||
- 各自维护自己的游戏规则、状态机、关卡、实体、碰撞、计分、胜负逻辑。
|
|
||||||
- 通过 Gfx 提供的接口绘制画面。
|
|
||||||
- 通过平台输入快照读取按键/触摸状态,而不是直接调用 SDL。
|
|
||||||
- 管理自己的资源索引和场景切换。
|
|
||||||
|
|
||||||
禁止:
|
|
||||||
|
|
||||||
- 游戏之间互相 include 对方代码。
|
|
||||||
- 游戏直接操作 SDL renderer / texture / window。
|
|
||||||
- 游戏直接依赖 framebuffer 内存布局,除非是明确标注的性能特例。
|
|
||||||
|
|
||||||
### 2.3 Apps/Launcher:启动器
|
|
||||||
|
|
||||||
职责:
|
|
||||||
|
|
||||||
- 展示游戏列表、图标、说明、版本信息。
|
|
||||||
- 选择并启动 GameA 或 GameB。
|
|
||||||
- 管理全局设置,例如音量、亮度、输入校准、语言等。
|
|
||||||
- 可以复用 Shared/UI,但不承载具体游戏逻辑。
|
|
||||||
|
|
||||||
启动方式有两种可选方案:
|
|
||||||
|
|
||||||
1. **单进程多应用模式**:Launcher、GameA、GameB 编译成一个可执行文件,内部切换当前 App。
|
|
||||||
2. **多进程模式**:Launcher 是独立程序,选择后启动另一个游戏可执行文件。
|
|
||||||
|
|
||||||
对 IMX6U 初期开发,推荐先用 **单进程多应用模式**,原因:
|
|
||||||
|
|
||||||
- 构建、部署、调试更简单。
|
|
||||||
- SDL2 初始化、资源缓存、输入状态可以共用。
|
|
||||||
- 避免频繁退出/启动进程带来的黑屏、资源重载和状态恢复问题。
|
|
||||||
|
|
||||||
等项目成熟后,如果每个游戏体积较大,或者需要独立更新,再考虑多进程拆分。
|
|
||||||
|
|
||||||
### 2.4 Shared:应用层共享模块
|
|
||||||
|
|
||||||
Shared 只放“应用层共享,但不属于底层图形库”的内容,例如:
|
|
||||||
|
|
||||||
- UI 控件:按钮、列表、九宫格面板、菜单焦点管理。
|
|
||||||
- 存档/设置:配置文件、最高分、解锁状态。
|
|
||||||
- 资源清单:多个应用共用的字体、图标、音效索引。
|
|
||||||
|
|
||||||
Shared 可以依赖 Gfx;Gfx 不能依赖 Shared。
|
|
||||||
|
|
||||||
## 3. 依赖方向
|
|
||||||
|
|
||||||
必须保持单向依赖:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Apps/GameA ─┐
|
|
||||||
Apps/GameB ─┼─> Shared ─> Gfx ─> Platform(SDL2/fb0/ITimeSource)
|
|
||||||
Launcher ─┘
|
|
||||||
|
|
||||||
Apps/GameA ─┐
|
|
||||||
Apps/GameB ─┼──────────> Gfx
|
|
||||||
Launcher ─┘
|
|
||||||
```
|
|
||||||
|
|
||||||
禁止反向依赖:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Gfx -> Apps 禁止
|
|
||||||
Gfx -> Shared 禁止
|
|
||||||
GameA -> GameB 禁止
|
|
||||||
GameB -> GameA 禁止
|
|
||||||
Platform -> Game 禁止
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. 应用统一接口
|
|
||||||
|
|
||||||
推荐为 Launcher、GameA、GameB 提供统一应用接口,例如:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class IApp
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IApp() {}
|
|
||||||
virtual void on_enter() = 0;
|
|
||||||
virtual void on_exit() = 0;
|
|
||||||
virtual void update(uint32_t fixed_delta_ms) = 0;
|
|
||||||
virtual void render(Gfx::DrawContext& ctx) = 0;
|
|
||||||
virtual AppId next_app() const = 0;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
主循环只认识 `IApp`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
poll input -> update current app -> render current app -> present framebuffer
|
|
||||||
```
|
|
||||||
|
|
||||||
这样三个应用层共用同一个主循环、同一套 SDL2 初始化、framebuffer 提交流程和独立时间源。
|
|
||||||
|
|
||||||
注意:接口可以先保留虚函数,因为它只在每帧应用级调用,不在像素/顶点热路径中调用。像 `draw_rect`、`draw_quad`、`set_pixel_fast` 这类热路径函数不要虚化。
|
|
||||||
|
|
||||||
## 5. 底层图形库优先提供的 API
|
|
||||||
|
|
||||||
Gfx 初期建议先做 2D 基础能力,不要一开始就做复杂引擎:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
namespace Gfx
|
|
||||||
{
|
|
||||||
struct RectI { int32_t x, y, w, h; };
|
|
||||||
struct PointI { int32_t x, y; };
|
|
||||||
struct Color32 { uint32_t rgba; };
|
|
||||||
|
|
||||||
class DrawContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void clear(Color32 color);
|
|
||||||
void draw_pixel(int32_t x, int32_t y, Color32 color);
|
|
||||||
void draw_line(PointI a, PointI b, Color32 color);
|
|
||||||
void draw_rect(RectI rect, Color32 color);
|
|
||||||
void fill_rect(RectI rect, Color32 color);
|
|
||||||
void draw_quad(PointI p0, PointI p1, PointI p2, PointI p3, Color32 color);
|
|
||||||
void fill_quad(PointI p0, PointI p1, PointI p2, PointI p3, Color32 color);
|
|
||||||
void draw_sprite(int32_t x, int32_t y, const RenderData::Image& image);
|
|
||||||
void draw_sprite_region(int32_t x, int32_t y,
|
|
||||||
const RenderData::SpriteRegion& region);
|
|
||||||
void draw_text(const RenderData::BitmapFont& font, int32_t x, int32_t y,
|
|
||||||
RenderData::Color color, const char* text);
|
|
||||||
void draw_tilemap(const RenderData::Tilemap& tilemap,
|
|
||||||
int32_t screen_x, int32_t screen_y,
|
|
||||||
int32_t viewport_w, int32_t viewport_h,
|
|
||||||
int32_t camera_x, int32_t camera_y);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
后续再扩展:
|
|
||||||
|
|
||||||
- `set_clip_rect`
|
|
||||||
- `set_camera_2d`
|
|
||||||
- `batch sprite/tile`
|
|
||||||
|
|
||||||
## 6. 命名建议
|
|
||||||
|
|
||||||
为了避免“项目名、库名、游戏名”混乱,建议:
|
|
||||||
|
|
||||||
- 项目仓库仍叫 `IMX6U-Game`。
|
|
||||||
- 底层图形库命名为 `Gfx` 或 `MiniGfx`。
|
|
||||||
- 三个应用用明确名字:`Launcher`、`GameA`、`GameB`,后续再替换成真实游戏名。
|
|
||||||
- CMake target 可以是:
|
|
||||||
- `imx6u_gfx` 静态库
|
|
||||||
- `imx6u_launcher`
|
|
||||||
- `imx6u_game_a`
|
|
||||||
- `imx6u_game_b`
|
|
||||||
- 或初期单可执行文件 `imx6u_suite`
|
|
||||||
|
|
||||||
## 7. 推荐演进顺序
|
|
||||||
|
|
||||||
1. ~~先抽出统一 `IApp` 和 `AppManager`,让当前 demo 成为一个 app。~~
|
|
||||||
2. ~~把 SDL2 初始化、输入、present 固定在平台层,应用层不直接碰 SDL。~~
|
|
||||||
3. ~~建立 `Gfx::DrawContext`,先封装 clear、pixel、line、rect、quad。~~ **已完成**(`Gfx::DrawContext` 封装了 clear、draw_line、draw_triangle、draw_sprite、draw_sprite_region、draw_text、draw_tilemap、present)
|
|
||||||
4. ~~底层代码迁移到 `src/Gfx/`,Demo 入口迁移到 `src/Apps/Demo/`。~~ **已完成**
|
|
||||||
5. 新增 Launcher app,只做最小菜单和应用切换。
|
|
||||||
6. 新增 GameA/GameB 空壳,验证三应用切换。
|
|
||||||
7. 再逐步把现有 3D demo 能力恢复为独立验证入口,或把 2D 游戏逻辑迁入对应 Game 目录。
|
|
||||||
8. 最后重构 CMake,按 `imx6u_gfx` + 应用 target 拆分。
|
|
||||||
|
|
||||||
## 8. 性能注意事项
|
|
||||||
|
|
||||||
- 应用切换不应重复销毁/创建 SDL window、renderer、texture。
|
|
||||||
- 三个应用共用 framebuffer、输入状态和 `Platform::ITimeSource` 时间源;Display 不承担计时职责。
|
|
||||||
- 每个应用可以有自己的资源缓存,但必须有上限和释放策略。
|
|
||||||
- Launcher 不应常驻消耗大量纹理/音频资源;进入游戏后可释放非必要启动器资源。
|
|
||||||
- Gfx 的绘制函数要保持小而直接,优先内联和连续内存写入。
|
|
||||||
- UI 控件层可以面向对象;像素/quad/sprite/tile 绘制层不要过度抽象。
|
|
||||||
- 无 3D 内容的 2D 应用应使用只清颜色缓冲的路径,避免每帧清理 depth buffer。
|
|
||||||
- `/dev/fb0` 后端提交可能是主要瓶颈;板端性能分析应拆分 `Frame` 和 `Present` 耗时,并确认 ARM 构建为 Release。
|
|
||||||
- 直接写 framebuffer 不是原子换屏,LCD 扫描会让局部动画看起来比完整帧率更连续;判断性能应以计时数据为准。
|
|
||||||
|
|
||||||
## 9. 资源转换约定
|
|
||||||
|
|
||||||
- 运行时资源优先使用离线转换后的简单数组,不在 IMX6U 运行时解码 PNG/TTF。
|
|
||||||
- `tools/png_to_header.py` 将 PNG 转为 `uint32_t` RGBA 数组,适用于 sprite、小图标、测试纹理等。
|
|
||||||
- `tools/gen_font_atlas.py` 将共享像素字体转为 ASCII bitmap atlas,并输出同名 PNG 预览和 C++ 头文件。
|
|
||||||
- 生成头文件、源 PNG/TTF 和转换脚本应一起纳入仓库,保证资源可追溯、可再生成。
|
|
||||||
- 生成数据目前面向简单直接的调试/小型游戏资源;后续如果资源体积增长,应再评估 1-bit/8-bit mask、RLE 或自定义资源包格式。
|
|
||||||
|
|
||||||
## 10. SpriteRegion 与 Tilemap 约定
|
|
||||||
|
|
||||||
- `RenderData::SpriteRegion` 只描述某张 atlas 中的子区域,不拥有像素数据;它通过 `const Image* atlas` 引用源图。
|
|
||||||
- `DrawContext::draw_sprite_ex` 是底层 sprite 绘制入口,负责源区域检查、目标屏幕裁剪、scale 和 flip;`draw_sprite_region` 系列只是对 atlas 子区域的语义包装。
|
|
||||||
- `RenderData::Tilemap` 使用 `uint16_t` tile id 保存地图网格,`Tilemap::EmptyTile` (`0xFFFF`) 表示空 tile。
|
|
||||||
- `Tilemap` 当前只支持一个 atlas、固定 tile 宽高和固定 `atlas_columns`;tile id 通过 `tile_id % atlas_columns` / `tile_id / atlas_columns` 映射到 atlas 中的源区域。
|
|
||||||
- `DrawContext::draw_tilemap` 的裁剪分两层:
|
|
||||||
- tilemap 层按 tile 计算需要尝试绘制的可见范围;
|
|
||||||
- sprite 层按像素裁剪每个 tile,支持 camera 像素级滚动时显示半个 tile。
|
|
||||||
- 带 `viewport_w` / `viewport_h` 的 `draw_tilemap` 重载用于子视口绘制,`screen_x` / `screen_y` 是视口左上角;旧重载默认视口延伸到 framebuffer 右下角。
|
|
||||||
- 当前实现优先保证清晰语义和可验证行为;后续性能优化可增加 tile region 查表、不透明 tile 行拷贝、chunk/dirty rect 或专用 tile 快路径。
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
add_executable(IMX6U-Demo
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
imx6u_configure_app_target(IMX6U-Demo)
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
set(TOM_GAME_TARGET IMX6U-Game)
|
||||||
|
|
||||||
|
add_executable(${TOM_GAME_TARGET}
|
||||||
|
Main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
imx6u_configure_app_target(${TOM_GAME_TARGET})
|
||||||
|
|
||||||
|
if(NOT USE_FRAMEBUFFER)
|
||||||
|
set(SPRITE_ASSET_TOOL_SOURCES
|
||||||
|
tools/asset_pipeline/SpriteAssetTool.cpp
|
||||||
|
${PROJECT_SOURCE_DIR}/src/Core/Asset/SpriteAssetLoader.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_executable(TomSpriteAssetTool ${SPRITE_ASSET_TOOL_SOURCES})
|
||||||
|
set_target_properties(TomSpriteAssetTool PROPERTIES OUTPUT_NAME SpriteAssetTool)
|
||||||
|
target_include_directories(TomSpriteAssetTool PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/src/Core/Asset
|
||||||
|
${PROJECT_SOURCE_DIR}/src/Core/RenderData
|
||||||
|
${PROJECT_SOURCE_DIR}/libs/Win/SDL2/include
|
||||||
|
${PROJECT_SOURCE_DIR}/libs/Win/SDL_image/include
|
||||||
|
)
|
||||||
|
target_link_directories(TomSpriteAssetTool PRIVATE
|
||||||
|
${SDL2_LIB_DIR}
|
||||||
|
${SDL2_IMAGE_LIB_DIR}
|
||||||
|
)
|
||||||
|
target_link_libraries(TomSpriteAssetTool PRIVATE SDL2main SDL2 SDL2_image)
|
||||||
|
|
||||||
|
add_custom_command(TARGET TomSpriteAssetTool POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${SDL2_DLL}"
|
||||||
|
"$<TARGET_FILE_DIR:TomSpriteAssetTool>"
|
||||||
|
)
|
||||||
|
add_custom_command(TARGET TomSpriteAssetTool POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${SDL2_IMAGE_DLL}"
|
||||||
|
"$<TARGET_FILE_DIR:TomSpriteAssetTool>"
|
||||||
|
)
|
||||||
|
elseif(SDL2_image_FOUND)
|
||||||
|
add_executable(TomSpriteAssetTool ${SPRITE_ASSET_TOOL_SOURCES})
|
||||||
|
set_target_properties(TomSpriteAssetTool PROPERTIES OUTPUT_NAME SpriteAssetTool)
|
||||||
|
target_include_directories(TomSpriteAssetTool PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/src/Core/Asset
|
||||||
|
${PROJECT_SOURCE_DIR}/src/Core/RenderData
|
||||||
|
${SDL2_image_INCLUDE_DIRS}
|
||||||
|
${SDL2_IMAGE_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
target_link_libraries(TomSpriteAssetTool PRIVATE SDL2::SDL2)
|
||||||
|
|
||||||
|
if(TARGET SDL2_image::SDL2_image)
|
||||||
|
target_link_libraries(TomSpriteAssetTool PRIVATE SDL2_image::SDL2_image)
|
||||||
|
else()
|
||||||
|
target_link_libraries(TomSpriteAssetTool PRIVATE
|
||||||
|
${SDL2_image_LIBRARIES}
|
||||||
|
${SDL2_IMAGE_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "SpriteAssetTool disabled: SDL2_image was not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET TomSpriteAssetTool)
|
||||||
|
add_custom_target(ConvertTomSprites
|
||||||
|
COMMAND $<TARGET_FILE:TomSpriteAssetTool>
|
||||||
|
--batch
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/assets/raw"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/assets/sprites"
|
||||||
|
--preset tom-800x480
|
||||||
|
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||||
|
DEPENDS TomSpriteAssetTool
|
||||||
|
COMMENT "Converting Tom PNG assets to board-ready .sprite files"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const int32_t ScreenWidth = 800;
|
const int32_t ScreenWidth = 1024;
|
||||||
const int32_t ScreenHeight = 480;
|
const int32_t ScreenHeight = 600;
|
||||||
|
|
||||||
struct ProgramOptions
|
struct ProgramOptions
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue