载入中...
搜索中...
未找到
SceneLoader.h
浏览该文件的文档.
1#pragma once
2
3#include "common/Module.h"
4#include "scene/NodeDesc.h"
5
6#include <functional>
7#include <memory>
8#include <mutex>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13struct aiScene;
14struct aiNode;
15struct aiMesh;
16
17namespace eve {
18namespace animation {
19class AnimSkeleton;
20class AnimClip;
21} // namespace animation
22namespace graphics {
23class Graphics;
24class Renderable3D;
25class Light3D;
26class Camera3D;
27class Texture;
28class Mesh;
29} // namespace graphics
30namespace model3d {
31class ModelData;
32} // namespace model3d
33namespace scene {
34class NodeDesc;
35class SceneHost;
36} // namespace scene
37namespace thread {
38class ThreadPool;
39}
40
41namespace sceneloader {
42
58 enum class Action { Add, Remove, Modify, Move };
59
61 std::string id; // GameObject id (scene-object id).
62 std::string parent; // new parent id (Add / Move only).
63};
64
65struct SceneDiff {
66 std::vector<SceneDiffEntry> entries;
67 int added = 0;
68 int removed = 0;
69 int modified = 0;
70 int moved = 0;
71
72 bool empty() const { return entries.empty(); }
73};
74
82struct MeshSlot {
83 const aiScene *scene = nullptr;
84 const aiMesh *mesh = nullptr;
85 unsigned materialIndex = 0;
86};
87using MeshSlotMap = std::unordered_map<std::string, std::vector<MeshSlot>>;
88
100 bool triangulate = true;
103 bool flipUVs = true;
106 bool sharedMeshes = true;
108 bool mipmaps = true;
110 bool importLights = true;
112 bool importCameras = false;
114 bool importAnimations = true;
115};
116
137class SceneLoader : public Module {
138public:
140
141 ~SceneLoader() override;
142
144 scene::SceneHost *load(const std::string &path, bool linkRenderables = true,
145 const LoadOptions &options = {});
146 scene::SceneHost *load(const std::string &path, const LoadOptions &options);
147
153 bool reload(const std::string &path, SceneDiff *out = nullptr,
154 const LoadOptions &options = {});
155
157 bool reloadChecked(const std::string &path) { return reload(path, nullptr); }
158
160 SceneDiff diff(const std::string &path);
161
163 scene::SceneHost *host(const std::string &path);
164
166 void unload(const std::string &path);
167
169 int nodeCount(const std::string &path);
171 bool loaded(const std::string &path);
172
173 // ---- async loading (decode off-thread, mount on the main thread) ----
174
181 bool loadAsync(const std::string &path, const LoadOptions &options = {},
182 std::function<void(scene::SceneHost *)> done = nullptr);
183
188 int pollAsync();
189
191 bool prewarmAsync(const std::string &path, const LoadOptions &options = {});
193 bool prewarmed(const std::string &path) const;
195 void clearPrewarm(const std::string &path);
196
198 int pendingAsyncCount() const;
199
200 // ---- imported scene extras ----
201
203 int lightCount(const std::string &path);
204 graphics::Light3D *light(const std::string &path, int index);
205
207 int cameraCount(const std::string &path);
208 graphics::Camera3D *camera(const std::string &path, int index);
209
211 int animationCount(const std::string &path);
213 animation::AnimSkeleton *skeleton(const std::string &path);
214 animation::AnimClip *clip(const std::string &path, int index);
215
216 // ---- pure tree helpers (no graphics required; unit-testable) ----
217
219 using TextureCache = std::unordered_map<std::string, graphics::Texture *>;
220 using MeshCache = std::unordered_map<const aiMesh *, graphics::Mesh *>;
222 struct CpuImage {
223 int w = 0;
224 int h = 0;
225 std::vector<uint8_t> rgba;
226 };
227 using CpuImageMap = std::unordered_map<std::string, CpuImage>;
228
230 static scene::NodeDesc buildNodeDesc(const aiScene *scene, MeshSlotMap *slotsOut = nullptr);
231
233 static SceneDiff diffTree(scene::SceneHost *host, const scene::NodeDesc &newRoot);
234
240 static bool applyTreeDiff(scene::SceneHost *host, const scene::NodeDesc &newRoot,
241 const SceneDiff &diff, graphics::Graphics *gfx,
242 const MeshSlotMap *slots);
243
249 static void fillSceneBounds(scene::SceneHost *host, const MeshSlotMap &slots);
250
251private:
252 struct Loaded {
253 std::string path;
254 scene::SceneHost *host = nullptr;
255 graphics::Graphics *gfx = nullptr;
256 LoadOptions options;
257 std::vector<graphics::Light3D *> lights;
258 std::vector<graphics::Camera3D *> cameras;
259 animation::AnimSkeleton *skeleton = nullptr;
260 std::vector<animation::AnimClip *> clips;
261 };
262
263 struct DecodedScene {
264 std::string path;
265 model3d::ModelData *md = nullptr;
266 scene::NodeDesc root;
267 MeshSlotMap slots;
268 LoadOptions options;
269 CpuImageMap cpuImages; // external textures pre-decoded off-thread
270 std::vector<graphics::Light3D *> lights;
271 std::vector<graphics::Camera3D *> cameras;
272 animation::AnimSkeleton *skeleton = nullptr;
273 std::vector<animation::AnimClip *> clips;
274 bool prewarmOnly = false;
275 std::function<void(scene::SceneHost *)> done;
276 };
277
278 bool decode(const std::string &path, const LoadOptions &options, DecodedScene *out);
279 scene::SceneHost *mount(DecodedScene &d);
281 void linkMeshNodes(scene::SceneHost *host, const MeshSlotMap &slots,
282 graphics::Graphics *gfx, const LoadOptions &options,
283 TextureCache &textures, MeshCache &shared,
284 const CpuImageMap *predecoded = nullptr);
286 void clearTextures();
287
288 std::unordered_map<std::string, Loaded> scenes_;
289 std::unordered_map<std::string, DecodedScene> prewarmed_;
290 TextureCache textures_;
291 std::shared_ptr<thread::ThreadPool> pool_;
292 std::vector<DecodedScene> pending_;
293 mutable std::mutex pendingMu_;
294};
295
296} // namespace sceneloader
297} // namespace eve
int d
3D bone hierarchy + bind-pose local TRS for skeletal animation. Independent of ik::Skeleton3D (FABRIK...
CPU-side decoded 3D model (Assimp scene owned via medialoader::ModelScene). Does not upload to GPU — ...
Definition ModelData.h:23
ECS mount point for one scene graph (full scene or nested subtree root). Isomorphic to eve::ui::UIHos...
Definition SceneHost.h:80
Loads a 3D scene (glTF / OBJ / FBX / GLB ... via Assimp/medialoader) into the ECS scene tree.
bool loadAsync(const std::string &path, const LoadOptions &options={}, std::function< void(scene::SceneHost *)> done=nullptr)
Decode path on a worker thread, then apply it on the main thread the next time pollAsync() is called ...
int pendingAsyncCount() const
Number of async loads still waiting to be mounted.
static bool applyTreeDiff(scene::SceneHost *host, const scene::NodeDesc &newRoot, const SceneDiff &diff, graphics::Graphics *gfx, const MeshSlotMap *slots)
Apply a diff to the host arena in place. Creates/destroys Renderable3D for added/removed mesh objects...
std::unordered_map< const aiMesh *, graphics::Mesh * > MeshCache
graphics::Light3D * light(const std::string &path, int index)
void clearPrewarm(const std::string &path)
Drop a decoded prewarm result and release its CPU scene.
int lightCount(const std::string &path)
Number of imported Light3D entities for path; 0 if none / disabled.
int animationCount(const std::string &path)
Number of imported animation clips for path; 0 if none / disabled.
bool prewarmAsync(const std::string &path, const LoadOptions &options={})
Decode and retain a scene without creating ECS/GPU objects.
scene::SceneHost * load(const std::string &path, bool linkRenderables=true, const LoadOptions &options={})
Full load: build the GameObject tree from path, mount it, return host.
std::unordered_map< std::string, CpuImage > CpuImageMap
SceneDiff diff(const std::string &path)
Dry-run diff for path against the currently mounted tree (no mutation).
bool reload(const std::string &path, SceneDiff *out=nullptr, const LoadOptions &options={})
Hot-reload path. Re-decodes, diffs, and applies only what changed. Returns false if the file failed t...
scene::SceneHost * host(const std::string &path)
The mounted host for path, or nullptr if not loaded.
animation::AnimSkeleton * skeleton(const std::string &path)
Imported skeleton for path (nullptr when the scene has no animations).
bool loaded(const std::string &path)
True if path is currently loaded.
animation::AnimClip * clip(const std::string &path, int index)
static scene::NodeDesc buildNodeDesc(const aiScene *scene, MeshSlotMap *slotsOut=nullptr)
Flatten an Assimp scene into a scene::NodeDesc tree (id = object id).
bool reloadChecked(const std::string &path)
Script-friendly reload: returns true when anything was updated.
static void fillSceneBounds(scene::SceneHost *host, const MeshSlotMap &slots)
Fill node bounds from Assimp mesh AABBs (mesh GameObjects get the exact local-space AABB; ancestors g...
static SceneDiff diffTree(scene::SceneHost *host, const scene::NodeDesc &newRoot)
Diff a mounted host tree against a freshly built NodeDesc tree.
void unload(const std::string &path)
Drop the loaded scene for path, destroying linked Renderable3D objects.
bool prewarmed(const std::string &path) const
True when a decoded scene is ready for load() to consume.
int nodeCount(const std::string &path)
Number of GameObjects (SceneNodes) currently mounted for path; 0 if none.
int pollAsync()
Mount every decoded-but-not-applied scene. Must be called on the main / render thread....
std::unordered_map< std::string, graphics::Texture * > TextureCache
Caches shared across the loader: textures by source key, GPU meshes per aiMesh.
int cameraCount(const std::string &path)
Number of imported Camera3D entities for path; 0 if none / disabled.
Fixed-size worker pool. Owns worker std::threads; tasks run FIFO. Squirrel VM is not thread-safe — do...
Definition ThreadPool.h:24
std::unordered_map< std::string, std::vector< MeshSlot > > MeshSlotMap
Definition SceneLoader.h:87
Definition Build.cpp:11
Declarative scene-node description (build once / on dirty → flatten into SceneHost::Tree)....
Definition NodeDesc.h:15
Options controlling how a 3D scene file is decoded and mounted.
Definition SceneLoader.h:99
bool importLights
Import aiLight entries as graphics::Light3D entities.
bool mipmaps
Generate mipmaps + anisotropic filtering for imported textures.
bool sharedMeshes
Reuse one GPU mesh when several nodes reference the same aiMesh.
bool importAnimations
Import aiAnimation clips (skeleton + clips exposed via accessors).
bool importCameras
Import aiCamera entries as inactive graphics::Camera3D entities.
A GPU mesh reference for one Assimp mesh referenced by an aiNode. The loader uploads one Renderable3D...
Definition SceneLoader.h:82
SceneDiffEntry / SceneDiff
Definition SceneLoader.h:57
std::vector< SceneDiffEntry > entries
Definition SceneLoader.h:66
CPU-decoded texture (RGBA8) keyed by the same source+suffix key as TextureCache.