SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
SceneBase.cpp
Go to the documentation of this file.
2#include <Core/GameObject.hpp>
3#include <Core/Logger.hpp>
4#include <Camera/Camera.hpp>
6#include <Lighting/Light.hpp>
8#include <Runtime/Skybox.hpp>
13
14namespace Sleak {
15
16/// Walks obj and its children, registering any ColliderComponent found with world.
18 if (!obj || !world) return;
19 auto* collider = obj->GetComponent<ColliderComponent>();
20 if (collider) {
21 world->RegisterCollider(collider);
22 }
23 for (size_t i = 0; i < obj->GetChildren().GetSize(); ++i) {
25 }
26}
27
28/// Walks obj and its children, unregistering any ColliderComponent found from world.
30 if (!obj || !world) return;
31 auto* collider = obj->GetComponent<ColliderComponent>();
32 if (collider) {
33 world->UnregisterCollider(collider);
34 }
35 for (size_t i = 0; i < obj->GetChildren().GetSize(); ++i) {
37 }
38}
39
42 delete m_lightManager;
43 m_lightManager = nullptr;
44 delete m_physicsWorld;
45 m_physicsWorld = nullptr;
46 delete m_skybox;
47 m_skybox = nullptr;
48}
49
56
60
61 if (bActive) Deactivate();
62
63 OnUnload();
64
66
68 q->ClearAll();
69
70 bInitialized = false;
72}
73
75 if (state == SceneState::Active) return;
76
78
80 bActive = true;
81
82 OnActivate();
83
84 Begin();
85}
86
88 if (state != SceneState::Active) return;
90 bActive = false;
92}
93
95 if (state != SceneState::Active) return;
97 bActive = false;
98}
99
101 if (state != SceneState::Paused) return;
103 bActive = true;
104}
105
107 if (bInitialized) return true;
108
109 if (!m_lightManager) {
111 m_lightManager->Initialize();
112 }
113
114 if (!m_physicsWorld) {
116
117 // Register colliders from objects added before PhysicsWorld existed
118 for (size_t i = 0; i < Objects.GetSize(); ++i) {
119 if (Objects[i]) {
121 }
122 }
123 }
124
125 if (m_skybox && !m_skybox->IsInitialized()) {
126 m_skybox->Initialize();
127 }
128
129 for (size_t i = 0; i < Objects.GetSize(); ++i) {
130 if (Objects[i]) Objects[i]->Initialize();
131 }
132
133 bInitialized = true;
134 return true;
135}
136
138 for (size_t i = 0; i < Objects.GetSize(); ++i) {
139 if (Objects[i]) Objects[i]->SetActive(true);
140 }
141}
142
143void SceneBase::Update(float deltaTime) {
144 if (!bActive) return;
145
146 // Update objects FIRST so Camera::View/Projection reflect this frame's
147 // rotation/position before any render-side UBO computes InvViewProj.
148 // Why: LightManager::UpdateDeferredCB reads the static Camera matrices
149 // to build InvViewProj for the deferred lighting pass. If it ran
150 // before the camera object updated, InvViewProj was one frame stale
151 // and the lighting pass reconstructed wrong world positions on any
152 // camera rotation, causing whole-terrain shadow flicker.
153 for (size_t i = 0; i < Objects.GetSize(); ++i) {
154 if (Objects[i] && Objects[i]->IsActive() && !Objects[i]->HasParent()) {
155 Objects[i]->Update(deltaTime);
156 }
157 }
158
159 if (m_lightManager)
160 m_lightManager->UpdateAndBind();
161
162 if (m_skybox)
163 m_skybox->Render();
164
165 if (m_physicsWorld)
166 m_physicsWorld->Step(deltaTime);
167
169 auto drawColliderShape = [](ColliderComponent* collider, const Math::Vector3D& worldPos, const Math::Vector3D& worldScale) {
170 const auto& shape = collider->GetShape();
171
172 if (auto* aabb = std::get_if<Physics::AABB>(&shape)) {
173 Physics::AABB worldAABB(
174 aabb->min * worldScale + worldPos,
175 aabb->max * worldScale + worldPos);
176 DebugLineRenderer::DrawAABB(worldAABB, 0.0f, 1.0f, 0.0f);
177 } else if (auto* sphere = std::get_if<Physics::BoundingSphere>(&shape)) {
178 Math::Vector3D center = sphere->center * worldScale + worldPos;
179 float maxScale = std::max({worldScale.GetX(), worldScale.GetY(), worldScale.GetZ()});
180 DebugLineRenderer::DrawSphere(center, sphere->radius * maxScale, 0.0f, 1.0f, 0.0f);
181 } else if (auto* capsule = std::get_if<Physics::BoundingCapsule>(&shape)) {
182 Physics::BoundingCapsule worldCapsule = *capsule;
183 worldCapsule.center = capsule->center * worldScale + worldPos;
184 float maxScale = std::max({worldScale.GetX(), worldScale.GetY(), worldScale.GetZ()});
185 worldCapsule.radius = capsule->radius * maxScale;
186 worldCapsule.halfHeight = capsule->halfHeight * maxScale;
187 DebugLineRenderer::DrawCapsule(worldCapsule, 0.0f, 1.0f, 0.0f);
188 }
189 };
190
191 for (size_t i = 0; i < Objects.GetSize(); ++i) {
192 if (!Objects[i]) continue;
193 auto* collider = Objects[i]->GetComponent<ColliderComponent>();
194 if (!collider) continue;
195
196 Math::Vector3D pos(0, 0, 0), scale(1, 1, 1);
197 auto* transform = Objects[i]->GetComponent<TransformComponent>();
198 if (transform) {
199 pos = transform->GetWorldPosition() + collider->GetOffset();
200 scale = transform->GetWorldScale();
201 } else if (auto* cam = dynamic_cast<Camera*>(Objects[i])) {
202 pos = cam->GetPosition() + collider->GetOffset();
203 }
204 drawColliderShape(collider, pos, scale);
205 }
206
207 }
208
210
212}
213
214void SceneBase::FixedUpdate(float fixedDeltaTime) {
215 if (!bActive) return;
216
217 for (size_t i = 0; i < Objects.GetSize(); ++i) {
218 if (Objects[i] && Objects[i]->IsActive() && !Objects[i]->HasParent()) {
219 Objects[i]->FixedUpdate(fixedDeltaTime);
220 }
221 }
222}
223
224void SceneBase::LateUpdate(float deltaTime) {
225 if (!bActive) return;
226
227 for (size_t i = 0; i < Objects.GetSize(); ++i) {
228 if (Objects[i] && Objects[i]->IsActive() && !Objects[i]->HasParent()) {
229 Objects[i]->LateUpdate(deltaTime);
230 }
231 }
232}
233
235 if (!object) return;
236 if (Objects.indexOf(object) != -1) return; // already in scene
237
238 Objects.add(object);
239
240 if (m_lightManager && object->IsLight()) {
241 m_lightManager->RegisterLight(
242 static_cast<Light*>(object));
243 }
244
245 if (m_physicsWorld) {
247 }
248
249 if (bInitialized && !object->IsActive()) {
250 object->Initialize();
251 if (bActive) object->SetActive(true);
252 }
253}
254
256 if (!object) return;
257 int index = Objects.indexOf(object);
258 if (index != -1) {
259 if (m_lightManager && object->IsLight()) {
260 m_lightManager->UnregisterLight(
261 static_cast<Light*>(object));
262 }
263 if (m_physicsWorld) {
265 }
266 Objects.erase(index);
267 delete object;
268 }
269}
270
272 if (!object) return;
273 if (object->IsPendingDestroy()) return;
274
275 object->MarkForDestroy();
276 m_pendingDestroy.add(object);
277
278 const auto& children = object->GetChildren();
279 for (size_t i = 0; i < children.GetSize(); ++i) {
280 if (children[i] && !children[i]->IsPendingDestroy()) {
281 DestroyObject(children[i]);
282 }
283 }
284}
285
286GameObject* SceneBase::FindObjectByName(const std::string& objectName) {
287 for (size_t i = 0; i < Objects.GetSize(); ++i) {
288 if (Objects[i] && Objects[i]->GetName() == objectName) {
289 return Objects[i];
290 }
291 }
292 return nullptr;
293}
294
296 for (size_t i = 0; i < Objects.GetSize(); ++i) {
297 if (Objects[i] && Objects[i]->GetUniqueID() == id) {
298 return Objects[i];
299 }
300 }
301 return nullptr;
302}
303
305 List<GameObject*> result;
306 for (size_t i = 0; i < Objects.GetSize(); ++i) {
307 if (Objects[i] && Objects[i]->GetTag() == tag) {
308 result.add(Objects[i]);
309 }
310 }
311 return result;
312}
313
315 if (m_pendingDestroy.empty()) return;
316
317 for (size_t i = 0; i < m_pendingDestroy.GetSize(); ++i) {
319 if (!obj) continue;
320
321 if (m_lightManager && obj->IsLight()) {
322 m_lightManager->UnregisterLight(
323 static_cast<Light*>(obj));
324 }
325
326 if (m_physicsWorld) {
328 }
329
330 int index = Objects.indexOf(obj);
331 if (index != -1) {
332 Objects.erase(index);
333 }
334
335 delete obj;
336 }
337 m_pendingDestroy.clear();
338}
339
341 // Clear pending list first (those are also in Objects)
342 m_pendingDestroy.clear();
343
344 for (size_t i = 0; i < Objects.GetSize(); ++i) {
345 delete Objects[i];
346 }
347 Objects.clear();
348}
349
351 if (m_skybox) {
352 delete m_skybox;
353 }
354 m_skybox = skybox;
355 if (m_skybox && bInitialized && !m_skybox->IsInitialized()) {
356 m_skybox->Initialize();
357 }
358}
359
360} // namespace Sleak
const Physics::ColliderShape & GetShape() const
Math::Vector3D GetOffset() const
static void Flush(Camera *camera)
Uploads all queued lines and draws them in one pass, then clears the queue.
static void DrawSphere(const Math::Vector3D &center, float radius, float r, float g, float b, float a=1.0f, int segments=16)
Queues a wireframe sphere approximated with segments latitude/longitude rings.
static void DrawAABB(const Physics::AABB &aabb, float r, float g, float b, float a=1.0f)
Queues a wireframe box outline.
static void DrawCapsule(const Physics::BoundingCapsule &capsule, float r, float g, float b, float a=1.0f, int segments=16)
Queues a wireframe capsule outline.
const List< GameObject * > & GetChildren() const
bool IsActive() const
bool IsPendingDestroy() const
virtual bool IsLight() const
T * GetComponent()
Finds the first attached component of type T, or nullptr.
Implements a dynamic array-like list for storing and managing a collection of elements.
Definition List.hpp:20
void add(const T &value)
Definition List.hpp:113
void RegisterCollider(ColliderComponent *collider)
void UnregisterCollider(ColliderComponent *collider)
static RenderCommandQueue * GetInstance()
Lazily creates and returns the process-wide singleton instance.
List< GameObject * > FindObjectsByTag(const std::string &tag)
Collects every object whose tag matches.
void Unload()
Deactivates if active, calls OnUnload(), and destroys all owned objects.
Definition SceneBase.cpp:57
void Deactivate()
Marks the scene inactive and calls OnDeactivate().
Definition SceneBase.cpp:87
List< GameObject * > Objects
virtual void Update(float deltaTime)=0
Advances all active, root-level objects by deltaTime, then steps lighting and physics.
virtual void FixedUpdate(float fixedDeltaTime)
Advances all active, root-level objects on the fixed timestep.
void Resume()
Reactivates a paused scene without re-running OnActivate().
void SetSkybox(Skybox *skybox)
Replaces the scene's skybox, deleting the previous one.
void ProcessPendingDestroy()
Actually deletes objects queued by DestroyObject().
GameObject * FindObjectByName(const std::string &name)
Linear search for the first object with a matching name.
virtual void OnLoad()
Override to load scene-specific assets; called once from Load().
Definition SceneBase.hpp:80
void DestroyObject(GameObject *object)
Queues an object for destruction; actually freed on the next ProcessPendingDestroy().
virtual void RemoveObject(GameObject *object)
Unregisters and deletes object immediately.
SceneState state
Camera * m_activeCamera
virtual void OnUnload()
Override to release scene-specific assets; called from Unload().
Definition SceneBase.hpp:82
void DestroyAllObjects()
Destroys every object still owned by the scene, e.g. during Unload().
List< GameObject * > m_pendingDestroy
void Activate()
Marks the scene active and calls OnActivate().
Definition SceneBase.cpp:74
virtual void OnActivate()
Override for logic that should run when the scene becomes active.
Definition SceneBase.hpp:86
LightManager * m_lightManager
GameObject * FindObjectByID(uint64_t id)
Linear search for the object with a matching unique ID.
void Load()
Moves Unloaded -> Loading -> Active, calling OnLoad() and Initialize().
Definition SceneBase.cpp:50
virtual void OnDeactivate()
Override for logic that should run when the scene stops being active.
Definition SceneBase.hpp:88
const std::string & GetName() const
void Pause()
Freezes the scene without tearing it down; leaves it in the Paused state.
Definition SceneBase.cpp:94
virtual void AddObject(GameObject *object)
Takes ownership of object, registering it with lighting and physics as needed.
virtual bool Initialize()
Runs once before the scene's first Begin()/Update().
Physics::PhysicsWorld * m_physicsWorld
bool IsActive() const
virtual void Begin()=0
Activates every owned object; runs once after Initialize().
virtual ~SceneBase()
Definition SceneBase.cpp:40
virtual void LateUpdate(float deltaTime)
Advances all active, root-level objects after the main Update pass.
Represents the position, rotation, and scale of an entity in 3D space.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10
static void RegisterCollidersRecursive(GameObject *obj, Physics::PhysicsWorld *world)
Walks obj and its children, registering any ColliderComponent found with world.
Definition SceneBase.cpp:17
static void UnregisterCollidersRecursive(GameObject *obj, Physics::PhysicsWorld *world)
Walks obj and its children, unregistering any ColliderComponent found from world.
Definition SceneBase.cpp:29