11#include "GLFW/glfw3.h"
13#include "backends/imgui_impl_glfw.h"
14#include "backends/imgui_impl_opengl3.h"
15#include "graphics/GraphicsAPI.h"
18#include "physics/PhysicsManager.h"
19#include "render/RenderQueue.h"
20#include "scene/components/CameraComponent.h"
24void KeyCallback(GLFWwindow *window,
int key,
int,
int action,
int)
27 if (action == GLFW_PRESS)
30 }
else if (action == GLFW_RELEASE)
32 inputManager.SetKeyPressed(
static_cast<Key>(key),
false);
39 if (action == GLFW_PRESS)
42 }
else if (action == GLFW_RELEASE)
44 inputManager.SetMouseButtonPressed(
static_cast<MouseButton>(button),
false);
54 vec2 currentPos(
static_cast<f32>(xpos),
static_cast<f32>(ypos));
55 inputManager.SetMousePositionCurrent(currentPos);
56 inputManager.SetMousePositionChanged(
true);
67 LOG_INFO(
"Engine::Init requested (%dx%d)", width, height);
76 glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
80 m_application->RegisterTypes();
89 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
90 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
91 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
95 if (m_window ==
nullptr)
101 LOG_INFO(
"Window created (%dx%d)", width, height);
107 glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
109 glfwMakeContextCurrent(m_window);
111 glewExperimental = GL_TRUE;
112 GLenum glewStatus = glewInit();
113#ifdef GLEW_ERROR_NO_GLX_DISPLAY
114 if (glewStatus == GLEW_ERROR_NO_GLX_DISPLAY)
116 glewStatus = GLEW_OK;
119 if (glewStatus != GLEW_OK)
121 LOG_ERROR(
"Failed to initialize GLEW: %s",
reinterpret_cast<const char *
>(glewGetErrorString(glewStatus)));
125 while (glGetError() != GL_NO_ERROR)
128 LOG_INFO(
"GLEW initialized (GL %s)",
reinterpret_cast<const char *
>(glGetString(GL_VERSION)));
131 if (!m_rendererBackend->Init())
133 LOG_ERROR(
"Renderer backend init failed");
137 m_physicsManager.
Init();
138 if (!m_audioManager.
Init())
144 if (!m_postProcess.
Init())
146 LOG_ERROR(
"PostProcess Init failed — outline pass disabled");
149 if (!m_editor.
Init(m_window))
153 if (!m_spriteRenderer.
Init())
157 m_particleSystem.
Init();
161 bool appOk = m_application->Init();
169 LOG_INFO(
"Application initialized");
178 LOG_ERROR(
"Engine::Run called with no application");
182 LOG_INFO(
"Engine main loop starting");
183 m_lastTimePoint = std::chrono::steady_clock::now();
185 while ((glfwWindowShouldClose(m_window) == 0) && !m_application->NeedsToBeClosed())
190 auto now = std::chrono::steady_clock::now();
191 float deltaTime = std::chrono::duration<float>(now - m_lastTimePoint).count();
192 m_lastTimePoint = now;
194 float scaledDt = m_paused ? 0.0F : deltaTime * m_timeScale;
196 m_physicsManager.
Update(scaledDt);
197 m_application->Update(scaledDt);
198 m_particleSystem.
Update(scaledDt);
203 int winW = 0, winH = 0;
204 glfwGetFramebufferSize(m_window, &winW, &winH);
212 else if (m_renderSettings.
pixelSize > 32)
224 m_sceneTarget.
Bind();
243 std::vector<LightData> lights;
245 f32 aspect =
static_cast<f32>(winW) /
static_cast<f32>(winH);
249 if (
auto cameraObject = m_currentScene->GetMainCamera())
255 cameraData.
viewMatrix = cameraComponent->GetViewMatrix();
257 cameraData.
position = cameraObject->GetWorldPosition();
258 cameraData.
nearPlane = cameraComponent->GetNearPlane();
259 cameraData.
farPlane = cameraComponent->GetFarPlane();
262 static bool warned =
false;
265 LOG_WARN(
"Main camera GameObject '%s' has no CameraComponent", cameraObject->GetName().c_str());
271 static bool warned =
false;
274 LOG_WARN(
"Scene has no main camera set — rendering with identity matrices");
279 lights = m_currentScene->CollectLight();
282 m_renderQueue.
Draw(m_graphicsAPI, cameraData, lights);
283 m_particleSystem.
Render(cameraData);
301 m_postProcess.
RunOutline(m_sceneTarget, cameraData);
322 if (runPostProcess && m_postProcess.
OutputTex() != 0)
333 const float instantFps = deltaTime > 0.0F ? 1.0F / deltaTime : 0.0F;
334 const float emaAlpha = 0.1F;
335 m_fpsSmoothed = (m_fpsSmoothed <= 0.0F)
337 : m_fpsSmoothed + (instantFps - m_fpsSmoothed) * emaAlpha;
338 m_fpsRefreshTimer += deltaTime;
339 if (m_fpsRefreshTimer >= 0.2F)
341 m_fpsDisplayed = m_fpsSmoothed;
342 m_fpsRefreshTimer = 0.0F;
346 std::snprintf(fpsBuf,
sizeof(fpsBuf),
"FPS %.0f %.2fms", m_fpsDisplayed,
347 m_fpsDisplayed > 0.0F ? 1000.0F / m_fpsDisplayed : 0.0F);
349 const float padding = 12.0F;
350 const float textSize = 22.0F;
351 const float boxWidth = textSize * 0.55F *
static_cast<float>(std::strlen(fpsBuf)) + padding * 2.0F;
352 const float boxHeight = textSize + padding;
354 vec2(boxWidth, boxHeight),
355 vec4(0.04F, 0.05F, 0.07F, 0.65F));
357 vec2(padding + padding * 0.5F + 1.0F,
358 padding + padding * 0.5F * 0.5F + 1.0F),
360 vec4(0.0F, 0.0F, 0.0F, 0.85F));
362 vec2(padding + padding * 0.5F,
363 padding + padding * 0.5F * 0.5F),
365 vec4(0.85F, 1.0F, 0.85F, 1.0F));
368 m_spriteRenderer.
Flush(winW, winH);
374 glfwSwapBuffers(m_window);
384 LOG_INFO(
"Engine::Destroy requested");
392 m_application->Destroy();
393 m_application.reset();
399 LOG_WARN(
"Engine::Destroy called with no application");
405 m_application.reset(app);
410 return m_application.get();
415 return m_inputManager;
420 return m_graphicsAPI;
425 return m_renderQueue;
430 m_currentScene.reset(scene);
435 return m_textureManager;
440 return m_audioManager;
445 return m_physicsManager;
450 return m_currentScene.get();
460void RenderLoadingFrameImpl(GLFWwindow *window,
const char *message,
float progress)
464 int winW = 0, winH = 0;
465 glfwGetFramebufferSize(window, &winW, &winH);
468 glClearColor(0.05F, 0.05F, 0.07F, 1.0F);
469 glClear(GL_COLOR_BUFFER_BIT);
471 ImGui_ImplOpenGL3_NewFrame();
472 ImGui_ImplGlfw_NewFrame();
475 const ImGuiViewport *vp = ImGui::GetMainViewport();
476 ImGui::SetNextWindowPos(ImVec2(vp->WorkPos.x + vp->WorkSize.x * 0.5F, vp->WorkPos.y + vp->WorkSize.y * 0.5F),
479 ImGui::SetNextWindowSize(ImVec2(420.0F, 0.0F), ImGuiCond_Always);
480 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0F, 24.0F));
481 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.10F, 0.10F, 0.13F, 1.0F));
482 ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.35F, 0.65F, 1.0F, 1.0F));
483 ImGui::Begin(
"##loading",
485 ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
486 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNav
487 | ImGuiWindowFlags_NoFocusOnAppearing);
489 ImGui::SetWindowFontScale(1.6F);
490 ImGui::TextUnformatted(message);
491 ImGui::SetWindowFontScale(1.0F);
494 float barFraction = (progress < 0.0F) ? -1.0F *
static_cast<float>(ImGui::GetTime()) : progress;
495 char overlay[16] =
"";
496 if (progress >= 0.0F)
498 std::snprintf(overlay,
sizeof(overlay),
"%d%%",
static_cast<int>(progress * 100.0F + 0.5F));
500 ImGui::ProgressBar(barFraction, ImVec2(-1.0F, 18.0F), progress >= 0.0F ? overlay :
"");
503 ImGui::PopStyleColor(2);
504 ImGui::PopStyleVar();
507 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
509 glfwSwapBuffers(window);
515 if (m_window ==
nullptr)
521 RenderLoadingFrameImpl(m_window, message, progress);
522 RenderLoadingFrameImpl(m_window, message, progress);
527 if (m_window ==
nullptr)
531 RenderLoadingFrameImpl(m_window, message, progress);
constexpr mnd::i32 kDefaultInternalHeight
constexpr const char * kDefaultWindowTitle
constexpr mnd::i32 kDefaultInternalWidth
Console logging macros for all engine and game code.
#define LOG_WARN(fmt,...)
#define LOG_INFO(fmt,...)
#define LOG_ERROR(fmt,...)
Interface that every runnable game or lab must implement.
Global audio backend wrapper.
bool Init()
Initialise the underlying miniaudio engine.
Perspective camera — provides view and projection matrices each frame.
void EndFrame()
Renders the ImGui draw data to the current framebuffer.
void Shutdown()
Tear down ImGui state. Call before destroying the GL context.
bool Init(GLFWwindow *window)
Initialise ImGui against the given GLFW window. Call once at startup.
void BeginFrame()
Call after glfwPollEvents.
void Draw()
Builds all panels (no GL state changes yet).
Singleton façade that drives the full engine lifecycle.
GraphicsAPI & GetGraphicsAPI()
Returns the low-level OpenGL wrapper used for all draw calls.
RenderQueue & GetRenderQueue()
Returns the per-frame command queue that batches and issues draw calls.
Scene * GetScene()
Returns the currently active scene, or nullptr if none is set.
InputManager & GetInputManager()
Returns the InputManager that tracks keyboard and mouse state.
FileSystem & GetFileSystem()
Returns the file system helper for asset-relative path resolution.
void SetScene(Scene *scene)
Replace the active scene (takes ownership).
bool Init(int width, int height)
Initialise the window, OpenGL context, and subsystems.
void Run()
Enter the blocking main loop.
Application * GetApplication()
Returns a raw pointer to the active application (owned by the engine).
AudioManager & GetAudioManager()
static Engine & GetInstance()
Returns the single Engine instance (created on first call).
void SetApplication(Application *app)
Transfer ownership of the application to the engine.
void DrawLoadingScreen(const char *message, float progress=-1.0F)
TextureManager & GetTextureManager()
Returns the TextureManager that caches loaded textures by path.
void UpdateLoadingProgress(float progress, const char *message)
Update the loading panel mid-load (single swap). Cheap to call per step.
PhysicsManager & GetPhysicsManager()
void Destroy()
Shut down the application and release all GL resources.
Resolves asset paths and loads files into memory.
OpenGL 3.3 Core Profile abstraction layer.
void ClearBuffers()
Clear the colour and depth buffers ready for the next frame.
void SetClearColor(float r, float g, float b, float a)
Set the colour that glClear() fills the framebuffer with.
void Update(f32 deltaTime)
Step every live particle, swap-erase dead ones.
void Render(const CameraData &cameraData)
Camera-aligned billboard pass. Call after the lit pass, before UI.
Owns the Bullet btDiscreteDynamicsWorld and all auxiliary collision structures (broadphase,...
void Update(float deltaTime)
Step the simulation by deltaTime seconds.
void Init()
Allocate broadphase, dispatcher, solver, and dynamics world. Call once.
void RunOutline(const RenderTarget &scene, const CameraData &cam)
Run the outline pass, sampling scene and writing to OutputTex().
Accumulates RenderCommands during Update and draws them in one pass.
void Draw(GraphicsAPI &graphicsAPI, const CameraData &cameraData, const std::vector< LightData > &lights)
Draw all submitted commands, then clear the queue.
static void BindDefault(int winW, int winH)
bool Create(int w, int h)
void Resize(int w, int h)
Container for the entire game object graph.
static void RegisterTypes()
Update all root objects (which recursively update their children).
void DrawText(const std::string &text, const vec2 &position, f32 pixelHeight, const vec4 &color=vec4(1.0F))
void DrawRect(const vec2 &position, const vec2 &size, const vec4 &color)
void Flush(int viewportWidth, int viewportHeight)
Path-keyed cache that prevents the same image from being uploaded twice.
Abstract base class for the user-defined game or lab application.
Lightweight data-transfer structs shared across subsystems.
Central singleton that owns and coordinates all engine subsystems.
glm::vec2 vec2
2-component float vector (e.g. UV coordinates, mouse position).
glm::vec4 vec4
4-component float vector (e.g. RGBA colour, homogeneous coords).
double f64
64-bit double — used for high-precision timing.
float f32
32-bit IEEE float — the standard GL scalar type.
BlitMode
Blit modes for BlitNearest.
@ SplatRed
Output (r,r,r,1) — used for visualising depth.
@ DecodeNrm
Output rgb as-is from a packed-normal texture (no remap).
@ Color
Sample RGB straight through (default).
void BlitNearest(GLuint srcTexture, int dstW, int dstH, BlitMode mode)
void CursorPositionCallback(GLFWwindow *window, f64 xpos, f64 ypos)
void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
void KeyCallback(GLFWwindow *window, int key, int, int action, int)
std::unique_ptr< RendererBackend > CreateOpenGLRendererBackend(GraphicsAPI &graphicsAPI)
Per-frame camera matrices and world-space position.
mat4 projectionMatrix
Camera → Clip space transform (perspective or ortho).
mat4 viewMatrix
World → Camera space transform (glm::lookAt result).
vec3 position
Camera world-space position, used for specular calculations.
f32 nearPlane
Frustum near distance — used by post passes for depth linearisation.
vec4 clearColor
RGBA value used by glClear at the start of each frame.
DebugView debugView
Which scene-target attachment to blit. Defaults to Color.
bool showFps
Draw FPS counter overlay in top-left corner.