From 217467a1feefadf3abc792af6071f9ff9f42a56d Mon Sep 17 00:00:00 2001 From: hydrogendeuteride Date: Fri, 28 Nov 2025 13:25:19 +0900 Subject: [PATCH] ADD: game API docs --- docs/GameAPI.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++ docs/Scene.md | 85 +++++++++++++++++++++++- src/core/engine.h | 3 + 3 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 docs/GameAPI.md diff --git a/docs/GameAPI.md b/docs/GameAPI.md new file mode 100644 index 0000000..fa4287a --- /dev/null +++ b/docs/GameAPI.md @@ -0,0 +1,166 @@ +## Game‑Facing API Overview + +This document summarizes the main engine APIs that are directly useful when building a game (spawn actors, control lights/animations, and interact via picking). + +For details on the underlying systems, see also: + +- `docs/Scene.md` – cameras, draw context, instances, picking. +- `docs/EngineContext.md` – access to managers and per‑frame state. +- `docs/RenderGraph.md` – render‑graph API for custom passes. + +--- + +## VulkanEngine Helpers + +Header: `src/core/engine.h` + +- Lifecycle + - `void init()` – initialize SDL, device, managers, scene, render graph. + - `void run()` – main loop: handles events, updates scene, builds Render Graph, submits frames. + - `void cleanup()` – destroy managers and GPU resources. + +- GLTF spawn helper + - `bool addGLTFInstance(const std::string &instanceName, const std::string &modelRelativePath, const glm::mat4 &transform = glm::mat4(1.f));` + - Loads a glTF from `assets/models/...` (via `AssetManager`) and registers it as a runtime scene instance. + - `instanceName` becomes the logical name used by `SceneManager` (e.g. for picking and animation control). + +- Picking access + - `struct PickInfo` (nested in `VulkanEngine`) + - `MeshAsset *mesh`, `LoadedGLTF *scene`, `Node *node` + - `RenderObject::OwnerType ownerType` (e.g. `StaticGLTF`, `GLTFInstance`, `MeshInstance`) + - `std::string ownerName` + - `glm::vec3 worldPos` + - `glm::mat4 worldTransform` + - `uint32_t indexCount`, `firstIndex`, `surfaceIndex` + - `bool valid` + - `const PickInfo &get_last_pick() const` + - Returns the last click selection result. + - Filled by the engine from either CPU ray picking or ID‑buffer picking depending on `_useIdBufferPicking`. + - Typical usage: + - On mouse‑up in your game layer, read `engine->get_last_pick()` and, if `valid`, use `ownerName`/`worldPos` to drive selection logic. + +> Note: hover picks and drag selections are also available as internal fields on `VulkanEngine` (`_hoverPick`, `_dragSelection`) and are documented in `docs/Scene.md`. You can expose additional getters if you want to rely on them from game code. + +--- + +## Scene & Instances (Actors, Lights, Animations) + +Header: `src/scene/vk_scene.h` +Docs: `docs/Scene.md` + +### Dynamic Mesh/GLTF Instances + +- Mesh instances + - `void addMeshInstance(const std::string &name, std::shared_ptr mesh, const glm::mat4 &transform = glm::mat4(1.f), std::optional boundsType = {});` + - `bool getMeshInstanceTransform(const std::string &name, glm::mat4 &outTransform);` + - `bool setMeshInstanceTransform(const std::string &name, const glm::mat4 &transform);` + - `bool removeMeshInstance(const std::string &name);` + - `void clearMeshInstances();` + - Typical usage: + - Spawn primitives or dynamic meshes at runtime (e.g. projectiles, props). + - Use `setMeshInstanceTransform` every frame to move them based on game logic. + +- GLTF instances (actors) + - `void addGLTFInstance(const std::string &name, std::shared_ptr scene, const glm::mat4 &transform = glm::mat4(1.f));` + - `bool getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform);` + - `bool setGLTFInstanceTransform(const std::string &name, const glm::mat4 &transform);` + - `bool removeGLTFInstance(const std::string &name);` + - `void clearGLTFInstances();` + - Usage pattern: + - Treat each GLTF instance as an “actor” with a name; use transforms to place characters, doors, props, etc. + +### Animations (GLTF) + +- Scene‑level + - `bool setSceneAnimation(const std::string &sceneName, int animationIndex, bool resetTime = true);` + - `bool setSceneAnimation(const std::string &sceneName, const std::string &animationName, bool resetTime = true);` + - `bool setSceneAnimationLoop(const std::string &sceneName, bool loop);` +- Instance‑level + - `bool setGLTFInstanceAnimation(const std::string &instanceName, int animationIndex, bool resetTime = true);` + - `bool setGLTFInstanceAnimation(const std::string &instanceName, const std::string &animationName, bool resetTime = true);` + - `bool setGLTFInstanceAnimationLoop(const std::string &instanceName, bool loop);` +- Notes: + - All functions return `bool` indicating whether the named scene/instance exists. + - `SceneManager::update_scene()` advances active animations each frame using engine delta time. + +### Point Lights + +- Struct: + - `struct PointLight { glm::vec3 position; float radius; glm::vec3 color; float intensity; };` +- API: + - `void addPointLight(const PointLight &light);` + - `void clearPointLights();` + - `size_t getPointLightCount() const;` + - `bool getPointLight(size_t index, PointLight &outLight) const;` + - `bool setPointLight(size_t index, const PointLight &light);` + - `bool removePointLight(size_t index);` +- Typical usage: + - On level load, add all static lights. + - At runtime, animate or toggle lights based on gameplay events (e.g. explosions, flickering lamps). + +--- + +## Picking & Selection (Interaction) + +Picking lives in `SceneManager` and is wired into `VulkanEngine`’s frame loop. + +Header: `src/scene/vk_scene.h` +Implementation: `src/scene/vk_scene_picking.cpp` + +### Single‑Object Ray Picking + +- `bool pick(const glm::vec2 &mousePosPixels, RenderObject &outObject, glm::vec3 &outWorldPos);` + - Input: + - `mousePosPixels` – window coordinates (SDL style), origin at top‑left. + - Output on success: + - `outObject` – closest `RenderObject` hit by the camera ray. + - `outWorldPos` – precise world‑space hit position (uses mesh BVH when available). + - Returns: + - `true` if any object was hit, otherwise `false`. + +### ID‑Buffer Picking + +- `bool resolveObjectID(uint32_t id, RenderObject &outObject) const;` + - Takes an ID read back from the ID buffer and resolves it to the corresponding `RenderObject` in the latest `DrawContext`. + - Used by the engine when `_useIdBufferPicking` is enabled to implement asynchronous picking. + +### Rectangle Selection (Drag Box) + +- `void selectRect(const glm::vec2 &p0, const glm::vec2 &p1, std::vector &outObjects) const;` + - Inputs: + - `p0`, `p1` – opposite corners of a window‑space rectangle (top‑left origin). + - Output: + - `outObjects` – appended with all `RenderObject`s whose projected bounds intersect the rectangle. + - Internals: + - Uses `sceneData.viewproj` and an NDC‑space bounds test to determine overlap. + +### Typical Game Usage + +- Hover tooltips: + - Track mouse position in window coordinates. + - Use `SceneManager::pick` directly, or read `VulkanEngine::get_last_pick()` and/or `_hoverPick` as documented in `Scene.md`. +- Object selection / interaction: + - On mouse click release, inspect `engine->get_last_pick()`: + - If `valid`, dispatch interaction based on `ownerType` / `ownerName` (e.g. select unit, open door). +- Multi‑select: + - When implementing drag selection, call `SceneManager::selectRect` with the drag rectangle to get all hits, or reuse the engine’s `_dragSelection` mechanism. + +--- + +## ImGui / ImGuizmo Editor Utilities + +File: `src/core/engine_ui.cpp` + +These are primarily debug/editor features but can be kept in a game build to provide in‑game tools. + +- Main entry: + - `void vk_engine_draw_debug_ui(VulkanEngine *eng);` + - Called once per frame by the engine to build the “Debug” window tabs. +- Useful tools for games: + - Scene tab: + - Spawn glTF instances at runtime using `VulkanEngine::addGLTFInstance(...)`. + - Spawn primitive mesh instances (cube/sphere) using `SceneManager::addMeshInstance(...)`. + - Point‑light editor UI built on `SceneManager` light APIs. + - Object gizmo (ImGuizmo): + - Uses last pick / hover pick as the current target and manipulates transforms via `setMeshInstanceTransform` / `setGLTFInstanceTransform`. + diff --git a/docs/Scene.md b/docs/Scene.md index 9026098..336ff26 100644 --- a/docs/Scene.md +++ b/docs/Scene.md @@ -89,11 +89,90 @@ These helpers forward to the underlying `LoadedGLTF`’s `setActiveAnimation(... ### GPU Scene Data - `GPUSceneData` carries camera matrices and lighting constants for the frame. -- Passes map and fill it into a per‑frame UBO, bindable with `DescriptorManager::gpuSceneDataLayout()`. +- Passes map and fill it into a per-frame UBO, bindable with `DescriptorManager::gpuSceneDataLayout()`. + +### Point Lights + +- `SceneManager::PointLight` + - `position` – world‑space position. + - `radius` – approximate influence radius (used for falloff). + - `color` – RGB color. + - `intensity` – scalar brightness. +- API + - `addPointLight(const PointLight &light)` + - `clearPointLights()` + - `getPointLightCount()`, `getPointLight(index, outLight)`, `setPointLight(index, light)`, `removePointLight(index)` +- Usage pattern + - On level load: call `addPointLight` for each baked/runtime point light. + - At runtime (e.g. gameplay): read/modify lights via the indexed helpers. + +### Picking & Selection (Game‑Facing) + +The scene system exposes CPU ray‑based picking and rectangle selection that the engine uses for editor tools, but you can also call them directly from game code. + +- Single‑object ray pick + - Function: `bool SceneManager::pick(const glm::vec2 &mousePosPixels, RenderObject &outObject, glm::vec3 &outWorldPos)` + - Input: `mousePosPixels` in window coordinates (SDL style), origin at top‑left. + - Output: + - `outObject` – the closest hit `RenderObject` (opaque or transparent) along the camera ray. + - `outWorldPos` – world‑space hit position (mesh BVH‑refined when available). + - Returns `true` when something was hit, `false` otherwise. + +- ID‑buffer picking + - In addition to CPU ray picks, the engine can render an object‑ID buffer and read back a single pixel. + - Core API: + - `SceneManager::resolveObjectID(uint32_t id, RenderObject &outObject) const` + - Takes an ID from the ID buffer and resolves it back to the `RenderObject` in the latest `DrawContext`. + - Engine integration: + - `RenderObject::objectID` is assigned in `MeshNode::Draw` and consumed by the geometry pass to write the ID buffer. + - `VulkanEngine` wires a small `PickReadback` render‑graph pass that copies one pixel from the ID buffer into a CPU readback buffer when ID‑buffer picking is enabled. + +- Rectangle selection + - Function: `void SceneManager::selectRect(const glm::vec2 &p0, const glm::vec2 &p1, std::vector &outObjects) const` + - Input: `p0`, `p1` – opposite corners of a screen‑space rectangle in window coordinates (top‑left origin). + - Output: `outObjects` – all `RenderObject`s whose projected bounds intersect the rectangle. + - Internals: + - Uses `sceneData.viewproj` and `box_overlaps_ndc_rect` to test each object’s bounds in clip space. + +### Engine‑Level Picking Helpers + +`VulkanEngine` wraps the scene picking functions and keeps a small amount of per‑frame state that game/editor code can query: + +- Structures on `VulkanEngine` + - `struct PickInfo` + - `MeshAsset *mesh`, `LoadedGLTF *scene`, `Node *node` + - `RenderObject::OwnerType ownerType`, `std::string ownerName` + - `glm::vec3 worldPos`, `glm::mat4 worldTransform` + - `uint32_t indexCount`, `firstIndex`, `surfaceIndex` + - `bool valid` + - Fields: + - `_lastPick` – result of the last click selection (via CPU ray or ID‑buffer). + - `_hoverPick` – result of the last per‑frame hover raycast (under the mouse cursor). + - `_dragSelection` – list of `PickInfo` filled by `SceneManager::selectRect` when a drag‑select completes. + - `_useIdBufferPicking` – toggles between CPU ray picking and ID‑buffer picking. + +- How the engine fills them (for reference) + - Mouse hover: + - The frame loop tracks `_mousePosPixels` from SDL mouse motion events. + - Each frame, `VulkanEngine::draw()` calls `SceneManager::pick(_mousePosPixels, ...)` and stores the result in `_hoverPick`. + - Click selection: + - On mouse button release, the engine either: + - Queues a pick request for the ID buffer (if `_useIdBufferPicking` is true), or + - Calls `SceneManager::pick(...)` directly (CPU ray). + - The resolved result is stored in `_lastPick`. + - Drag selection: + - The engine tracks a drag rectangle in screen space and, on release, calls `SceneManager::selectRect(...)` and converts each `RenderObject` into a `PickInfo` stored in `_dragSelection`. + +- Typical game‑side usage + - Hover tooltips: + - Read `engine->_hoverPick` each frame; if `valid`, use `ownerName`, `worldPos`, or `ownerType` to drive UI. + - Click selection: + - After input handling, inspect `engine->_lastPick` for the most recent clicked object. + - Multi‑select: + - After a drag, iterate `engine->_dragSelection` for group actions. ### Tips - Treat `DrawContext` as immutable during rendering; build it fully in `update_scene()`. -- Keep `RenderObject` small; use device addresses for vertex data to avoid per‑draw vertex buffer binds. +- Keep `RenderObject` small; use device addresses for vertex data to avoid per-draw vertex buffer binds. - For custom sorting/culling, modify only the scene layer; render passes stay simple. - diff --git a/src/core/engine.h b/src/core/engine.h index 03fcfd5..d27f0a9 100644 --- a/src/core/engine.h +++ b/src/core/engine.h @@ -174,6 +174,9 @@ public: // Debug: draw mesh BVH boxes for last pick bool _debugDrawBVH = false; + // Last click selection (CPU ray or ID-buffer). Useful for game/editor code. + const PickInfo &get_last_pick() const { return _lastPick; } + // Debug: persistent pass enable overrides (by pass name) std::unordered_map _rgPassToggles;