Window Module
The Window module manages the application window, OpenGL context, and user input handling. It provides the foundation for rendering and user interaction in Astra applications.
Purpose
The Window module provides:
- Window creation and management
- OpenGL context initialization via GLFW and GLAD
- Input event handling (keyboard and mouse movement)
- Frame timing via the
Timesingleton - Window state management (open/close, resize, headless mode)
Key Components
Window Class
The core Window class (namespace astralix) manages the application window and its properties.
Key Methods:
create(id, title, width, height, headless)- Static factory; creates and returns aRef<Window>start()- Creates the GLFW window, initializes the OpenGL context (GLAD), and registers GLFW callbacksupdate()- Polls GLFW events and processes pending key releasesswap()- Resets mouse delta, destroys released-key state, and callsglfwSwapBufferswidth()/height()- Return current window dimensions asintid()- Returns theWindowIDfor this windowtitle()- Returns the window title stringis_open()- Returnstruewhile the GLFW window should not closeclose()- Terminates GLFWvalue()- Returns the underlyingGLFWwindow*mouse()- ReturnsRef<input::Mouse>for the window's mouse statekeyboard()- ReturnsRef<input::Keyboard>for the window's keyboard state
Constructor parameters:
Window(WindowID& id, std::string& title, int& width, int& height, bool headless);The headless flag suppresses GLFW window visibility and skips input callbacks, which is useful for headless/testing modes.
WindowManager
WindowManager is a singleton (extends BaseManager<WindowManager>) that tracks all windows and provides the concept of an active window. Access it via the inline helper window_manager().
Key Methods:
start()/update()/swap()/end()- Lifecycle forwarding to all managed windowsis_open()- Returnstruewhile the active window is openload_window(window)/load_windows({...})- Register one or more windowsget_window_by_id(id)- Look up a window byWindowIDactive_window()- ReturnsRef<Window>for the currently active windowset_active_window_by_id(id)- Switch the active windowresize(width, height)- Resize the active window
Convenience macros:
ACTIVE_WINDOW_WIDTH() // active window pixel width
ACTIVE_WINDOW_HEIGHT() // active window pixel heightInput System
Input is exposed through free functions in the astralix::input namespace, all operating on the active window via window_manager(). There is no static Input class.
Keyboard:
input::IS_KEY_DOWN(input::KeyCode keycode) // true while key is held
input::IS_KEY_RELEASED(input::KeyCode keycode) // true on the frame the key was releasedMouse:
input::MOUSE_DELTA() // returns Mouse::Position{double x, double y} - accumulated delta since last swap
input::HAS_MOUSE_MOVED() // true if mouse moved since last swap
input::SET_MOUSE_POSITION(Mouse::Position& pos) // manually set mouse positionMouse button state and scroll are not tracked by this module.
Time Class
Frame timing is provided by the Time singleton, separate from the Window class.
Time::init(); // must be called once before use
Time* t = Time::get();
t->update(); // call each frame (uses glfwGetTime() internally)
float dt = t->get_deltatime(); // seconds elapsed since last update()
float now = t->get_current_time(); // current time in secondsThere is no GetFrameCount() method and no frame-count tracking.
Architecture
GLFW Integration
Astra uses GLFW for cross-platform window management and OpenGL context creation:
// In namespace astralix
class Window {
public:
static Ref<Window> create(WindowID& id, std::string& title,
int& width, int& height, bool headless);
void start(); // creates GLFW window + initializes OpenGL via GLAD
void update(); // glfwPollEvents + key release processing
void swap(); // mouse delta reset + glfwSwapBuffers
GLFWwindow* value() const noexcept;
int width() const noexcept;
int height() const noexcept;
// ...
private:
GLFWwindow* m_value;
int m_width, m_height;
std::string m_title;
WindowID m_id;
Ref<input::Keyboard> m_keyboard;
Ref<input::Mouse> m_mouse;
bool m_headless;
};The OpenGL context is initialized directly inside Window::start() via gladLoadGLLoader. There is no separate GraphicsContext abstraction in this module.
Event System
The Window module dispatches events through the engine-level EventDispatcher and EventScheduler. There is no SetEventCallback method on Window.
Actual event types defined in this module:
| Event class | Namespace | Fields |
|---|---|---|
KeyPressedEvent | astralix::input | KeyCode key_code, WindowID window_id |
KeyReleasedEvent | astralix::input | KeyCode key_code, WindowID window_id |
MouseEvent | astralix | double x, double y (absolute cursor position) |
MouseEvent is fired only when the cursor moves and the mouse is not in "view mode" (cursor captured). Mouse button press/release and scroll events are not implemented.
Window resize is handled internally by a GLFW framebuffer-size callback (Window::resizing) that updates m_width/m_height and calls glViewport. There is no WindowResizeEvent or WindowCloseEvent class.
Key Features
Window Creation
// Create a window
WindowID id = /* your GUID */;
std::string title = "Astra Game";
int width = 1920, height = 1080;
Ref<Window> window = Window::create(id, title, width, height, /*headless=*/false);
// Register with the manager and make it active
window_manager()->load_window(window);
window_manager()->set_active_window_by_id(id);
// Initialize the GLFW window and OpenGL context
window->start();Keyboard Input Polling
Check key state each frame using the free-function API:
void update() {
if (input::IS_KEY_DOWN(input::KeyCode::W)) {
MoveForward();
}
if (input::IS_KEY_DOWN(input::KeyCode::S)) {
MoveBackward();
}
if (input::IS_KEY_RELEASED(input::KeyCode::Escape)) {
// Key was released this frame
}
}Mouse Input Polling
Retrieve mouse movement delta each frame:
void update() {
if (input::HAS_MOUSE_MOVED()) {
auto delta = input::MOUSE_DELTA(); // Mouse::Position{double x, double y}
RotateCamera(delta.x, delta.y);
}
}Frame Timing
// Initialize once at startup
Time::init();
// Each frame
Time::get()->update();
float deltaTime = Time::get()->get_deltatime();
float elapsed = Time::get()->get_current_time();Cursor Capture
The Window automatically toggles cursor capture when the Escape key is released. This is handled internally by Window::toggle_view_mouse. There is no public SetCursorMode API; cursor behavior is controlled via this built-in Escape-key toggle.
While the cursor is captured (GLFW_CURSOR_DISABLED), mouse events are suppressed. When capture is released (GLFW_CURSOR_NORMAL), MouseEvent is fired on cursor movement.
VSync
VSync is not configurable through the Window API. GLFW swap-interval control is not exposed; buffer swapping is performed unconditionally in Window::swap().
Integration with Other Modules
With the Application/Engine Loop
// Startup
Time::init();
window_manager()->load_window(Window::create(id, title, width, height, false));
window_manager()->set_active_window_by_id(id);
window_manager()->active_window()->start();
// Main loop
while (window_manager()->is_open()) {
Time::get()->update();
float deltaTime = Time::get()->get_deltatime();
window_manager()->update(); // poll events, release keys
// Game/editor update logic
OnUpdate(deltaTime);
// Render ...
window_manager()->swap(); // reset mouse delta, swap buffers
}With the Editor Module
The Editor (class Editor, not EditorLayer) listens to input::KeyPressedEvent and MouseEvent through the EventDispatcher, relying on the same IS_KEY_DOWN / MOUSE_DELTA functions for camera and viewport interaction.
Input Events
Keyboard Events
// astralix::input namespace
class KeyPressedEvent : public Event {
KeyCode key_code;
WindowID window_id;
};
class KeyReleasedEvent : public Event {
KeyCode key_code;
WindowID window_id;
};Key events are scheduled via EventScheduler with SchedulerType::POST_FRAME.
Mouse Events
// astralix namespace
struct MouseEvent : public Event {
double x; // absolute cursor x
double y; // absolute cursor y
};Mouse button pressed/released and scroll events are not implemented in this module.
Key Codes
Key codes are defined as a scoped enum in astralix::input::KeyCode. Values match GLFW constants directly:
namespace astralix::input {
enum class KeyCode : int {
Space = 32,
A = 65, B = 66, /* ... */ W = 87, /* ... */ Z = 90,
Escape = 256,
Left = 263, Up = 265, Down = 264, Right = 262,
LeftShift = 340, LeftControl = 341, LeftAlt = 342,
// ... full set mirrors glfw3.h
};
}Usage:
input::IS_KEY_DOWN(input::KeyCode::W)
input::IS_KEY_RELEASED(input::KeyCode::Escape)There is no Mouse::Button* namespace or mouse button state tracking in this module.
File Locations
src/modules/window/
├── window.hpp # Window class declaration
├── window.cpp # Window implementation
├── time.hpp # Time singleton declaration
├── time.cpp # Time singleton implementation
├── events/
│ ├── key-codes.hpp # KeyCode enum class
│ ├── key-event.hpp # KeyPressedEvent, KeyReleasedEvent, KeyboardListener
│ ├── keyboard.hpp # Keyboard class (key state tracking)
│ ├── keyboard.cpp
│ ├── mouse.hpp # Mouse class (position delta tracking)
│ ├── mouse.cpp
│ ├── mouse-event.hpp # MouseEvent struct
│ └── mouse-listener.hpp # MouseListener class
└── managers/
├── window-manager.hpp # WindowManager singleton + input free functions
└── window-manager.cppRelated Modules
- Application - Creates and manages the Window lifecycle
- Engine - Receives input for game systems
- Editor - Uses window input for editor UI
Best Practices
- Single Active Window: Use
WindowManagerto track windows and set one as active before calling input free functions - Call
start()after registration: Register the window withWindowManagerbefore callingWindow::start()so the manager can resolve windows during GLFW callbacks - Update
Timeeach frame: CallTime::get()->update()at the top of the game loop before querying delta time - Handle resize via GLFW callback: Window resize is handled internally;
m_width/m_heightare always up to date afterupdate() - Mouse delta is frame-scoped:
MOUSE_DELTA()accumulates betweenswap()calls; always read it before callingwindow_manager()->swap()
Performance Considerations
IS_KEY_DOWN/IS_KEY_RELEASEDare O(1) hash-map lookups on theKeyboardobject- Mouse delta is reset to zero every
swap()call - always consume it before swapping Time::get()->update()usesglfwGetTime()which is a thin OS timer query- There is no built-in frame-rate cap; add VSync or a sleep if needed at the application level
Common Patterns
Input Handling in a Player Controller
class PlayerController {
void ProcessInput(float deltaTime) {
glm::vec3 movement(0.0f);
if (input::IS_KEY_DOWN(input::KeyCode::W))
movement.z += 1.0f;
if (input::IS_KEY_DOWN(input::KeyCode::S))
movement.z -= 1.0f;
if (input::IS_KEY_DOWN(input::KeyCode::A))
movement.x -= 1.0f;
if (input::IS_KEY_DOWN(input::KeyCode::D))
movement.x += 1.0f;
if (glm::length(movement) > 0.0f) {
movement = glm::normalize(movement);
MovePlayer(movement * speed * deltaTime);
}
}
};Camera Rotation from Mouse Delta
void UpdateCamera(float deltaTime) {
if (input::HAS_MOUSE_MOVED()) {
auto delta = input::MOUSE_DELTA();
camera.Yaw += static_cast<float>(delta.x) * sensitivity;
camera.Pitch += static_cast<float>(delta.y) * sensitivity;
}
}Headless Mode
// Create a window that is invisible and has no input callbacks
WindowID id = /* guid */;
std::string title = "headless";
int w = 1, h = 1;
auto window = Window::create(id, title, w, h, /*headless=*/true);
window_manager()->load_window(window);
window_manager()->set_active_window_by_id(id);
window->start();