galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
Scene.cpp
Go to the documentation of this file.
1
7
8#include <entt/locator/locator.hpp>
9#include <sol/sol.hpp>
10
21
22#include "Scene.hpp"
23
24namespace galaxy
25{
26 Scene::Scene(const std::string& name) noexcept
27 : State {name}
28 {
29 /*
30 auto& w = core::ServiceLocator<core::Window>::ref();
31 m_camera.set_viewport(w.frame_width(), w.frame_height());
32 auto& nui = core::ServiceLocator<ui::NuklearUI>::ref();
33 m_dispatcher.sink<events::WindowResized>().connect<&Scene::on_window_resized>(this);
34 m_dispatcher.sink<events::MousePressed>().connect<&ui::NuklearUI::on_mouse_pressed>(nui);
35 m_dispatcher.sink<events::MouseWheel>().connect<&ui::NuklearUI::on_mouse_wheel>(nui);
36 m_dispatcher.sink<events::KeyChar>().connect<&ui::NuklearUI::on_key_char>(nui);
37 m_dispatcher.sink<events::KeyPress>().connect<&ui::NuklearUI::on_key_press>(nui);
38 m_dispatcher.sink<events::ContentScale>().connect<&ui::NuklearUI::on_content_scale>(nui);
39 */
40 }
41
42 Scene::~Scene() noexcept
43 {
44 }
45
47 {
48 }
49
51 {
52 if (entt::locator<sol::state>::has_value())
53 {
54 entt::locator<sol::state>::value().collect_garbage();
55 }
56 }
57
58 void Scene::on_event(SDL_Event& event)
59 {
60 /*for (auto& layer : std::views::reverse(m_LayerStack))
61 {
62 layer->OnEvent(event);
63 if (event.Handled)
64 break;
65 }
66
67 Core::EventDispatcher dispatcher(event);
68 dispatcher.Dispatch<Core::MouseButtonPressedEvent>([this](Core::MouseButtonPressedEvent& e) { return OnMouseButtonPressed(e); });
69 dispatcher.Dispatch<Core::MouseMovedEvent>([this](Core::MouseMovedEvent& e) { return OnMouseMoved(e); });
70 dispatcher.Dispatch<Core::WindowClosedEvent>([this](Core::WindowClosedEvent& e) { return OnWindowClosed(e); });
71
72 switch (event.type)
73 {
74 case SDL_EVENT_SCREEN_KEYBOARD_SHOWN:
75 case SDL_EVENT_SCREEN_KEYBOARD_HIDDEN:
76 break;
77
78 case SDL_EVENT_LOCALE_CHANGED:
79 // TODO: Handle Languages.
80 break;
81
82 case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
83 case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
84 SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED, /**< Display has changed desktop mode
85 //SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, /**< Display has changed current mode
86 // SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale
87 //SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, /**< Display has changed usable bounds
88 // SDL_GetDisplayContentScale
89 // SDL_GetWindowDisplayScale
90 // https://wiki.libsdl.org/SDL3/README-highdpi
91 float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
92 break;
93
94 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
95 // SDL_GetWindowSizeInPixels
96 break;
97
98 case SDL_EVENT_WINDOW_RESIZED:
99 case SDL_EVENT_WINDOW_MAXIMIZED:
100 case SDL_EVENT_WINDOW_RESTORED:
101 case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
102 case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
103 case SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED:
104 {
105 const auto size = window.get_pixel_size();
106 dispatcher.enqueue<WindowResized>(size.x, size.y);
107 }
108 break;
109
110 case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
111 // TODO
112 // HANDLE RESIZE + DISPLAY SCALE + PIXEL SIZE SCALE.
113 break;
114
115 case SDL_EVENT_WINDOW_MOUSE_ENTER:
116 case SDL_EVENT_WINDOW_FOCUS_GAINED:
117 dispatcher.enqueue<GainedFocus>();
118 break;
119
120 case SDL_EVENT_WINDOW_MOUSE_LEAVE:
121 case SDL_EVENT_WINDOW_FOCUS_LOST:
122 dispatcher.enqueue<LostFocus>();
123 break;
124
125 case SDL_EVENT_KEY_DOWN:
126 {
127 dispatcher.enqueue<KeyPressed>(
128 m_events.key.scancode,
129 static_cast<Keys>(m_events.key.key),
130 static_cast<KeyMods>(m_events.key.mod),
131 m_events.key.raw,
132 m_events.key.repeat
133 );
134 }
135 break;
136
137 case SDL_EVENT_KEY_UP:
138 {
139 dispatcher.enqueue<KeyReleased>(
140 m_events.key.scancode,
141 static_cast<Keys>(m_events.key.key),
142 static_cast<KeyMods>(m_events.key.mod),
143 m_events.key.raw,
144 m_events.key.repeat
145 );
146 }
147 break;
148
149 case SDL_EVENT_TEXT_INPUT:
150 // case SDL_EVENT_TEXT_EDITING:
151 // case SDL_EVENT_TEXT_EDITING_CANDIDATES:
152 {
153 auto text = std::string(m_events.text.text);
154 dispatcher.enqueue<KeyInput>(std::move(text));
155 }
156 break;
157
158 case SDL_EVENT_MOUSE_MOTION:
159 {
160 dispatcher.enqueue<MouseMoved>(m_events.motion.x, m_events.motion.y, m_events.motion.xrel, m_events.motion.yrel);
161 }
162 break;
163
164 case SDL_EVENT_MOUSE_BUTTON_DOWN:
165 {
166 dispatcher.enqueue<MousePressed>(m_events.button.x, m_events.button.y, m_events.button.clicks, static_cast<MouseButton>(m_events.button.button));
167 }
168 break;
169
170 case SDL_EVENT_MOUSE_BUTTON_UP:
171 {
172 dispatcher.enqueue<MouseReleased>(m_events.button.x, m_events.button.y, m_events.button.clicks, static_cast<MouseButton>(m_events.button.button));
173 }
174 break;
175
176 case SDL_EVENT_MOUSE_WHEEL:
177 {
178 dispatcher.enqueue<MouseWheel>(
179 m_events.wheel.x,
180 m_events.wheel.y,
181 m_events.wheel.direction,
182 m_events.wheel.mouse_x,
183 m_events.wheel.mouse_y,
184 m_events.wheel.integer_x,
185 m_events.wheel.integer_y
186 );
187 }
188 break;
189
190 case SDL_EVENT_DROP_BEGIN:
191 // TODO
192 Drag and drop events
193 SDL_EVENT_DROP_FILE = 0x1000, /**< The system requests a file open *
194 SDL_EVENT_DROP_TEXT, /**< text/plain drag-and-drop event *
195 SDL_EVENT_DROP_BEGIN, /**< A new set of drops is beginning (NULL filename) *
196 SDL_EVENT_DROP_COMPLETE, /**< Current set of drops is now complete (NULL filename) *
197 SDL_EVENT_DROP_POSITION, /**< Position while moving over the window
198 // SDL_DropEvent
199 break;
200
201 case SDL_EVENT_JOYSTICK_AXIS_MOTION:
202 case SDL_EVENT_JOYSTICK_BALL_MOTION:
203 case SDL_EVENT_JOYSTICK_HAT_MOTION:
204 case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
205 case SDL_EVENT_JOYSTICK_BUTTON_UP:
206 case SDL_EVENT_JOYSTICK_REMOVED:
207 case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
208 case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
209 // TODO
210 break;
211
212 case SDL_EVENT_GAMEPAD_AXIS_MOTION:
213 case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
214 case SDL_EVENT_GAMEPAD_BUTTON_UP:
215 case SDL_EVENT_GAMEPAD_REMOVED:
216 case SDL_EVENT_GAMEPAD_REMAPPED:
217 case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
218 case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
219 case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
220 case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
221 case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE:
222 case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
223 // TODO
224 break;
225
226 case SDL_EVENT_FINGER_DOWN:
227 case SDL_EVENT_FINGER_UP:
228 case SDL_EVENT_FINGER_MOTION:
229 case SDL_EVENT_FINGER_CANCELED:
230 // TODO
231 break;
232
233 case SDL_EVENT_PEN_PROXIMITY_IN:
234 case SDL_EVENT_PEN_PROXIMITY_OUT:
235 case SDL_EVENT_PEN_DOWN:
236 case SDL_EVENT_PEN_UP:
237 case SDL_EVENT_PEN_BUTTON_DOWN:
238 case SDL_EVENT_PEN_BUTTON_UP:
239 case SDL_EVENT_PEN_MOTION:
240 case SDL_EVENT_PEN_AXIS:
241 // TODO
242 break;
243
244 default:
245 break;
246 }
247 */
248 }
249
251 {
252 // make sure events are propagated from top to bottom.
253 // make sure updting is from btm to top.
254
255 // graphics::Renderer::ref().flush();
256 // m_registry.update(m_b2world);
257 // m_b2world.Step(GALAXY_DT, m_velocity_iterations, m_position_iterations);
258 m_sysman.update(em, this);
259 }
260
262 {
263 // render scene
264 // then any ui layers.
265
266 /*
267 graphics::Renderer::ref().begin_post();
268
269 // Scene specific.
270 graphics::Renderer::ref().submit_camera(m_camera);
271 graphics::Renderer::ref().draw();
272
273 graphics::Renderer::ref().end_post();
274 graphics::Renderer::ref().begin_default();
275 graphics::Renderer::ref().render_post();
276 graphics::Renderer::ref().end_default();
277
278 // Scene specific.
279 auto& nui = core::ServiceLocator<ui::NuklearUI>::ref();
280
281 nui.new_frame();
282 update_ui();
283 nui.render();
284
285 graphics::Renderer::ref().end_default();
286 */
287 }
288
290 {
291 return m_sysman;
292 }
293
294 /*void Scene::update_ui()
295 {
296 const auto view = m_registry.m_entt.view<components::GUI>(entt::exclude<flags::Disabled>);
297 for (auto&& [entity, gui] : view.each())
298 {
299 if (gui.m_update.valid())
300 {
301 gui.m_update(gui.m_self);
302 }
303 }
304 }
305 bool Scene::load_world(const std::string& file)
306 {
307 if (m_world.load(file))
308 {
309 m_world.parse();
310 return true;
311 }
312
313 return false;
314 }
315
316 nlohmann::json Scene::serialize()
317 {
318 json["camera"] = m_camera.serialize();
319 json["physics"] = nlohmann::json::object();
320 auto& physics = json.at("physics");
321
322 auto gravity = m_b2world.GetGravity();
323 physics["gravity"]["x"] = gravity.x;
324 physics["gravity"]["y"] = gravity.y;
325
326 physics["allow_sleeping"] = m_b2world.GetAllowSleeping();
327 physics["allow_autoclearforces"] = m_b2world.GetAutoClearForces();
328 physics["velocity_iterations"] = m_velocity_iterations;
329 physics["position_iterations"] = m_position_iterations;
330 json["name"] = m_name;
331 json["ldtk_world"] = m_world.file();
332 json["current_map"] = m_world.get_active() ? m_world.get_active()->name() : "";
333 nlohmann::json json = "{}"_json;
334 json["camera"] = m_camera.serialize();
335 json["entities"] = nlohmann::json::array();
336
337 auto& em = core::ServiceLocator<meta::EntityMeta>::ref();
338
339 for (const auto& [entity] : m_registry.m_entt.view<entt::entity>(entt::exclude<flags::DenySerialization>).each())
340 {
341 json["entities"].push_back(em.serialize_entity(entity, m_registry.m_entt));
342 }
343
344 json["physics"] = nlohmann::json::object();
345 auto& physics = json.at("physics");
346
347 auto gravity = m_b2world.GetGravity();
348 physics["gravity"]["x"] = gravity.x;
349 physics["gravity"]["y"] = gravity.y;
350
351 physics["allow_sleeping"] = m_b2world.GetAllowSleeping();
352 physics["allow_autoclearforces"] = m_b2world.GetAutoClearForces();
353 physics["velocity_iterations"] = m_velocity_iterations;
354 physics["position_iterations"] = m_position_iterations;
355 json["name"] = m_name;
356 json["ldtk_world"] = m_world.file();
357 json["current_map"] = m_world.get_active() ? m_world.get_active()->name() : "";
358
359 nlohmann::json json = "{}"_json;
360 json["name"] = m_name;
361
362 json["systems"] = nlohmann::json::object();
363 for (auto i = 0; i < m_systems.size(); i++)
364 {
365 json["systems"][std::to_string(i)] = m_systems[i]->id();
366 }
367
368 return json;
369 }
370
371 void Scene::deserialize(const nlohmann::json& json)
372 {
373 m_name = json.at("name");
374
375 const auto& systems = json.at("systems");
376 m_systems.reserve(systems.size());
377 for (const auto& [index, name] : systems.items())
378 {
379 add_system(name.get<std::string>());
380 }
381
382 m_camera.deserialize(json.at("camera"));
383 auto& em = core::ServiceLocator<meta::EntityMeta>::ref();
384
385 const auto& physics = json.at("physics");
386 const auto& gravity = physics.at("gravity");
387
388 m_b2world.SetGravity({gravity.at("x"), gravity.at("y")});
389 m_b2world.SetAllowSleeping(physics.at("allow_sleeping"));
390 m_b2world.SetAutoClearForces(physics.at("allow_autoclearforces"));
391 m_velocity_iterations = physics.at("velocity_iterations");
392 m_position_iterations = physics.at("position_iterations");
393
394 if (load_world(json.at("ldtk_world")))
395 {
396 m_world.set_active(json.at("current_map"));
397 }
398 m_camera.deserialize(json.at("camera"));
399 auto& em = core::ServiceLocator<meta::EntityMeta>::ref();
400
401 m_registry.clear();
402
403 const auto& physics = json.at("physics");
404 const auto& gravity = physics.at("gravity");
405
406 m_b2world.SetGravity({gravity.at("x"), gravity.at("y")});
407 m_b2world.SetAllowSleeping(physics.at("allow_sleeping"));
408 m_b2world.SetAutoClearForces(physics.at("allow_autoclearforces"));
409 m_velocity_iterations = physics.at("velocity_iterations");
410 m_position_iterations = physics.at("position_iterations");
411
412 const auto& entity_json = json.at("entities");
413 for (const auto& data : entity_json)
414 {
415 const auto entity = em.deserialize_entity(data, m_registry.m_entt);
416
417 if (!m_registry.m_entt.all_of<components::Tag>(entity))
418 {
419 auto& tag = m_registry.m_entt.emplace<components::Tag>(entity);
420 tag.m_tag = "Untagged";
421 }
422 }
423
424 m_name = json.at("name");
425
426 if (load_world(json.at("ldtk_world")))
427 {
428 m_world.set_active(json.at("current_map"));
429 }
430 }
431
432 */
433} // namespace galaxy
Class for making creating and managing entities easier.
void on_push() override
When scene is pushed to the stack.
Definition Scene.cpp:46
virtual ~Scene() noexcept
Destructor.
Definition Scene.cpp:42
void update(EntityManager &em)
Process events and updates.
Definition Scene.cpp:250
void on_pop() override
When scene is popped from the stack.
Definition Scene.cpp:50
void on_event(SDL_Event &event)
Handle an event for a scene.
Definition Scene.cpp:58
SystemManager m_sysman
Systems only used by this scene.
Definition Scene.hpp:98
void render()
Render scene.
Definition Scene.cpp:261
SystemManager & sys_man() noexcept
Get system manager.
Definition Scene.cpp:289
Scene()=delete
Constructor.
A state to use in a finite state machine.
Definition State.hpp:19
Manages the systems assigned to it.
void update(EntityManager &em, Scene *scene)
Process all systems.
Application.hpp galaxy.