* chore(ci): add clang-format gate, CODEOWNERS and agent collaboration rules * refactor(modules): clear remaining back-edges and split the largest TUs Three known dependency back-edges are gone (module_depgraph.py KNOWN_BACK_EDGES is now empty; --check passes with 0 violations, 0 cycles): - window -> graphics: window queries the new IWindowSurfaceHost capability (common/WindowSurfaceHost.h) instead of holding a Graphics pointer; Window::setGraphics was removed and all call sites updated. - window -> image: Window::setIcon was replaced by setIconRGBA(const uint8_t*, w, h); the window no longer decodes ImageData. - scene -> graphics: pickScreenAt / collectFrustumIdsAt implementations moved to graphics/ScenePicking.cpp (graphics -> scene is a legal downward edge); scene now depends only on spatial. TU splits (pure moves, verified identical method sets and brace balance): - vulkan/Graphics.cpp (5118 lines) -> Graphics.cpp (lifecycle), GraphicsPipeline, Graphics2D, Graphics3D, GraphicsMesh + shared GraphicsInternal.h. - scene/Scene.cpp -> Scene.cpp (script layer / host lifecycle / serialization) + SceneNodes.cpp + shared SceneInternal.h. Verified with a real build (MSVC 19.51, prebuilt third-party): full build green; window.* and Scene.* suites pass, including scene picking/culling and GPU cases. * refactor(graphics): narrow Graphics interfaces and clear public-header leaks Step 4 — interface segregation: - New lean interfaces: IGraphics2D, IGraphics3D, IResourceFactory, IPostFX (pure virtuals, forward-declared types only; graphics/Color.h extracted from Canvas.h so modules that only need the color type stop pulling Canvas.h). - Graphics now implements all four facets; consumers can depend on the narrow interface they use instead of the 129-method god class. - Migrated voxel (VoxelWorld::drawVisible -> IGraphics3D*) and model3d (ModelRenderer::buildRenderable(s) -> IResourceFactory&). - Graphics.h slims from 24 sub-header includes to a handful of small type headers + forward declarations; the destructor moved out-of-line so unique_ptr effect members are destroyed where types are complete. Step 5 — header leaks (module_depgraph.py '*' marks: 14 -> 7): - map/TileLayer.h, particles/ParticleEmitter.h, avatar/AvatarInstance.h, animation/SpineAnim.h, map/TileSystem.h, model3d/ModelData.h, model3d/ModelRenderer.h, audio/Audio.h + Source.h, image/ImageData.h + Image.h, dialogue/Dialogue.h, procgen Palette/OutputSpec/TextureRecipe/ PbrMaterial -> forward declarations, includes moved to .cpp. - voxel/VoxelWorld.h: terrain sampler Pimpl'd (unique_ptr + out-of-line destructor), removing the procgen header dependency. - gpgpu/vulkan backend headers stop pulling graphics/vulkan/Graphics.h. - Remaining '*' marks are deliberate: tiny POD/enum headers (GridConfig, MapObject, BlendMode, Color), an internal backend header (GraphicsInternal.h -> filesystem), and lean interface references. Verified with a full clean build (MSVC) and tests: window/Scene/voxel/ RenderSystem/Quad/shader/TextureSampler/resourceLifetime pass; broad suite only shows the pre-existing PHYSFS-init filesystem-environment failures. * feat(resources): revive ResourceManager as unified IAssetReloader-backed cache * fix(resources): leak ResourceManager singleton to avoid exit-time teardown crashes Cached CPU resources may own third-party handles (FreeType faces, Assimp scenes, image decode handlers) whose libraries are torn down at process exit in an unspecified TU order; destroying cached entries from the singleton destructor can segfault at exit (seen on CI Windows in model3d.materialApi.objMtl). Keep the singleton alive until OS reclaim; explicit unload()/clear() still release entries during the run. * refactor(devtools): consume business modules through capability interfaces DevTools / cmdline no longer include business-module headers, so trimming scene / physics / procgen / particles / audio / ui / graphics no longer requires disabling devtools, and devtools can be switched off with -DEVENGINE_MODULE_DEVTOOLS=OFF. New capability interfaces in common/: - ISceneQuery (scene) - host/node inspection + mutation + transform sync - IRenderCapture (graphics) - render status, PNG capture, camera control, visible-entity snapshot, entity-ID mask, G-buffer PNGs - IPhysicsQuery (physics) - 2D world lifecycle + ray casts - IProcgenQuery (procgen) - recipe listing, map/mesh generation - IParticlesQuery (particles) - emitter status + one-shot emit - IAudioQuery (audio) - volume / stop-all - IEditorHost (ui) - declarative editor host (used by cmdline too) Providers register in their module constructors. DevTools rewires McpServer (render/scene/procgen/physics/particles/audio/host tools), SceneInspect (now delegates to ISceneQuery + IRenderCapture) and RenderVision (uses IRenderCapture::capturePngDataUrl); cmdline/Mcp.cpp uses IEditorHost. manifest: devtools DEPS graphics scene physics procgen particles audio ui image event filesystem -> event; cmdline DEPS filesystem ui -> filesystem. Verified: full build green; devtools.mcp.* tests pass; broad suite shows only the pre-existing PHYSFS-init filesystem-environment failures. * style: apply clang-format to changed lines after dev merge * fix(webgpu): include RenderControl/TextureSampler explicitly after Graphics.h slimming * fix(webgpu): provide newFont/print stubs to satisfy IGraphics2D/IResourceFactory vtables * fix(common): make ProcgenQuery.h self-sufficient (cstdint/utility for GCC)
125 lines
5.0 KiB
C++
125 lines
5.0 KiB
C++
#pragma once
|
||
|
||
#include "common/Export.h"
|
||
|
||
#include <glm/glm.hpp>
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace eve {
|
||
class IRenderCapture;
|
||
class ISceneQuery;
|
||
} // namespace eve
|
||
|
||
namespace eve::dev {
|
||
|
||
/**
|
||
* @brief 场景巡检工具集(MCP 底层数据底座)。
|
||
*
|
||
* 提供原子化的相机控制 + 渲染帧捕获 + 可见实体三维几何快照,保证图像与
|
||
* 3D 几何数据严格同步(同一次相机位姿下抓帧并导出配套几何 JSON)。
|
||
*
|
||
* 本模块不依赖任何脚本状态,直接读取引擎的 Graphics / Camera3D / Scene
|
||
* 运行时模块,因此可被 MCP 工具、C++ 测试或调试面板复用。
|
||
*
|
||
* 桌面端专用(EVDevTools 的一部分)。
|
||
*/
|
||
struct EVENGINE_API InspectView {
|
||
std::string name; // "along_road" | "bird_eye" | "corner_close" | "vista"
|
||
std::string kind; // 中文说明:沿路平视 / 高空俯拍 / 拐角特写 / 远景视角
|
||
glm::vec3 eye{0.f};
|
||
glm::vec3 target{0.f};
|
||
float fovYDeg = 60.f;
|
||
};
|
||
|
||
/** @brief 一次原子快照的结果:PNG 渲染帧 + 配套几何 JSON。 */
|
||
struct EVENGINE_API InspectCapture {
|
||
bool ok = false;
|
||
std::string error;
|
||
std::string pngPath; // 渲染帧 PNG 的磁盘路径(color buffer)
|
||
std::string jsonPath; // 配套三维几何快照 JSON 的磁盘路径
|
||
int width = 0;
|
||
int height = 0;
|
||
int entityCount = 0;
|
||
// 可选附加缓冲区(按需生成)。
|
||
std::string depthPngPath; // depth buffer PNG(GBuffer 线性深度)
|
||
std::string normalPngPath; // normal buffer PNG(GBuffer 世界法线)
|
||
std::string idPngPath; // 渲染 ID mask PNG(逐像素实体 ID 颜色)
|
||
std::string idJsonPath; // 渲染 ID mask 的 id→实体 映射 JSON
|
||
std::vector<std::string> unsupported; // 请求但当前后端不支持的缓冲区
|
||
};
|
||
|
||
class EVENGINE_API SceneInspect {
|
||
public:
|
||
static SceneInspect& instance();
|
||
|
||
SceneInspect(const SceneInspect&) = delete;
|
||
SceneInspect& operator=(const SceneInspect&) = delete;
|
||
|
||
// ---------- 多机位自动采样 ----------
|
||
/**
|
||
* @brief 围绕 center 自动生成一组标准化巡检机位:
|
||
* - along_road 沿路平视:低机位、贴近目标、视线水平略前倾
|
||
* - bird_eye 高空俯拍:目标正上方垂直俯拍
|
||
* - corner_close 拐角特写:贴近目标、斜向特写、较窄 FOV
|
||
* - vista 远景视角:抬高拉远、广角俯览
|
||
* fov 为基准 FOV(度),各机位在此基础上微调。
|
||
*/
|
||
static std::vector<InspectView> generateViews(const glm::vec3& center, float fov = 60.f);
|
||
|
||
// ---------- 相机位姿 ----------
|
||
/**
|
||
* @brief 以 pos + 欧拉角 rot 设置相机位姿。
|
||
* rot = [yawDeg, pitchDeg](与 firstperson 约定一致,Y-up)。
|
||
* fov <= 0 时保持当前 FOV。
|
||
*/
|
||
bool setCameraPose(const glm::vec3& eye, const glm::vec3& rotYawPitch, float fov = 0.f);
|
||
bool setCameraView(const InspectView& v);
|
||
|
||
// ---------- 原子快照(渲染帧 + 几何 JSON) ----------
|
||
/**
|
||
* @brief 锁定当前相机 → 捕获渲染帧 PNG → 立刻导出配套可见实体几何 JSON。
|
||
* 两者共享同一相机位姿,杜绝图片与实体数据错位。
|
||
* outDir 为空时使用缓存目录。返回文件路径与图像尺寸。
|
||
* buffers 可选值:"color"(默认, 帧) | "depth" | "normal" | "id"(渲染 ID mask)
|
||
* | "shadow"(当前后端不支持, 记为 unsupported)。
|
||
*/
|
||
InspectCapture capture(const std::string& outDir = {}, const std::string& tag = "frame",
|
||
const std::vector<std::string>& buffers = {});
|
||
|
||
// ---------- 可见实体三维几何快照 ----------
|
||
/**
|
||
* @brief 生成当前视锥内可见实体的结构化 JSON:
|
||
* { camera, viewport, entities:[ { id, asset, world_aabb:{min,max},
|
||
* screen_bbox:{x,y,w,h} } ] }
|
||
* 位姿可用 camera 指定,否则回退到当前激活相机。
|
||
*/
|
||
std::string visibleEntitiesJson(const glm::vec3* eye = nullptr,
|
||
const glm::vec3* target = nullptr, float fov = 0.f);
|
||
/** @brief 当前激活相机位姿 JSON(eye/target/fov/viewport)。 */
|
||
std::string currentPoseJson();
|
||
|
||
// ---------- 快照持久化 / 临时缓存 ----------
|
||
void setCacheDir(std::string dir) { cacheDir_ = std::move(dir); }
|
||
const std::string& cacheDir() const { return cacheDir_; }
|
||
/** @brief 默认缓存目录:<gameRoot>/eve_inspect_cache。 */
|
||
std::string defaultCacheDir() const;
|
||
/** @brief 最近一次快照的 PNG / JSON 路径(供后续读取)。 */
|
||
const std::string& lastPngPath() const { return lastPngPath_; }
|
||
const std::string& lastJsonPath() const { return lastJsonPath_; }
|
||
|
||
private:
|
||
SceneInspect() = default;
|
||
|
||
eve::IRenderCapture* captureIface();
|
||
eve::ISceneQuery* scene();
|
||
bool ensureCamera();
|
||
|
||
std::string cacheDir_;
|
||
std::string lastPngPath_;
|
||
std::string lastJsonPath_;
|
||
};
|
||
|
||
} // namespace eve::dev
|