VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
Engine.cpp
1// engine.cpp
2#include "Engine.hpp"
3#include "SDL3/SDL_events.h"
4
7#include "components/PathUtils.hpp"
8#include "components/EngineCommands.hpp"
9
12
15#include "components/backends/vulkan/PhysicsDebug.hpp"
16
18#include "components/UtilitySystem.hpp"
20
21
22#include <cstdint>
23#include <filesystem>
24#include <memory>
25
26#include "VexBuildVersion.hpp"
27
28namespace vex {
29
31 return VEX_VERSION_MAJOR;
32 }
33
35 return VEX_VERSION_MINOR;
36 }
37
39 return VEX_VERSION_PATCH;
40 }
41
43 return VEX_VERSION_STRING;
44 }
45
46Engine::Engine(const char* title, int width, int height, GameInfo gInfo) {
47 std::filesystem::current_path(GetExecutableDir());
48 m_gameInfo = gInfo;
49 if(m_gameInfo.versionMajor == 0 && m_gameInfo.versionMinor == 0 && m_gameInfo.versionPatch == 0){
50 log("Project version not set!");
51 }
52
53 log("Creating window..");
54 m_window = std::make_shared<Window>(title, width, height);
55 m_resolutionManager = std::make_unique<ResolutionManager>(m_window->GetSDLWindow());
56
57 #ifdef __linux__
58 const char* driver = SDL_GetCurrentVideoDriver();
59 if (driver && std::string(driver) == "wayland") {
60 m_isWayland = true;
61 log("Wayland detected: Enforcing Software VSync strategy.");
62 }
63 #endif
64
65 log("Initializing virtual file system..");
66 m_vfs = std::make_shared<VirtualFileSystem>();
67 m_vfs->initialize(GetExecutableDir().string());
68
69 std::string defaultUserDataDir = std::string(SDL_GetUserFolder(SDL_Folder::SDL_FOLDER_DOCUMENTS) + gInfo.projectName);
70 SetUserDataDir(defaultUserDataDir);
71 //vex::log("Setting user data dir: %s", defaultUserDataDir.c_str());
72
73 m_physicsSystem = std::make_unique<PhysicsSystem>(m_registry);
74 m_physicsSystem->init();
75
76 m_audioSystem = std::make_unique<AudioSystem>(m_registry);
77 m_audioSystem->Init(m_vfs.get());
78
79 auto renderRes = m_resolutionManager->getRenderResolution();
80 log("Initializing Vulkan interface...");
81 m_interface = std::make_unique<Interface>(m_window->GetSDLWindow(), renderRes, m_gameInfo, m_vfs.get());
82 m_imgui = std::make_unique<VulkanImGUIWrapper>(m_window->GetSDLWindow(), *m_interface->getContext());
83 m_imgui->init();
84
85 vex::DebugConsole::Get().Init();
86
87 log("Initializing engine components...");
88
89 m_inputSystem = std::make_unique<InputSystem>(m_registry, m_window->GetSDLWindow());
90 m_sceneManager = std::make_unique<SceneManager>();
91
93
94 RegisterEngineCommands(this);
95 log("Engine initialized successfully");
96}
97
98const char* Engine::GetBuildHash() {
99 return VEX_ENGINE_BUILD_ID;
100 }
101
103 return m_sceneManager.get();
104}
105
107 return m_interface.get();
108}
109
110std::shared_ptr<VexUI> Engine::createVexUI(){
111 return std::make_shared<VexUI>(*m_interface->getContext(), m_vfs.get(), m_interface->getResources(), m_resolutionManager.get());
112}
113
114void Engine::run(std::function<void()> onUpdateLoop) {
115 Uint64 lastTime = SDL_GetPerformanceCounter();
116
117 while (m_running) {
118 Uint64 frameStart = SDL_GetPerformanceCounter();
119 if (onUpdateLoop) onUpdateLoop();
120
121 SDL_Event event;
122 while (SDL_PollEvent(&event)) {
123 processEvent(event, m_deltaTime);
124 m_imgui->processEvent(&event);
125 vex::View<UiComponent> uiView(m_registry);
126 uiView.each([&event](vex::Entity entity, UiComponent& uiComp) {
127 if(uiComp.m_vexUI->isInitialized()){
128 uiComp.m_vexUI->processEvent(event);
129 }
130 });
131 switch (event.type) {
132 case SDL_EVENT_GAMEPAD_ADDED:
133 SDL_OpenGamepad(event.gdevice.which);
134 log("Gamepad connected and opened.");
135 break;
136 case SDL_EVENT_QUIT:
137 m_running = false;
138 break;
139 case SDL_EVENT_DID_ENTER_FOREGROUND:
140 log("Binding window to Vulkan...");
141 m_interface->bindWindow(m_window->GetSDLWindow());
142 m_internally_paused = false;
143 break;
144 case SDL_EVENT_WILL_ENTER_BACKGROUND:
145 m_interface->unbindWindow();
146 m_internally_paused = true;
147 break;
148 case SDL_EVENT_WINDOW_RESIZED:
149 m_resolutionManager->update();
150 //auto renderRes = m_resolutionManager->getRenderResolution();
151 //m_interface->setRenderResolution(renderRes);
152 break;
153 }
154 }
155
156 if (!m_running) break;
157
158 vex::View<TransformComponent> transformView(m_registry);
159 transformView.each([this](vex::Entity entity, TransformComponent& transform) {
160 if(!transform.isReady()){
161 transform.setRegistry(m_registry);
162 }
163 });
164
165 update(m_deltaTime);
166
167 float targetFps = (float)m_targetFps;
168
169 #ifdef __linux__
170 if (m_vsyncEnabled && m_isWayland) {
171 targetFps = m_window->getRefreshRate();
172 }
173 #endif
174
175 if (targetFps > 0) {
176 float targetFrameTime = 1000.0f / targetFps;
177
178 Uint64 frameEnd = SDL_GetPerformanceCounter();
179 float elapsedMS = (frameEnd - frameStart) / (float)SDL_GetPerformanceFrequency() * 1000.0f;
180
181 if (elapsedMS < targetFrameTime) {
182 SDL_Delay(static_cast<Uint32>(targetFrameTime - elapsedMS));
183 }
184 }
185
186 Uint64 now = SDL_GetPerformanceCounter();
187 m_deltaTime = (float)((now - lastTime) / (float)SDL_GetPerformanceFrequency());
188 lastTime = now;
189 }
190
191 if (m_interface) {
192 log("Engine shutdown requested. Waiting for GPU to finish...");
193 m_interface->WaitForGPUToFinish();
194 }
195}
196
198 if (m_interface) {
199 m_interface->WaitForGPUToFinish();
200 }
201}
202
204 m_targetFps = fps;
205}
206
207void Engine::setVSync(bool enabled) {
208 if (m_vsyncEnabled == enabled) return;
209 m_vsyncEnabled = enabled;
210
211 if (m_interface) {
212 m_interface->setVSync(enabled);
213 }
214}
215
216bool Engine::getVSync() const {
217 return m_vsyncEnabled;
218}
219
220Engine::~Engine() {
221 m_audioSystem->Shutdown();
222 m_audioSystem.reset();
223 if (m_physicsSystem) {
224 m_physicsSystem->shutdown();
225 m_physicsSystem.reset();
226 }
227 m_imgui.reset();
228 m_interface.reset();
229 m_inputSystem.reset();
230 m_window.reset();
231 SDL_Quit();
232}
233
235 log("Engine initialization handed of to Editor");
236}
237
239 m_resolutionManager->setMode(mode);
240 m_resolutionManager->update();
241 //auto renderRes = m_resolutionManager->getRenderResolution();
242 //m_interface->setRenderResolution(renderRes);
243}
244
246 m_interface->setEnvironment(settings);
247}
248
250 return m_interface->getEnvironment();
251}
252
253void Engine::setFullscreen(bool enabled, bool exclusive) {
254 if (m_window) {
255 m_window->setFullscreen(enabled, exclusive);
256 }
257}
258
260 return m_window ? m_window->isFullscreen() : false;
261}
262
264 lastLoadedScenes = getSceneManager()->GetAllSceneNames();
265}
266
267void Engine::processEvent(const SDL_Event& event, float deltaTime) {
268 m_inputSystem->processEvent(event, deltaTime);
269}
270
271void Engine::update(float deltaTime) {
272 m_inputSystem->update(deltaTime);
273
274 auto cameraEntity = getCamera();
275 if (cameraEntity != vex::NULL_ENTITY) {
276 m_audioSystem->Update(cameraEntity);
277 }
278
279 if(m_frame > 0){
280
281 vex::View<UiComponent> uiView(m_registry);
282 uiView.each([this, deltaTime](vex::Entity entity, UiComponent& uiComp) {
283 if(!uiComp.m_vexUI->isInitialized()){
284 uiComp.m_vexUI->init();
285 uiComp.m_vexUI->update(deltaTime);
286 }
287 });
288
289
290 if (m_paused && deltaTime == 0.0f) deltaTime = 0.016f;
291 ProcessParticles(m_registry, deltaTime);
292 if(!(m_paused || m_internally_paused)){
293 ProcessUtilityComponents(m_registry, deltaTime, *this);
294 m_sceneManager->scenesUpdate(deltaTime);
295 m_physicsSystem->update(deltaTime);
296 }
297 }else{
298
299 vex::View<UiComponent> uiView(m_registry);
300 uiView.each([this, deltaTime](vex::Entity entity, UiComponent& uiComp) {
301 if(!uiComp.m_vexUI->isInitialized()){
302 uiComp.m_vexUI->init();
303 uiComp.m_vexUI->update(deltaTime);
304 }
305 });
306
307 beginGame();
308 }
309
310 if(!m_internally_paused){
311 render();
312 m_frame++;
313 }
314}
315
318 //log("Render function called");
319 auto renderRes = m_resolutionManager->getRenderResolution();
320 auto cameraEntity = getCamera();
321
322 if (cameraEntity == vex::NULL_ENTITY) {
323 return;
324 }
325
326 //std::cout << "renderRes x:" << renderRes.x << ", y:" << renderRes.y << std::endl;
327
328 //log("Calling Renderer::renderFrame()");
329 try{
330 vex::SceneRenderData renderData;
331
332 if (!m_interface->getRenderer().beginFrame(renderRes, renderData)) {
333 return;
334 }
335
336 #if DEBUG
337 const std::vector<DebugVertex>* debugLines = nullptr;
338 if(m_renderPhysicsDebug) {
339 auto* dbg = m_interface->getPhysicsDebug();
340 dbg->Clear();
341 m_physicsSystem->setDebugRenderer(dbg);
342 m_physicsSystem->drawDebug();
343 debugLines = &dbg->GetLines();
344 }
345 m_interface->getRenderer().renderScene(renderData, cameraEntity, m_registry, m_frame, debugLines);
346 #else
347 m_interface->getRenderer().renderScene(renderData, cameraEntity, m_registry, m_frame);
348 #endif
349
350 m_interface->getRenderer().composeFrame(renderData, *m_imgui, false);
351 m_interface->getRenderer().endFrame(renderData);
352 } catch (const std::exception& e) {
353 log(LogLevel::ERROR, "Frame render failed");
355 }
356 //log("Frame Rendered");
357}
358
359}
Contains basic components like transform, camera, name components..
Contains main Engine class.
This file defines interface Class for vulkan backend.
This file defines SceneManager class.
Component you add to your GameObject to add ui elements to your game. ex. hud to player.
This file defines VirtualFileSystem and VPKStream classes.
This file defines class with Imgui for vulkan backend definition.
This file defines Window class.
void run(std::function< void()> onUpdateLoop=nullptr)
Starts and runs the main game loop.
Definition Engine.cpp:114
virtual void setFullscreen(bool enabled, bool exclusive=false)
Function to enable/disable fullscreen mode. with optional exclusive parameter.
Definition Engine.cpp:253
static int GetVersionMinor()
Returns the minor version of the engine.
Definition Engine.cpp:34
void prepareScenesForHotReload()
Prepares the engine for a hot-reload event.
Definition Engine.cpp:263
SceneManager * getSceneManager()
Returns pointer to SceneManager.
Definition Engine.cpp:102
static const char * GetVersionString()
Returns the version string of the engine.
Definition Engine.cpp:42
virtual void beginGame()
Internal virtual function for handling stuff right at the beginning of the game but after initializat...
Definition Engine.cpp:316
virtual void render()
Internal function that orchestrates the frame rendering process.
Definition Engine.cpp:317
void WaitForGpu()
Waits for the GPU to finish all pending operations.
Definition Engine.cpp:197
bool isFullscreen()
Function to check if fullscreen mode is enabled.
Definition Engine.cpp:259
Interface * getInterface()
Returns Interface, used internally.
Definition Engine.cpp:106
void setFrameLimit(int fps)
Sets the target frame rate limit.
Definition Engine.cpp:203
void setResolutionMode(ResolutionMode mode)
Sets the resolution mode and updates the resolution manager.
Definition Engine.cpp:238
static const char * GetBuildHash()
returns engine hash generated during build process.
Definition Engine.cpp:98
virtual void update(float deltaTime)
Internal function for handling updates; called every frame before rendering.
Definition Engine.cpp:271
static int GetVersionPatch()
Returns the patch version of the engine.
Definition Engine.cpp:38
environment getEnvironmentSettings()
Returns the current environment settings.
Definition Engine.cpp:249
Engine(const char *title, int width, int height, GameInfo gInfo)
Constructor for the Engine class.
Definition Engine.cpp:46
void setVSync(bool enabled)
Toggles VSync (Vertical Synchronization).
Definition Engine.cpp:207
std::shared_ptr< VexUI > createVexUI()
Creates and returns a shared pointer to a VexUI instance.
Definition Engine.cpp:110
vex::Entity getCamera()
Function returning the entity of the camera.
Definition Engine.hpp:93
void setEnvironmentSettings(environment settings)
Applies new global environment settings (lighting, shading) to the interface.
Definition Engine.cpp:245
virtual void processEvent(const SDL_Event &event, float deltaTime)
Internal virtual function for handling window/keyboard events.
Definition Engine.cpp:267
static int GetVersionMajor()
Returns the major version of the engine.
Definition Engine.cpp:30
bool getVSync() const
Returns the current state of VSync.
Definition Engine.cpp:216
Interface Class for vulkan backend.
Definition Interface.hpp:34
MeshManager & getMeshManager()
Getter for MeshManager.
Definition Interface.hpp:71
void init(Engine *engine)
Initialize the MeshManager.
SceneManager class implements scene management functionality like loading and unloading scenes,...
std::vector< std::string > GetAllSceneNames() const
Retrieves the names of all currently loaded scenes.
Provides iteration over entities that have all specified component types.
Definition View.hpp:17
void each(Func func)
Iterates over all entities with the specified component types.
Definition View.hpp:40
This file defines struct holding all vulkan data, like device, surface, swapchain,...
uint32_t Entity
Type alias representing a unique entity identifier in the ECS system.
Definition Types.hpp:11
std::filesystem::path VEX_EXPORT GetExecutableDir()
Retrieves the directory containing the current executable.
Definition PathUtils.cpp:37
ResolutionMode
Enumeration representing different resolution modes.
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
void VEX_EXPORT handle_exception(const std::exception &e)
Handles an exception based on build configuration.
constexpr Entity NULL_ENTITY
Special entity value indicating an invalid or null entity.
Definition Types.hpp:15
void VEX_EXPORT SetUserDataDir(const std::string &userDataDir)
Sets the current user data directory.
Definition PathUtils.cpp:22
void ProcessParticles(vex::Registry &registry, float deltaTime)
Processes CPU-side particle simulation and prepares GPU data.
this struct contains information about the game. like project name and version.
Definition GameInfo.hpp:15
Data structure to pass state between render stages.
Definition Renderer.hpp:57
Struct containing transform data and methods.
Struct containing VexUI class.
This struct is used to hold all environment settings. eg. shading details or lighting setup.