Index

template<WindowImplementationConcept WindowImplementation = DefaultWindowImplementation, Dispatchable EventDispatcher = Dispatcher, template<typename> typename Renderer = DefaultRendererImplementation>
class Application
#include <application.hxx>

Provides the entry point for any Obscura game or application.

Template Parameters:
  • WindowImplementation – The implementation of the window to use. Defaults to DefaultWindowImplementation.

  • EventDispatcher – The dispatcher to use for the window. Defaults to obscura::Dispatcher.

Public Types

using WindowType = Window<WindowImplementation>

Public Functions

inline Application()
inline void run()

This will start the main loop. This is a blocking call.

inline void onTick([[maybe_unused]] const TickEvent &event)

Callback that is triggered with every main loop iteration. This callback updates the window. Don’t call this function manually.

Parameters:

event – The tick event.

inline void stopMainLoop()

This will stop the main loop and hence the application. Can only be called from another thread as the run function is a blocking call.

inline auto getWindow() const -> WindowType&
inline auto getMainLoop() const -> MainLoop<Dispatcher>&
inline auto getWindowEventEmitter() const -> auto&

Private Functions

inline void startMainLoop()

Private Members

std::unique_ptr<WindowType> window
std::unique_ptr<Renderer<WindowType>> renderer
std::unique_ptr<typename WindowImplementation::template EventEmitterType<Dispatcher>, typename WindowImplementation::template EventEmitterDeleterType<Dispatcher>> windowEventEmitter
MainLoop<Dispatcher> *mainLoop = {nullptr}
class ApplicationAlreadyRunningException : public std::exception

Private Functions

auto what() const noexcept -> const char* override
template<Dispatchable Dispatcher>
class AsyncLoop : public obscura::LoopBase<Dispatcher>

Public Functions

inline void run(const FPS &fps)
inline void stop()

Private Members

std::unique_ptr<std::thread> asyncThread
class BaseLoggerImpl
#include <logger_impl.hxx>

Base class for the logger implementation.

A logger should always be a singleton. That is, first create a logger class inheriting from this base class and then create a singleton of that class.

Subclassed by obscura::CoreLoggerImpl, obscura::LoggerImpl

Public Functions

explicit BaseLoggerImpl(const std::string &name)
BaseLoggerImpl(const std::string &name, spdlog::sink_ptr sink)
void addSink(spdlog::sink_ptr sink)
void setLevel(spdlog::level::level_enum level)
template<typename ...Args>
inline void info(const char *fmt, const Args&... args)
template<typename ...Args>
inline void warn(const char *fmt, const Args&... args)
template<typename ...Args>
inline void error(const char *fmt, const Args&... args)
template<typename ...Args>
inline void debug(const char *fmt, const Args&... args)
template<typename ...Args>
inline void trace(const char *fmt, const Args&... args)

Private Members

spdlog::logger backend
template<class Child>
class BaseLoopConfig

Public Functions

inline auto setMinFrameTime(float newMinFrameTime) -> Child&
inline auto setMaxFrameTime(float newMaxFrameTime) -> Child&

Protected Functions

inline void setBaseConfigParameters(LoopConfig &config) const

Protected Attributes

bool hasMinFrameTime = false
bool hasMaxFrameTime = false
float minFrameTime = 0
float maxFrameTime = 100
template<class Listener, class EventType, void (Listener::* CallbackPointer)(const EventType&)>
class CallbackWrapper

Public Static Functions

static inline void call(Listener *listener, const EventType &event)
template<EventDefinitionConcept Definition, EventDefinitionConcept... AdditionalDefinitions>
class ConfigurableDispatcher : public obscura::DispatcherBase<Definition>

The class provides an implementation for a dispatcher. It must be configured to be compatible with the event_system that are supposed to be dispatched. For that you must pass event definitions to the template parameters list. A Definition must satisfy the EventDefinitionConcept concept.

Template Parameters:
  • Definition – Class that satisfies EventDefinitionConcept concept

  • AdditionalDefinitions – Classes that satisfies EventDefinitionConcept concept

Subclassed by obscura::LoopBase< Dispatcher >

Public Functions

void dispatch()

Dispatches all enqueued events to the respective listeners.

template<class Listener, bool hasFoundMatchedConcept = false>
void registerListener(Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP})

Registers a listener with the dispatcher. The callbacks of the listener will be invoked when dispatch() is called.

Template Parameters:
  • Listener – Type of the listener

  • hasFoundMatchedConcept – Template parameter that indicates if the listener fits any of the configured definitions. The parameter is false by default and should not be manually changed.

Parameters:
  • listener – The listener that is registered with the dispatcher. Can be any object as long as it contains at least one of the callback defined via the event definitions. If the listener is not matching any event definition a compile error will be thrown. Each listener can have arbitrarily many supported callbacks.

  • listenerGroup – The listener group the listener should be registered for. Events can be dispatched to specific listener groups. The default listener listenerGroup is named “default”.

template<class Listener>
void unregisterListener(const Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP})

Removes a listener from the register of the dispatcher, i.e., event_system will not be dispatched to the respective listener anymore. Throws an KeyError when the listener could not be removed for the given group.

Template Parameters:

Listener – Type of the listener.

Parameters:

listener – Reference to the listener.

template<class Listener>
auto isListenerRegistered(const Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP}) -> bool
template<EventDefinitionConcept Definition>
class ConfigurableDispatcher<Definition> : public obscura::DispatcherBase<Definition>

Public Functions

void dispatch()
template<class Listener, bool hasFoundMatchedConcept = false>
void registerListener(Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP})
template<class Listener>
void unregisterListener(const Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP})
template<class Listener>
auto isListenerRegistered(const Listener &listener, const std::string &listenerGroup = std::string{DispatcherBase<Definition>::DEFAULT_LISTENER_GROUP}) -> bool
class CoreLogger : public obscura::Singleton<CoreLoggerImpl>
#include <logging.hxx>

The CoreLogger class is a singleton that provides a logging interface for the core of the library.

Can be used by calling CoreLogger::getInstance().info(“Hello, world!”). However, instead of using this singleton directly, it is recommended to use the logCoreInfo, logCoreWarn, logCoreError, logCoreDebug and logCoreTrace, since these functions are only called if logging is enabled.

class CoreLoggerImpl : public obscura::BaseLoggerImpl
#include <logger_impl.hxx>

Implementation of the logger for the core.

This class should not be used directly. Instead, use the CoreLogger singleton.

Public Functions

CoreLoggerImpl()
template<class App>
class DefaultApplicationListener
#include <application.hxx>

A default application listener that will close the window and stop the main loop when the window closed button is pressed. Without registering this listener, the application will not close by using the OS UI.

Template Parameters:

App – The application type. Should be of type obscura::Application.

Public Functions

inline explicit DefaultApplicationListener(App &application)
inline void onWindowClosed([[maybe_unused]] const WindowEvent &event)

Private Members

App *application
class Device

Public Functions

explicit Device(const Instance &instance)

Private Functions

auto setupPhysicalDevice() -> vk::raii::PhysicalDevice
auto setupLogicalDevice() -> vk::raii::Device
auto findGraphicsQueueFamilyIndex() -> uint32_t

Private Members

const Instance *instance
vk::raii::PhysicalDevice physicalDevice
vk::raii::Device logicalDevice

Private Static Functions

static auto logPhysicalDevices(const vk::raii::PhysicalDevices &physicalDevices) -> void
static auto selectPhysicalDevice(const vk::raii::PhysicalDevices &physicalDevices) -> const vk::raii::PhysicalDevice&
template<EventDefinitionConcept Definition, class ListenerIdType = uintptr_t>
class DispatcherBase

Subclassed by obscura::ConfigurableDispatcher< Definition, AdditionalDefinitions >, obscura::ConfigurableDispatcher< Definition >

Public Functions

void enqueue(typename Definition::Event &&event, const std::string &listenerGroup = std::string{DEFAULT_LISTENER_GROUP})

Enqueue an event in the dispatcher. The event is passed forward to the respective listener once dispatch() is called.

Parameters:
  • event – Can be any event, the dispatcher is configured for. The function only takes event_system that are defined for the dispatcher.

  • listenerGroup – The group of listeners the event should be dispatched to.

void enqueue(const typename Definition::Event &event, const std::string &listenerGroup = std::string{DEFAULT_LISTENER_GROUP})

Same as enqueue(Definition::Event&&, const std::string&) but the function takes a const reference of the event.

Parameters:
  • event – Can be any event, the dispatcher is configured for. The function only takes event_system that are defined for the dispatcher.

  • listenerGroup – The group of listeners the event should be dispatched to.

void enqueueForAllGroups(typename Definition::Event &&event)
void enqueueForAllGroups(const typename Definition::Event &event)
inline auto hasListenerForEvent(const typename Definition::Event&, const std::string &listenerGroup = std::string{DEFAULT_LISTENER_GROUP}) -> bool

Checks whether a listener was appended that a certain event can be dispatched to.

Parameters:

event – Any event the dispatcher is configured for.

Returns:

Whether a listener for an event is appended.

Public Static Attributes

static constexpr std::string_view DEFAULT_LISTENER_GROUP = {"default"}

Protected Types

using EventQueue = eventpp::EventQueue<std::string, void(const typename Definition::Event&)>

Protected Functions

void appendToEventQueue(typename Definition::Event &&event, const std::string &listenerGroup)

Given an event and an event queue, the function checks if the event queue has a listener registered for this event (if not a warning will be logged) and enqueues the event in the queue.

Parameters:
  • listenerGroup – Group of listeners the event will be dispatched to.

  • event – The event of type Definition::Event.

void appendToEventQueue(const typename Definition::Event &event, const std::string &listenerGroup)

Same as appendToEventQueue(Definition::Event&&, const std::string&) but with a const reference event.

Parameters:
  • listenerGroup – Listener listenerGroup to which the event shall be dispatched.

  • event – The event of type Definition::Event.

void checkIfHasListener(const std::string &listenerGroup)

Checks if a queue has any listener for the given listenerGroup.

Parameters:

listenerGroup – The listener listenerGroup.

template<class Listener>
void appendToListenerQueue(Listener &listener, const std::string &listenerGroup)

Append and register a listener with the event queue.

Template Parameters:

Listener – The listener type.

Parameters:
  • listener – The listener object.

  • listenerGroup – The group the listener should be registered with. Any event dispatched to this group will be forwarded to the listener.

template<class Listener>
auto removeFromListenerQueue(const Listener &listener, const std::string &listenerGroup) -> bool
template<class Listener>
auto isListenerRegisteredForDefinition(const Listener &listener, const std::string &listenerGroup) -> bool

Checks if a listener is already registered with a listenerGroup.

Template Parameters:

Listener – The listener type.

Parameters:
  • listener – The listener object.

  • listenerGroup – The group the listener is checked to be registered with.

Returns:

Whether the given listener was registered.

Protected Attributes

EventQueue eventQueue = {}

Private Members

ListenerRegistry<typename EventQueue::Handle, ListenerIdType> listenerRegistry = {}
class DispatcherBaseFixture : public testing::Test

Public Members

std::unique_ptr<DispatcherBase<KeyPressedDefinition>> dispatcherBase

Protected Functions

inline void SetUp() override
inline void TearDown() override
class DuplicateError : public std::runtime_error

Public Functions

explicit DuplicateError(const std::string &key)
class DynamicLoader

Public Functions

DynamicLoader()

Private Members

vk::DynamicLoader dynamicLoader
class Event
#include <event.hxx>

Base class for all event_system.

Subclassed by obscura::KeyEvent< EventCause::MouseClicked >, obscura::KeyEvent< compile_time_cause >, obscura::LoopStoppedEvent, obscura::MouseMovedEvent, obscura::MouseScrolledEvent, obscura::TickEvent, obscura::WindowEvent

Public Functions

inline Event(obscura::EventCategory category, obscura::EventCause cause)
inline auto getCategory() const -> obscura::EventCategory
inline auto getCause() const -> obscura::EventCause
inline auto getCode() const

Returns a unique code that is a combination of the event’s category and cause.

Returns:

The event’s code.

inline void setCategory(EventCategory eventCategory)
inline void setCause(EventCause eventCause)

Private Members

obscura::EventCategory category
obscura::EventCause cause
template<StringLiteral Name, class EventType, template<class Listener> class Callback>
struct EventDefinition

Public Types

using Event = EventType

Public Static Functions

template<class Listener>
static inline constexpr auto getCallback(Listener &listener) -> decltype(auto)
static inline constexpr auto getEventCode() -> std::size_t
static inline constexpr auto getName() -> std::string_view

Public Static Attributes

static constexpr obscura::EventCategory Category = Event::Category
static constexpr obscura::EventCause Cause = Event::Cause
template<class Listener>
static constexpr bool hasCallback = requires(Listener& listener, const EventType& event) { Callback<Listener>::call(&listener, event); }
class FakeWindow

Public Static Functions

static inline constexpr auto getVulkanExtensions()
class FPS

Public Functions

FPS()
template<class T> inline explicit requires std::is_convertible_v< T, float > FPS (T fps)
template<class TimeUnit>
inline auto toFrameTime() const -> TimeUnit
template<class TimeUnit>
inline auto framesPerTimeUnit() const -> float
inline auto framesPerSecond() const -> float
void set(float newFps)
template<class T> inline requires std::is_convertible_v< T, float > auto operator= (T newFps) -> FPS &
operator float() const
operator double() const

Public Static Functions

template<class TimeUnit>
static inline auto fromFrameTime(TimeUnit &&frameTime) -> FPS
template<class TimeUnit>
static inline auto fromDurationAndNumberOfFrames(TimeUnit duration, std::size_t numberOfFrames) -> FPS

Private Members

float fps
class FractionalLoopConfig : public obscura::BaseLoopConfig<FractionalLoopConfig>

Public Functions

auto build() const -> LoopConfig

Private Functions

explicit FractionalLoopConfig(float fraction)

Private Members

float fraction

Friends

friend class LoopConfig
template<Dispatchable Dispatcher, class Event>
class FrameDelayer

Public Functions

~FrameDelayer() = default
FrameDelayer(const FrameDelayer&) = delete
FrameDelayer &operator=(const FrameDelayer&) = delete
FrameDelayer(FrameDelayer&&) = delete
FrameDelayer &operator=(FrameDelayer&&) = delete
inline void onTick([[maybe_unused]] const TickEvent &tickEvent)

Private Functions

inline FrameDelayer(Dispatcher &dispatcher, Event &&event, std::size_t framesToWait)

Private Members

Event event
Dispatcher *dispatcher
std::size_t framesToWait

Friends

template<Dispatchable D, class E>
friend void emitDelayedEvent(D&, E &&event, std::size_t)
template<duration HorizonTimeUnit = std::chrono::seconds>
class FramePacer : public obscura::FrameProfiler<std::chrono::seconds>
#include <frame_pacer.hxx>

Responsible for pacing frames and reaching consisting frame times.

Template Parameters:

HorizonTimeUnit – See obscura::FrameProfiler for more information.

Public Functions

inline FramePacer()
inline void sleepRestOfFrameTime(const FPS &fps) const
template<duration TimeUnit>
inline void sleepForSinceLastTick(TimeUnit duration) const
template<duration HorizonTimeUnit = std::chrono::seconds>
class FrameProfiler : public obscura::Timer
#include <frame_profiler.hxx>

Class that profiles frame times. It can be used to receive the FPS or intervals between frames. It is an extension of obscura::Timer.

Template Parameters:

HorizonTimeUnit – Type of the time horizon for the FPS averaging. In order to measure the FPS it is necessary to provide a time window in which the frame times are averaged. This template parameter specifies the type of that duration.

Public Functions

inline explicit FrameProfiler(const HorizonTimeUnit &timePointsHorizon = std::chrono::seconds{2})

The constructor requires the time horizon for the FPS aggregation. Since the FPS measures how many frames there are per second, it must be specified over what time horizon the frames will be counted. A longer time horizon will be less sensible to outliers while a shorter horizon will be make frame time spikes more visible.

Parameters:

timePointsHorizon – Time horizon for FPS counting. Default: 2 seconds

inline void start()

Must be called before measuring any frame times.

inline void tick()

Should be called at the beginning of each frame.

inline void stop()

Stops the measurement. Calling this function is not required for cleaning up the frame profiler.

inline auto getFPS() const -> FPS

Returns FPS measured over the time point horizon.

Returns:

FPS

template<duration TimeUnit>
inline auto getFPS(const TimeUnit &aggregationTimeframe) -> FPS

Returns FPS measured over the given aggregation horizon. The given time frame cannot be longer than the specified time horizon in the constructor.

Template Parameters:

TimeUnit – The time unit for the aggregation time frame.

Parameters:

aggregationTimeframe – The aggregation time frame.

Returns:

FPS

inline auto getDelta() const -> float
Returns:

Frame time delta in seconds.

inline void setReferenceTimePoint()

Creates a reference point from where frame time computations are carried out.

This function should be called at the beginning of any frame time computations in order to guarantee the consistency of consecutive calls to aggregating function. All aggregate computations concerning frame times must have a rolling sample window. That sample window is carried out from either this measuring point or from the current time point. If a reference point is not set the sample window is changing with consecutive calls.

Note that you also have to set createNewReferencePoint to false in any function that requires reference points in order to use this reference point.

Example: tick - tick - sample window start - tick - tick - setReferenceTimePoint point/sample window end

inline auto getNumberOfFrameTimes() const -> std::size_t

Returns the number of frames within the time point horizon.

The time point horizon is set in the constructor. A frame is considered within the horizon if it intersects with the horizon.

Returns:

Number of frames.

template<duration TimeUnit>
inline auto getNumberOfFrameTimes(const TimeUnit &withinDuration, bool createNewReferencePoint = true) -> std::size_t

Returns the number of frames within the given duration.

A frame is considered within the duration if it intersects with it.

Template Parameters:

TimeUnit – The time unit for the duration.

Parameters:

withinDuration – The duration in which frames should be counted.

Returns:

Number of frames.

inline auto getFrameTimes() const -> std::list<TimePoint::duration>

Returns the frame times within the time point horizon.

The time point horizon is set in the constructor. A frame is considered within the horizon if it intersects with the horizon.

Returns:

List of frame times within the horizon.

template<duration FrameTimeUnit, duration CutOffTimeUnit>
inline auto getFrameTimes(const CutOffTimeUnit &withinDuration, bool createNewReferencePoint = true) -> std::list<FrameTimeUnit>

Returns the frame times within the given duration.

A frame is considered within the duration if it intersects with it.

Template Parameters:
  • TimeUnit – The time unit for the returned frame times.

  • CutOffTimeUnit – The time unit for the time window.

Parameters:
  • withinDuration – The duration in which frames should be counted.

  • createNewReferencePoint – Whether or not to create a new reference point for the time window. Create a manual reference point if you consecutively call functions with a time window in order to keep a consistent time window.

Returns:

List of frame times within the given duration.

template<duration TimeUnit = TimePoint::duration>
inline auto getCumulativeFrameTimes() const -> TimeUnit

Returns the summed up frame times within the time point horizon.

Template Parameters:

TimeUnit – The time unit for the duration.

Returns:

Sum of frame times within the horizon.

template<duration CutOffTimeUnit, duration TimeUnit = TimePoint::duration>
inline auto getCumulativeFrameTimes(const CutOffTimeUnit &withinDuration, bool createNewReferencePoint = true) -> TimeUnit

Returns the summed up frame times within the given duration.

Template Parameters:
  • CutOffTimeUnit – The time unit for the time window.

  • TimeUnit – The time unit for the returned frame times.

Parameters:
  • withinDuration – The duration in which frames should be counted.

  • createNewReferencePoint – Whether or not to create a new reference point for the time window. Create a manual reference point if you consecutively call functions with a time window in order to keep a consistent time window.

Returns:

Sum of frame times within the given duration.

template<duration TimeUnit = TimePoint::duration>
inline auto getLastFrameTime() const -> TimeUnit
template<duration TimeUnit = TimePoint::duration>
inline auto getDurationSinceLastTick(bool createNewReferencePoint = true) -> TimeUnit

Nearly the same as obscura::Timer::getDurationSinceLastTick with the difference that a reference point can be used.

Template Parameters:

TimeUnit – Type of duration to return.

Parameters:

createNewReferencePoint – Whether or not to create a new reference point. Set this to false if you have manually created a reference point.

Returns:

The duration from end/reference point to the last tick.

Private Functions

inline void removeTimePointsOutsideOfHorizon()

Private Members

std::list<TimePoint::duration> frameTimes = {}
std::list<TimePoint> tickedTimePoints = {}
TimePoint referencePoint
HorizonTimeUnit timePointsHorizon
template<Dispatchable Dispatcher>
class GlfwEventEmitter
#include <event_emitter.hxx>

GlfwEventEmitter is a class that emits events from GLFW to the Obscura event system. It is responsible for polling window-related events from GLFW and emitting them to the event system. Don’t construct an object of this class manually. Instead, use the makeEventEmitter function.

Template Parameters:

Dispatcher – The type of the dispatcher to use.

Public Functions

inline explicit GlfwEventEmitter(GLFWwindow *window)
inline ~GlfwEventEmitter()
GlfwEventEmitter(const GlfwEventEmitter&) = delete
GlfwEventEmitter(GlfwEventEmitter&&) = default
GlfwEventEmitter &operator=(const GlfwEventEmitter&) = delete
GlfwEventEmitter &operator=(GlfwEventEmitter&&) = default
inline void onTick(const TickEvent&)

Public Static Functions

static inline const glm::vec2 &getLastMousePosition()
static inline void setLastMousePosition(const glm::vec2 &newMousePosition)

Private Members

GLFWwindow *window

Private Static Functions

static inline void pollEvents()

Private Static Attributes

static bool lastMousePositionModifiedInThisTick = false
static glm::vec2 lastMousePosition = {0, 0}
template<Dispatchable Dispatcher>
struct GlfwEventEmitterDeleter
#include <event_emitter.hxx>

A deleter for the GlfwEventEmitter class. This is used by the std::shared_ptr to delete the GlfwEventEmitter object.

Template Parameters:

Dispatcher

Public Functions

inline void operator()(GlfwEventEmitter<Dispatcher> *ptr)
class GlfwException : private std::exception

Public Functions

auto what() const noexcept -> const char* override
class GlfwWindow

Public Types

template<Dispatchable Dispatcher>
using EventEmitterType = GlfwEventEmitter<Dispatcher>
template<Dispatchable Dispatcher>
using EventEmitterDeleterType = GlfwEventEmitterDeleter<Dispatcher>

Public Functions

GlfwWindow()
void create(const std::string &title, std::size_t width, std::size_t height)
void update()
template<Dispatchable Dispatcher>
inline auto makeEventEmitter() -> std::unique_ptr<GlfwEventEmitter<Dispatcher>, GlfwEventEmitterDeleter<Dispatcher>>
inline auto getGlfwWindow() const -> GLFWwindow*

Public Static Functions

static auto getVulkanExtensions() -> std::span<const char*>

Private Members

std::unique_ptr<GLFWwindow, void (*)(GLFWwindow*)> window

Private Static Attributes

static bool glfwInitialized = false
template<Dispatchable Dispatcher>
class HeadlessEventEmitter
#include <event_emitter.hxx>

HeadlessEventEmitter is a class that can be used to emit events without a window. It is used by the HeadlessWindow to emit events into the Obscura event system. Don’t construct this class directly, but use the makeEventEmitter function instead. Once, an object of this class is you can manually simulate mouse, keyboard and window events.

Template Parameters:

Dispatcher – The type of the dispatcher to use.

Public Functions

inline HeadlessEventEmitter()
inline ~HeadlessEventEmitter()
HeadlessEventEmitter(const HeadlessEventEmitter&) = delete
HeadlessEventEmitter(HeadlessEventEmitter&&) = default
HeadlessEventEmitter &operator=(const HeadlessEventEmitter&) = delete
HeadlessEventEmitter &operator=(HeadlessEventEmitter&&) = default
inline void pressKey(int key)
inline void releaseKey(int key)
inline void repeatKey(int key)
inline void moveMouseFromTo(const glm::vec2 &origin, const glm::vec2 &target, float pixels_per_second, float pollIntervalInSeconds = constant::DEFAULT_MOUSE_MOVE_INTERVAL_IN_SECONDS)

Moves the mouse from origin to target with a given speed.

Parameters:
  • origin – Origin position of the mouse.

  • target – Target position of the mouse.

  • pixels_per_second – Pixels per second the mouse should move.

  • pollIntervalInSeconds – Interval in seconds between two mouse move events.

inline void clickMouse(const glm::vec2 &position, int key)
inline void scrollMouse(float verticalOffset, float horizontalOffset)
inline void onTick(const TickEvent&)

Private Functions

template<class E, class EventArgs>
inline void processQueue(moodycamel::ConcurrentQueue<EventArgs> *queue)
inline void pollEvents()

Private Members

moodycamel::ConcurrentQueue<std::tuple<int>> keyPressedEvents
moodycamel::ConcurrentQueue<std::tuple<int>> keyReleasedEvents
moodycamel::ConcurrentQueue<std::tuple<int>> keyRepeatedEvents
moodycamel::ConcurrentQueue<std::tuple<float, float, float, float>> movedMouseEvents
moodycamel::ConcurrentQueue<std::tuple<float, float, int>> clickedMouseEvents
moodycamel::ConcurrentQueue<std::tuple<float, float>> scrolledMouseEvents
template<class Dispatcher>
class HeadlessEventEmitterDeleter

Public Functions

inline void operator()(HeadlessEventEmitter<Dispatcher> *ptr)
class HeadlessWindow

Public Types

template<Dispatchable Dispatcher>
using EventEmitterType = HeadlessEventEmitter<Dispatcher>
template<Dispatchable Dispatcher>
using EventEmitterDeleterType = HeadlessEventEmitterDeleter<Dispatcher>

Public Functions

HeadlessWindow() = default
inline void create([[maybe_unused]] const std::string &title, [[maybe_unused]] std::size_t width, [[maybe_unused]] std::size_t height)
template<Dispatchable Dispatcher>
inline auto makeEventEmitter() -> std::unique_ptr<HeadlessEventEmitter<Dispatcher>, HeadlessEventEmitterDeleter<Dispatcher>>
inline void update()

Public Static Functions

static inline auto getVulkanExtensions() -> std::span<const char*>
class Instance

Public Functions

Instance()
explicit Instance(const std::span<const char*> &externallyRequiredExtensions)
~Instance() = default
Instance(const Instance &other) = delete
auto operator=(const Instance &other) -> Instance& = delete
Instance(Instance&&) = delete
auto operator=(Instance&&) -> Instance& = delete
inline auto getVulkanInternalInstance() const -> const vk::raii::Instance&

Private Functions

auto createInstanceCreateInfo(const std::span<const char*> &externallyRequiredExtensions) -> vk::InstanceCreateInfo
auto createInstance() const -> vk::raii::Instance
auto setupDebugMessenger() -> std::optional<vk::raii::DebugUtilsMessengerEXT>
auto setupVulkanExtensions(const std::span<const char*> &externallyRequiredExtensions) -> void
auto setupVulkanLayers() -> void
auto checkRequiredExtensions() const -> void
auto checkRequiredVulkanLayers() const -> void

Private Members

std::string applicationName = {constant::DEFAULT_WINDOW_TITLE}
vk::raii::Context context
vk::ApplicationInfo applicationInfo
std::vector<const char*> requiredExtensions
std::vector<const char*> requiredLayers
vk::InstanceCreateInfo instanceCreateInfo
vk::raii::Instance instance
std::optional<vk::raii::DebugUtilsMessengerEXT> debugMessenger

Private Static Functions

static auto queryAvailableVulkanExtensions() -> const std::vector<vk::ExtensionProperties>&
static auto queryAvailableVulkanLayers() -> const std::vector<vk::LayerProperties>&
static auto logAvailableVulkanExtensions() -> void
static auto logAvailableVulkanLayers() -> void
static auto createDebugUtilsMessengerCreateInfoEXT() -> vk::DebugUtilsMessengerCreateInfoEXT

Private Static Attributes

static const bool enableValidationLayers = false
static bool extensionsAlreadyQueried = false
static std::vector<vk::ExtensionProperties> availableExtensions
static bool layersAlreadyQueried = false
static std::vector<vk::LayerProperties> availableLayers
class KeyError : public std::runtime_error

Public Functions

explicit KeyError(const std::string &key)
template<obscura::EventCause compile_time_cause>
class KeyEvent : public obscura::Event

Public Functions

inline explicit KeyEvent(int key)
inline auto getKey() const -> int

Private Members

int key
class ListenerCouldNotBeRemovedException : public std::exception

Public Functions

auto what() const noexcept -> const char* override
template<class EventQueueHandle, class ListenerIdType = uintptr_t>
class ListenerRegistry

Class that implements a container that keeps track of listeners registered with the dispatcher. A ListenerRegistry internally contains a hash map in the format:

Template Parameters:
  • ListenerIdType

  • EventQueueHandle

Public Functions

template<class Listener>
void registerListener(const Listener &listener, const std::string &listenerGroup, const EventQueueHandle &eventQueueHandle)

Add listener to the register.

Template Parameters:

Listener – Type of the listener.

Parameters:
  • listener – Reference to the listener.

  • listenerGroup – Listener group in which the listener should be registered.

  • eventQueueHandleEvent queue handle of the listener. When adding a listener to the event queue you should receive some kind of handle with that you can remove the listener from the queue again. This handle must be stored in the registry.

template<class Listener>
void unregisterListener(const Listener &listener, const std::string &listenerGroup)
template<class Listener>
auto getHandle(const Listener &listener, const std::string &listenerGroup) const -> const EventQueueHandle&
auto containsListenerGroup(const std::string &listenerGroup) const noexcept -> bool
auto getListenerGroups() const -> const std::set<std::string>&
template<class Listener>
auto contains(const Listener &listener) const -> bool

Checks whether the given listener is registered to any listener group.

Template Parameters:

Listener – Type of the listener.

Parameters:

listener – Reference to the listener.

Returns:

Whether listener is registered to any listener group.

template<class Listener>
auto contains(const Listener &listener, const std::string &listenerGroup) const -> bool

Checks whether the given is registered to the given listener group.

Template Parameters:

Listener – Type of the listener.

Parameters:
  • listener – Reference to the listener.

  • listenerGroup – Listener group that is checked for containing the given listener.

Returns:

Whether the listener is registered to the listener group.

Private Members

std::unordered_map<ListenerIdType, std::unordered_map<std::string, EventQueueHandle>> listenerRegistry = {}
std::set<std::string> listenerGroups = {}

Private Static Functions

template<class Listener>
static inline auto getListenerId(const Listener &listener) -> ListenerIdType

Get the listener id from a listener object. The id is used for checking if a listener is already registered or with which group it is registered.

Template Parameters:

Listener – The listener type.

Parameters:

listener – The listener object.

Returns:

The listener id.

class ListenerRegistryFixture : public TestKeyListenerFixture

Public Members

std::unique_ptr<ListenerRegistry<int>> listenerRegistry

Protected Functions

inline void SetUp() override
inline void TearDown() override
class Logger : public obscura::Singleton<LoggerImpl>
#include <logging.hxx>

The Logger class is a singleton that provides a logging interface.

Can be used by calling Logger::getInstance().info(“Hello, world!”). However, instead of using this singleton directly, it is recommended to use the logInfo, logWarn, logError, logDebug and logTrace, since these functions are only called if logging is enabled.

class LoggerImpl : public obscura::BaseLoggerImpl
#include <logger_impl.hxx>

Implementation of the logger for the client.

This class should not be used directly. Instead, use the Logger singleton.

Public Functions

LoggerImpl()
template<Dispatchable Dispatcher>
class LoopBase : public obscura::ConfigurableDispatcher<TickDefinition, KeyPressedDefinition, MouseMovedDefintion, KeyReleasedDefinition, KeyRepeatedDefinition, WindowClosedDefintion, MouseClickedDefinition, LoopEndDefinition>

Subclassed by obscura::MainLoop< obscura::ConfigurableDispatcher >, obscura::AsyncLoop< Dispatcher >, obscura::MainLoop< Dispatcher >, obscura::SyncLoop< Dispatcher, BaseLoop >

Public Functions

inline LoopBase()
~LoopBase() = default
LoopBase(LoopBase<Dispatcher>&&) noexcept = default
auto operator=(LoopBase<Dispatcher>&&) noexcept -> LoopBase<Dispatcher>& = default
LoopBase(const LoopBase<Dispatcher>&) = delete
auto operator=(const LoopBase<Dispatcher>&) -> LoopBase<Dispatcher>& = delete
inline void tick()
template<class Event>
inline void scheduleOnce(Event &&event)
template<class Event, class Duration>
inline void scheduleOnce(Event &&event, const Duration &delay)
template<class Event>
inline void scheduleOnce(Event &&event, std::size_t afterNFrames)
inline auto getFramePacer() const -> const FramePacer<>&
inline void waitForStop()

Protected Functions

inline void assertIsNotRunning() const
inline void initRun()
inline void tearDownRun()
inline auto getInterruptSignal() -> std::atomic_flag&
inline auto getIsRunning() -> std::atomic_flag&

Private Members

FramePacer framePacer = {}
std::atomic_flag isRunning
std::atomic_flag interruptSignal
class LoopConfig

Subclassed by obscura::LoopSynchronizer< BaseLoop, DependentLoop >

Public Static Functions

static auto targetFPS(const FPS &fps)
static auto runAtFractionOfBaseLoop(float fraction) -> FractionalLoopConfig

Protected Attributes

bool isTargetingFPS = false
FPS fpsTarget
bool runsAtFractionOfBaseLoop = false
float fractionOfBaseLoop = {}
bool hasMinFrameTime = false
bool hasMaxFrameTime = false
float minFrameTime = {}
float maxFrameTime = {}

Private Functions

LoopConfig() = default

Friends

friend class TargetFPSLoopConfig
friend class FractionalLoopConfig
friend class BaseLoopConfig
class LoopDoesNotExistException : public std::exception

Public Functions

explicit LoopDoesNotExistException(const std::string &name)
auto what() const noexcept -> const char* override

Private Members

std::string message
class LoopIsAlreadyRunningException : public std::exception

Public Functions

auto what() const noexcept -> const char* override
class LoopStoppedEvent : public obscura::Event

Public Functions

explicit LoopStoppedEvent(std::string loopName)
auto getLoopName() const -> const std::string&

Private Members

std::string loopName
template<class BaseLoop, class DependentLoop>
class LoopSynchronizer : private obscura::LoopConfig

Public Functions

inline LoopSynchronizer(BaseLoop &baseLoop, DependentLoop &dependentLoop, LoopConfig config)
inline LoopSynchronizer(BaseLoop &baseLoop, DependentLoop &dependentLoop, LoopConfig &&config)
inline void onTick([[maybe_unused]] const TickEvent &event)

Private Functions

inline auto shouldTickDependentLoop(const FPS &targetFPS) const -> bool
template<class TimeUnit>
inline auto computeFrameTimeRequiredForTargetFPS(const FPS &targetFPS) const -> TimeUnit
template<class TimeUnit>
inline auto predictDurationToNextBaseTick() const -> TimeUnit
inline auto shouldTickDependentLoop(float fractionOfBaseLoop) const -> bool

Private Members

BaseLoop *baseLoop
DependentLoop *dependentLoop
template<Dispatchable Dispatcher>
class MainLoop : public obscura::LoopBase<Dispatcher>

Public Functions

inline void run(const FPS &fps)
inline void stop()
class MouseClickedEvent : public obscura::KeyEvent<EventCause::MouseClicked>

Public Functions

MouseClickedEvent(float xPosition, float yPosition, int key)
auto getPosition() const -> const glm::vec2&

Private Members

glm::vec2 position
class MouseMovedEvent : public obscura::Event

Public Functions

MouseMovedEvent(float xPosition, float yPosition, float xOffset, float yOffset)
auto getOffset() const -> const glm::vec2&
auto getPreviousPosition() const -> const glm::vec2&
auto getCurrentPosition() const -> glm::vec2

Private Members

glm::vec2 offset
glm::vec2 position
class MouseScrolledEvent : public obscura::Event

Public Functions

MouseScrolledEvent(float verticalOffset, float horizontalOffset)
auto getVerticalOffset() const -> const float&
auto getHorizontalOffset() const -> const float&

Private Members

float verticalOffset
float horizontalOffset
class NameAlreadyTakenException : public std::exception

Public Functions

NameAlreadyTakenException(const std::string &name, const std::string &context)
auto what() const noexcept -> const char* override

Private Members

std::string message
class NotInitializedException : public std::runtime_error

Public Functions

explicit NotInitializedException(const std::string &message)

Private Members

std::string message
template<Dispatchable Dispatcher>
class Scheduler : public obscura::Singleton<SchedulerImpl<Dispatcher>>
#include <scheduler.hxx>

Scheduler is a singleton that manages all the loops in the application. The class inherits from obscura::SchedulerImpl that implements all the main functionalities. In order to use the scheduler, retrieve an instance of the scheduler using obscura::Scheduler::getInstance().

Template Parameters:

Dispatcher – Type of the dispatcher to be used by the scheduler.

Private Functions

inline Scheduler()
template<Dispatchable Dispatcher>
class SchedulerImpl

Public Functions

inline auto getMainLoop() -> MainLoop<Dispatcher>*
inline auto getSyncLoop(const std::string &name) -> SyncLoop<Dispatcher, MainLoop<Dispatcher>>*
inline auto getAsyncLoop(const std::string &name) -> AsyncLoop<Dispatcher>*
inline void startMainLoop()
inline void stopMainLoop()
inline auto createSyncLoop(const std::string &name, const LoopConfig &config) -> SyncLoop<Dispatcher, MainLoop<Dispatcher>>*

Creates a new synchronous loop and registers it with the scheduler.

Parameters:
  • name – Name of the loop. The name is required to schedule event_system on the loop.

  • config – Config for the loop.

Returns:

Returns a pointer to the newly created loop.

inline auto createAsyncLoop(const std::string &name, const FPS &fps) -> AsyncLoop<Dispatcher>*

Creates a new asynchronous loop and registers it with the scheduler.

Parameters:
  • name – Name of the loop. The name is required to schedule event_system on the loop.

  • fpsFPS of the loop.

Returns:

Returns a pointer to the newly created loop.

template<class Event>
inline void scheduleOnce(Event &&event, const std::string &loopName)

Schedules an event on the specified loop.

Template Parameters:

Event – Type of the event.

Parameters:
  • eventEvent to be scheduled.

  • loopName – Name of the loop on which the event is to be scheduled.

template<class Event>
inline void scheduleOnce(Event &&event)

Schedules an event on the main loop.

Template Parameters:

Event – Type of the event.

Parameters:

eventEvent to be scheduled.

template<class Event, class Duration>
inline void scheduleOnce(Event &&event, const Duration &delay, const std::string &loopName)

Schedules an event on the specified loop after a delay.

Template Parameters:
  • Event – Type of the event.

  • Duration – Type of the duration. Usually, a std::chrono::duration.

Parameters:
  • eventEvent to be scheduled.

  • delay – Delay after which the event is to be scheduled.

  • loopName – Name of the loop on which the event is to be scheduled.

template<class Event, class Duration>
inline void scheduleOnce(Event &&event, const Duration &delay)

Schedules an event on the main loop.

Template Parameters:
  • Event – Type of the event.

  • Duration – Type of the duration. Usually, a std::chrono::duration.

Parameters:
  • eventEvent to be scheduled.

  • delay – Delay after which the event is to be scheduled.

template<class Listener>
inline void registerListener(Listener &listener, const std::string &loopName)
template<class Listener>
inline void registerListener(Listener &listener)

Registers a listener with the main loop.

Template Parameters:

Listener – Type of the listener.

Parameters:

listener – The listener to be registered.

template<class Listener>
inline void unregisterListener(Listener &listener, const std::string &loopName)

Unregisters a listener from the specified loop.

Template Parameters:

Listener – Type of the listener.

Parameters:
  • listener – The listener to be unregistered.

  • loopName – Name of the loop from which the listener is to be unregistered.

template<class Listener>
inline void unregisterListener(Listener &listener)

Unregisters a listener from the main loop.

Template Parameters:

Listener – Type of the listener.

Parameters:

listener – The listener to be unregistered.

Private Members

MainLoop<Dispatcher> mainLoop = {}
std::unordered_map<std::string, SyncLoop<Dispatcher, MainLoop<Dispatcher>>> syncLoops
std::unordered_map<std::string, AsyncLoop<Dispatcher>> asyncLoops

Private Static Attributes

static constexpr auto defaultFPS = 30
template<class T>
class Singleton

Public Functions

Singleton(const Singleton&) = delete
void operator=(const Singleton&) = delete
Singleton(Singleton&&) = delete
auto operator=(Singleton&&) -> Singleton& = delete

Public Static Functions

static inline auto getInstance() -> T&

Protected Functions

Singleton() = default
~Singleton() = default
template<class T, class D = void>
struct SmartPtr : public std::false_type
template<class T>
struct SmartPtr<std::shared_ptr<T>> : public std::true_type
template<class T>
struct SmartPtr<std::unique_ptr<T>> : public std::true_type
template<class T, class D>
struct SmartPtr<std::unique_ptr<T, D>> : public std::true_type
template<size_t N>
struct StringLiteral

A class that can be used to pass string literals as template parameters.

Template Parameters:

N – Number of characters. The template parameter is deduced automatically.

Public Functions

inline constexpr StringLiteral(const char (&str)[N])

Public Members

char value[N] = {}
template<Dispatchable Dispatcher, Loop BaseLoop>
class SyncLoop : public obscura::LoopBase<Dispatcher>

Public Functions

inline void run(BaseLoop &newBaseLoop, const LoopConfig &config)
inline void stop()

Private Members

BaseLoop *baseLoop = {nullptr}
std::unique_ptr<LoopSynchronizer<BaseLoop, SyncLoop<Dispatcher, BaseLoop>>> synchronizer
class TargetFPSLoopConfig : public obscura::BaseLoopConfig<TargetFPSLoopConfig>

Public Functions

auto build() const

Private Functions

explicit TargetFPSLoopConfig(const FPS &fps)

Private Members

FPS fpsTarget

Friends

friend class LoopConfig
class TickEvent : public obscura::Event

Public Functions

explicit TickEvent(std::chrono::microseconds durationSinceLastTick)
auto getDurationSinceLastTick() const -> std::chrono::microseconds

Private Members

std::chrono::microseconds durationSinceLastTick
class Timer
#include <timer.hxx>

Class that measures times between tick points.

Subclassed by obscura::FrameProfiler< std::chrono::seconds >, obscura::FrameProfiler< HorizonTimeUnit >

Public Functions

Timer() = default
void start()

Starts the timer. Must be called before measuring any times. Otherwise, an exception is thrown.

void tick()

Creates a tick point that is used to measure intermediate timings.

void stop()

Stops the timer. The timing between the start and stop point can be gathered afterward.

auto getStart() const -> TimePoint
auto getTick() const -> TimePoint
auto getEnd() const -> TimePoint
auto isStarted() const -> bool
auto isStopped() const -> bool
template<class TimeUnit = TimePoint::duration>
inline auto getDuration() const -> TimeUnit

Returns the duration between the stop and start point, if stop was called, or otherwise the duration between the current time point and the start point.

Template Parameters:

TimeUnit – Type of the duration to return. Usually, std::chrono::duration.

Returns:

Returns the duration between stop/current point and start point.

template<class TimeUnit = TimePoint::duration>
inline auto getDurationSinceLastTick() -> TimeUnit

Returns the duration between the stop and last tick point, if stop was called, or otherwise the duration between the current time point and the last tick point.

Template Parameters:

TimeUnit – Type of the duration to return. Usually, std::chrono::duration.

Returns:

Returns the duration between stop/current point and last tick point.

Private Functions

auto invoked() const -> bool

Private Members

TimePoint startPoint
TimePoint lastTickPoint
TimePoint endPoint
bool started = false
bool stopped = false
class TimerAlreadyStartedException : public std::exception

Private Functions

auto what() const noexcept -> const char* override
class TimerAlreadyStoppedException : public std::exception

Private Functions

auto what() const noexcept -> const char* override
class TimerNotStartedException : public std::exception

Private Functions

auto what() const noexcept -> const char* override
class TimerNotStoppedException : public std::exception

Private Functions

auto what() const noexcept -> const char* override
class VulkanInstanceTest : public testing::Test

Private Members

obscura::DynamicLoader dynamicLoader
template<typename Window>
class VulkanRenderer

Public Functions

inline explicit VulkanRenderer(const Window &window)

Private Members

DynamicLoader dynamicLoader = {}
Instance instance
Device device
class VulkanRendererTest : public testing::Test
template<WindowImplementationConcept Implementation = DefaultWindowImplementation>
class Window

Public Functions

inline explicit Window(const WindowProperties &windowProperties)
inline void open(const WindowProperties &newWindowProperties)
inline void close()
inline void tick()
inline auto getWidth() const -> std::size_t
inline auto getHeight() const -> std::size_t
inline auto getImplementation() const -> Implementation&
inline auto getVulkanExtensions() const -> std::span<const char*>
template<Dispatchable Dispatcher>
inline auto makeEventEmitter()

Constructs an event emitter for the given dispatcher. As long as the returned event emitter is alive, it will forward events sent to the window to the dispatcher. Destroy this object to stop this behavior. If this isn’t called, windows events cannot be processed.

Template Parameters:

Dispatcher – The type of the dispatcher to use.

Returns:

A unique pointer to an event emitter object.

Private Members

std::unique_ptr<Implementation> implementation
std::unique_ptr<WindowProperties> windowProperties
std::atomic<bool> windowClosed = true
class WindowEvent : public obscura::Event

Public Functions

explicit WindowEvent(const EventCause &cause)
struct WindowProperties

Public Members

std::size_t width = constant::DEFAULT_WINDOW_WIDTH
std::size_t height = constant::DEFAULT_WINDOW_HEIGHT
std::string title = std::string{constant::DEFAULT_WINDOW_TITLE}
namespace obscura

Typedefs

using Dispatcher = ConfigurableDispatcher<TickDefinition, KeyPressedDefinition, MouseMovedDefintion, KeyReleasedDefinition, KeyRepeatedDefinition, WindowClosedDefintion, MouseClickedDefinition, LoopEndDefinition>

The Obscura default dispatcher with all predefined event types pre-configured. Use this class if you have no need to define custom event_system.

template<class Listener>
using KeyPressedCallback = CallbackWrapper<Listener, KeyPressedEvent, &Listener::onKeyPressed>
using KeyPressedDefinition = EventDefinition<"KeyPressedDefinition", KeyPressedEvent, KeyPressedCallback>
template<class Listener>
using KeyReleasedCallback = CallbackWrapper<Listener, KeyReleasedEvent, &Listener::onKeyReleased>
using KeyReleasedDefinition = EventDefinition<"KeyReleasedDefinition", KeyReleasedEvent, KeyReleasedCallback>
template<class Listener>
using KeyRepeatedCallback = CallbackWrapper<Listener, KeyRepeatedEvent, &Listener::onKeyRepeated>
using KeyRepeatedDefinition = EventDefinition<"KeyRepeatedDefinition", KeyRepeatedEvent, KeyRepeatedCallback>
template<class Listener>
using TickCallback = CallbackWrapper<Listener, TickEvent, &Listener::onTick>
using TickDefinition = EventDefinition<"TickDefinition", TickEvent, TickCallback>
template<class Listener>
using LoopEndCallback = CallbackWrapper<Listener, LoopStoppedEvent, &Listener::onLoopStop>
using LoopEndDefinition = EventDefinition<"LoopEndDefinition", LoopStoppedEvent, LoopEndCallback>
template<class Listener>
using MouseMovedCallback = CallbackWrapper<Listener, MouseMovedEvent, &Listener::onMouseMoved>
using MouseMovedDefintion = EventDefinition<"MouseMovedDefintion", MouseMovedEvent, MouseMovedCallback>
template<class Listener>
using MouseClickedCallback = CallbackWrapper<Listener, MouseClickedEvent, &Listener::onMouseClicked>
using MouseClickedDefinition = EventDefinition<"MouseClickedDefinition", MouseClickedEvent, MouseClickedCallback>
template<class Listener>
using WindowClosedCallback = CallbackWrapper<Listener, WindowEvent, &Listener::onWindowClosed>
using WindowClosedDefintion = EventDefinition<"WindowClosedDefintion", WindowEvent, WindowClosedCallback>
using KeyPressedEvent = KeyEvent<EventCause::KeyPressed>
using KeyRepeatedEvent = KeyEvent<EventCause::KeyRepeated>
using KeyReleasedEvent = KeyEvent<EventCause::KeyReleased>
template<typename Window>
using DefaultRendererImplementation = VulkanRenderer<Window>
typedef std::chrono::steady_clock Clock
using TimePoint = decltype(Clock::now())
using DefaultWindowImplementation = GlfwWindow

Enums

enum class EventCategory

The available event categories for Obscura. SIZE must be at the end of the enum. It is used to determine the number of categories.

Values:

enumerator None
enumerator Application
enumerator KeyInput
enumerator ScrollInput
enumerator CoordinateInput
enumerator Window
enumerator SIZE
enum class EventCause

The available event causes for Obscura.

Values:

enumerator None
enumerator KeyPressed
enumerator KeyReleased
enumerator KeyRepeated
enumerator WindowClosed
enumerator WindowResized
enumerator WindowMoved
enumerator WindowFocus
enumerator WindowLostFocus
enumerator MouseMoved
enumerator MouseScrolled
enumerator MouseClicked
enumerator LoopTicked
enumerator LoopStopped
enumerator Rendered

Functions

inline constexpr auto eventCode(EventCategory category, EventCause cause) -> std::size_t

Returns a unique code that is a combination of the event’s category and cause.

Parameters:
  • category – Category of the event.

  • cause – Cause of the event.

Returns:

Unique code for the event.

inline auto getCategoryFromCode(std::size_t code) -> EventCategory

Determines and returns the category of an event from its code.

Parameters:

code – The event’s code.

Returns:

An event category.

inline auto getCauseFromCode(std::size_t code) -> EventCause

Determines and returns the cause of an event from its code.

Parameters:

code – The event’s code.

Returns:

An event cause.

template<Dispatchable Dispatcher, class Event>
void emitDelayedEvent(Dispatcher &dispatcher, Event &&event, std::size_t emitAfterNFrames)
template<typename StringType, typename ...Args>
inline void logCoreInfo(StringType fmt, const Args&... args)

Logs an info message.

Should only be used internally by obscura. For logging in the client code, use logInfo. The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logCoreWarn(StringType fmt, const Args&... args)

Logs a warning message.

Should only be used internally by obscura. For logging in the client code, use logWarn. The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logCoreError(StringType fmt, const Args&... args)

Logs an error message.

Should only be used internally by obscura. For logging in the client code, use logError. The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logCoreDebug(StringType fmt, const Args&... args)

Logs a debug message.

Should only be used internally by obscura. For logging in the client code, use logDebug. The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logCoreTrace(StringType fmt, const Args&... args)

Logs a trace message.

Should only be used internally by obscura. For logging in the client code, use logTrace. The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logInfo(StringType fmt, const Args&... args)

Logs an info message.

The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logWarn(StringType fmt, const Args&... args)

Logs a warning message.

The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logError(StringType fmt, const Args&... args)

Logs an error message.

The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logDebug(StringType fmt, const Args&... args)

Logs a debug message.

The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

template<typename StringType, typename ...Args>
inline void logTrace(StringType fmt, const Args&... args)

Logs a trace message.

The function is only called if logging is enabled. If the pre-processing variable is set to false, the function does not cause any function call overhead.

Template Parameters:
  • StringType – The type of the string to log.

  • Args – The types of the arguments to log.

Parameters:
  • fmt – The format string.

  • args – The arguments to log.

static VKAPI_ATTR auto VKAPI_CALL debugCallback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *) -> VkBool32
template<class T>
requires std::is_convertible_v<T, float>
auto operator<=(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator<=(T lhs, const obscura::FPS &rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator<(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator<(T lhs, const obscura::FPS &rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator==(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator==(T lhs, const obscura::FPS &rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator!=(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator!=(T lhs, const obscura::FPS &rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator>=(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator>=(T lhs, const obscura::FPS &rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator>(const obscura::FPS &lhs, T rhs) -> bool
template<class T>
requires std::is_convertible_v<T, float>
auto operator>(T lhs, const obscura::FPS &rhs) -> bool
template<class TimePoint>
void preciseSleepUntil(const TimePoint &timePoint)
template<duration TimeUnit>
void preciseSleepFor(const TimeUnit &duration)
template<Dispatchable Dispatcher>
void keyCallback([[maybe_unused]] GLFWwindow*, int key, [[maybe_unused]] int scancode, int action, [[maybe_unused]] int mods)
template<class Dispatcher>
void windowCloseCallback([[maybe_unused]] GLFWwindow*)
template<class Dispatcher, class WindowImplementation>
void mouseMovedCallback([[maybe_unused]] GLFWwindow*, double xCoordinate, double yCoordinate)

Variables

template<class T> concept Dispatchable   = requires(T impl) { impl.dispatch(); }
template<class T> concept Loop  = requires(T impl) {impl.tick();impl.scheduleOnce(0);impl.scheduleOnce(0, std::chrono::seconds { 1 });impl.scheduleOnce(0, std::chrono::milliseconds { 1 });impl.scheduleOnce(0, std::chrono::microseconds { 1 });impl.scheduleOnce(0, std::size_t {});{ impl.getFramePacer() } -> std::convertible_to<Timer>;impl.waitForStop();}
constexpr std::size_t MAX_CATEGORIES = 100
static const bool loggingEnabled = false
template<typename Renderer, typename Window> concept RendererImplementationConcept   = requires(Renderer renderer, Windowwindow) {Renderer { window };}
template<class T> concept duration  = std::regular<T> && requires(T lhs, T rhs, typename T::rep rep) {typename T::rep;typename T::period;{ lhs + rhs } -> std::same_as<T>;{ lhs - rhs } -> std::same_as<T>;{ lhs* rep } -> std::same_as<T>;{ rep* lhs } -> std::same_as<T>;{ lhs / rep } -> std::same_as<T>;{ lhs / rhs } -> std::same_as<typename T::rep>;{ lhs % rep } -> std::same_as<T>;{ lhs % rhs } -> std::same_as<T>;{ lhs.count() } -> std::same_as<typename T::rep>;}
template<class T> concept is_smart_ptr   = SmartPtr<T>::value
template<class T> concept WindowImplementationConcept  =requires(T impl, const std::string& title, std::size_t width, std::size_t height) {T();{ impl.create(title, width, height) } -> std::same_as<void>;{ impl.update() } -> std::same_as<void>;{ impl.template makeEventEmitter<Dispatcher>() } -> is_smart_ptr;impl.getVulkanExtensions();}
std::mutex tickMutex
namespace constant

Variables

constexpr std::size_t QUEUE_PROCESS_BULK_SIZE = 32

The number of events that are processed by the headless window in one batch.

constexpr float DEFAULT_MOUSE_MOVE_INTERVAL_IN_SECONDS = 1e-3

The default interval in seconds between two mouse move events.

constexpr std::size_t DEFAULT_WINDOW_WIDTH = {1280}
constexpr std::size_t DEFAULT_WINDOW_HEIGHT = {720}
constexpr std::string_view DEFAULT_WINDOW_TITLE = {"Obscura"}
namespace std
namespace chrono_literals
namespace testing
file CONTRIBUTING_INSTRUCTIONS.md
file application.hxx
file application.test.cxx
#include <chrono>
#include <gtest/gtest.h>
#include <test_config/config.hxx>
#include <thread>

Functions

TEST_F(ApplicationFixture, MultipleEventsCanBeDispatched)
TEST_F(ApplicationFixture, MultipleConcurrentEventsCanBeDispatched)
TEST_F(ApplicationFixture, TickEventsAreDispatchedToMainLoop)
file core.hxx
#include <atomic>
#include <bit>
#include <chrono>
#include <concepts>
#include <cstddef>
#include <format>
#include <functional>
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <numeric>
#include <optional>
#include <set>
#include <span>
#include <string>
#include <thread>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>
file dispatcher.hxx
file dispatcher.hxx
file loop.hxx
#include “obscura/core/core.hxx
#include “obscura/timer/timer.hxx
file configurable_dispatcher.hxx
#include “dispatcher_base.hxx
file dispatcher.test.cxx
#include <gtest/gtest.h>
#include <test_config/config.hxx>

Functions

TEST(DispatcherNoErrorsTest, DispatcherCanBeConstructed)
TEST(DispatcherNoErrorsTest, ListenerCanBeAppended)
TEST(DispatcherNoErrorsTest, EventCanBeEnqueued)
TEST_F(DispatcherFixture, KeyPressedEventIsDispatched)
TEST_F(DispatcherFixture, KeyReleaseEventIsDispatched)
TEST_F(DispatcherFixture, MouseMovedEventIsDispatched)
TEST_F(DispatcherFixture, KeyPressedEventIsNotDispatchedIfKeyReleasedEventIsEmitted)
TEST_F(DispatcherFixture, MultipleEventsAreDispatched)
TEST(DispatcherListenerTest, AddressedEventsAreCorrectlyDispatched)
TEST(DispatcherListenerTest, ListenersCanBeRemoved)
TEST_F(DispatcherFixture, TickListenerIsAddedToDispatcher)
TEST_F(DispatcherFixture, MultipleListenersAreRegistered)
TEST_F(TestKeyListenerFixture, CallbackWrapperCallsListenerCorrectly)
TEST(DispatcherNoErrorsTest, SingleDefinitionDispatcherCanBeConstructed)
TEST(DispatcherNoErrorsTest, ListenerCanBeRegisteredWithSingleDefinitionDispatcher)
TEST(DispatcherNoErrorsTest, EventCanBeEnqueuedAndDispatchedWithSingleDefinitionDispatcher)
file dispatcher_base.hxx
#include “listener_registry.hxx
#include “obscura/core/core.hxx
#include <eventpp/eventdispatcher.h>
#include <eventpp/eventqueue.h>
file dispatcher_base.test.cxx
#include <gtest/gtest.h>

Functions

TEST_F(DispatcherBaseFixture, EventCanBeEnqueued)
TEST_F(DispatcherBaseFixture, HasListenerForEventReturnsCorrectlyFalse)
file listener_registry.hxx
#include “obscura/core/core.hxx
file listener_registry.test.cxx
#include <gtest/gtest.h>
#include <test_config/config.hxx>

Functions

TEST_F(ListenerRegistryFixture, ListenerCanBeRegistered)
TEST_F(ListenerRegistryFixture, ListenerIsNotContainedIfNotAdded)
TEST_F(ListenerRegistryFixture, ListenerCanBeRegisteredForMultipleGroups)
TEST_F(ListenerRegistryFixture, ExceptionIsThrownIfListenerIsRegisteredTwice)
TEST_F(ListenerRegistryFixture, ListenerCanBeUnregistered)
TEST_F(ListenerRegistryFixture, ErrorIsThrownIfListenerWithNonExistingGroupIsUnregistered)
TEST_F(ListenerRegistryFixture, ErrorIsThrownIfNotRegisteredListenerIsUnregistered)
TEST_F(ListenerRegistryFixture, ContainsListenerGroupReturnsTrueIfGroupExists)
TEST_F(ListenerRegistryFixture, ContainsListenerGroupReturnsFalseIfGroupDoesNotExist)
TEST_F(ListenerRegistryFixture, HandleCanBeReceivedForListener)
TEST_F(ListenerRegistryFixture, ListenerGroupsAreCorrectlyReturnedWithMultipleGroups)
file event_definition.hxx

Variables

template<class T> concept EventDefinitionConcept  = requires(T definition) {{EventDefinition{ definition } } -> std::same_as<T>;}
file key_event_definitions.hxx
file loop_event_definitions.hxx
file mouse_event_definitions.hxx
file window_event_defintions.hxx
file async_loop.hxx
#include “loop_base.hxx
file loop_base.hxx
#include “obscura/timer/sleep.hxx
file loop_config.cxx
file loop_config.hxx
file loop_synchronizer.hxx
#include “loop_config.hxx
#include “obscura/timer/timer.hxx
file loops.test.cxx
#include <gtest/gtest.h>
#include <test_config/config.hxx>

Functions

TEST_F(MainLoopFixture, TickListenerAddedToMainLoopIsRegistered)
TEST_F(MainLoopFixture, TickListenerAddedToMainLoopAcceptsTickEvents)
TEST_F(MainLoopFixture, TickListenerOnSyncLoopShouldOnlyReceiveHalfOfTicks)
TEST_F(MainLoopFixture, AsyncLoopAndMainLoopStopAfterGivenNumberOfTicks)
file main_loop.hxx
#include “loop_base.hxx
#include “obscura/core/core.hxx
file sync_loop.hxx
#include “loop_base.hxx
#include “loop_synchronizer.hxx
file event.hxx
#include “obscura/core/core.hxx
file events.test.cxx
#include <gtest/gtest.h>
#include <iostream>

Functions

TEST(EventCategoryAndCauseTest, EventCategoryIntsAreCorrect)
TEST(EventCategoryAndCauseTest, EventCauseIntsAreCorrect)
TEST(EventCategoryAndCauseTest, EventCodeIsCorrect)
TEST(EventCategoryAndCauseTest, EventCodeConversionWorks)
file key_events.hxx
#include “event.hxx
file key_events.test.cxx
#include <gtest/gtest.h>

Functions

TEST(KeyEventConstructorTest, KeyEventCanBeConstructed)
TEST(KeyEventConstructorTest, KeyEventGettersReturnCorrectValues)
TEST(KeyEventConstructorTest, KeyEventHasCorrectCode)
file loop_events.cxx
#include <utility>
file loop_events.hxx
#include “event.hxx
#include <chrono>
file mouse_events.cxx
file mouse_events.hxx
#include “event.hxx
#include “key_events.hxx
#include <glm/glm.hpp>
file mouse_events.test.cxx
#include <gtest/gtest.h>

Functions

TEST(MouseMovedEventConstructorTest, MouseMovedEventCanBeConstructed)
TEST(MouseMovedEventConstructorTest, OffsetIsCorrect)
TEST(MouseMovedEventConstructorTest, PreviousPositionIsCorrect)
TEST(MouseMovedEventConstructorTest, CurrentPositionIsCorrect)
TEST(MouseMovedEventConstructorTest, CategoryAndCauseAreCorrect)
TEST(MouseScrolledEventConstructorTest, MouseScrolledEventCanBeConstructed)
TEST(MouseScrolledEventConstructorTest, VerticalOffsetIsCorrect)
TEST(MouseScrolledEventConstructorTest, HorizontalOffsetIsCorrect)
TEST(MouseScrolledEventConstructorTest, CategoryAndCauseAreCorrect)
file window_events.cxx
file window_events.hxx
#include “event.hxx
file delay.hxx
file scheduler.hxx
#include “obscura/core/core.hxx
file scheduler.test.cxx
#include <gtest/gtest.h>
#include <test_config/config.hxx>

Functions

TEST(SingletonTest, SingletonReturnsSamePointer)
TEST(SingletonTest, SchedulerReturnsSameMainLoop)
TEST_F(TestKeyListenerFixture, MainLoopCanBeRetrievedAndEventsCanBeScheduled)
TEST_F(TestKeyListenerFixture, EventsCanBeScheduled)
file exceptions.cxx
file exceptions.hxx
file logger_impl.cxx
#include <spdlog/sinks/stdout_color_sinks.h>
file logger_impl.hxx
#include <spdlog/spdlog.h>
#include <string>
file logging.hxx
file logging_levels.hxx
file obscura.hxx
file renderer.hxx
file renderer.hxx
file renderer_concept.hxx
file vulkan-init.test.cxx
#include <gtest/gtest.h>
#include <vulkan/vulkan_raii.hpp>

Functions

TEST(Renderer, VulkanInit)
file device.cxx
file device.hxx
#include <vulkan/vulkan_raii.hpp>
file dynamic_loader.cxx

Variables

VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
file dynamic_loader.hxx
#include <vulkan/vulkan_raii.hpp>
file instance.cxx
#include <vulkan/vulkan_raii.hpp>
file instance.hxx
#include <span>
#include <vulkan/vulkan_raii.hpp>
file instance.test.cxx
#include <gtest/gtest.h>

Functions

TEST_F(VulkanInstanceTest, VulkanInstanceIsSuccessfullyCreated)
TEST_F(VulkanInstanceTest, VulkanInstanceRequiresUnknownExtension)
TEST_F(VulkanInstanceTest, VulkanInstanceCanBeCreatedTwice)
file renderer.test.cxx
#include <gtest/gtest.h>

Functions

TEST_F(VulkanRendererTest, VulkanRendererIsSuccessfullyCreated)
TEST_F(VulkanRendererTest, VulkanRendererCanBeCreatedTwice)
file duration.hxx
file fps.hxx
file fps.test.cxx
#include <gtest/gtest.h>

Functions

TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromFloat)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromDouble)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromInt)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromUnsignedInt)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromChar)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromFrameTime)
TEST(FPSConstructionTests, FPSObjectCanBeConstructedFromDurationAndNumberOfFrames)
TEST(FPSAssignmentTests, FloatCanBeAssignedToFPSObject)
TEST(FPSAssignmentTests, DoubleCanBeAssignedToFPSObject)
TEST(FPSAssignmentTests, IntCanBeAssignedToFPSObject)
TEST(FPSAssignmentTests, CharCanBeAssignedToFPSObject)
TEST(FPSAssignmentTests, UnsignedIntCanBeAssignedToFPSObject)
TEST(FPSConversionTests, FPSCanBeConvertedToFrameTime)
TEST(FPSConversionTests, FPSCanBeConvertedToMicrosecondsFrameTime)
TEST(FPSOperatorTests, LessEqualOperatorWorks)
TEST(FPSOperatorTests, LessOperatorWorks)
TEST(FPSOperatorTests, EqualOperatorWorks)
TEST(FPSOperatorTests, NotEqualOperatorWorks)
TEST(FPSOperatorTests, GreaterEqualOperatorWorks)
TEST(FPSOperatorTests, GreaterOperatorWorks)
TEST(FPSConversionTests, FPSCanBeConvertedToFramesPerSecond)
TEST(FPSConversionTests, FPSCanBeConvertedToFramesPerSecondSpecialization)
TEST(FPSConversionTests, FPSCanBeConvertedToFramesPerMicrosecond)
file fps_comp_operators.hxx
file fps_impl.cxx
#include “fps_impl.hxx

Functions

template<>
auto framesPerTimeUnit<std::chrono::seconds>() const -> float
file fps_impl.hxx
file frame_pacer.hxx
file frame_pacer.test.cxx
#include <gtest/gtest.h>

Functions

TEST(FramePacerFunctionalityTest, SleepForRestOfFrameTimeWorks)
TEST(FramePacerFunctionalityTest, SleepForSinceLastTickWorks)
file frame_profiler.hxx
file frame_profiler.test.cxx
#include <gtest/gtest.h>

Functions

TEST(FrameProfilerExceptionTest, ExceptionIsThrownIfTimerIsNotStopped)
TEST(FrameProfilerFunctionalityTest, TimerReturnsApproximatelyRightDurationWithTick)
TEST(FrameProfilerFunctionalityTest, NumberOfFramesInLastSecondsReturnsCorrectTotal)
TEST(FrameProfilerFunctionalityTest, NumberOfFramesInLastSecondsReturnsCorrectTotalWithSleep)
TEST(FrameProfilerFunctionalityTest, NumberOfFramesInLastSecondThatExceedOneSecondAreCorrect)
TEST(FrameProfilerFunctionalityTest, FrameTimesOfLastSecondAreApproximatelyCorrect)
TEST(FrameProfilerFunctionalityTest, FrameTimesOfLastSecondAreCorrectWhenOneFrameTimeLongerThanASecond)
TEST(FrameProfilerFunctionalityTest, CumulativeFrameTimeIsCorrect)
TEST(FrameProfilerFunctionalityTest, GetLastFrameTimeReturnsCorrectValue)
TEST(FrameProfilerFunctionalityTest, GetFPSReturnsCorrectValue)
TEST(FrameProfilerFunctionalityTest, GetDeltaReturnsCorrectValue)
file sleep.hxx
file timer.cxx
file timer.hxx
file timer.test.cxx
#include <gtest/gtest.h>
#include <thread>

Functions

TEST(TimerExceptionTest, ExceptionIsThrownIfTimerIsNotStarted)
TEST(TimerExceptionTest, ExceptionIsThrownIfTimerIsStartedTwice)
TEST(TimerExceptionsTest, ExceptionsIsThrownIfTimerIsStoppedTwice)
TEST(TimerFunctionalityTest, TimerReturnsApproximatelyRightDuration)
TEST(TimerFunctionalityTest, TimerReturnsApproximatelyRightDurationInMilliSeconds)
file singleton.hxx
file window_implementation.hxx
file event_emitter.hxx
#include <GLFW/glfw3.h>
file event_emitter.hxx
#include <concurrentqueue.h>
file window.cxx
file window.cxx
file window.hxx
#include <GLFW/glfw3.h>
file window.hxx
#include <concurrentqueue.h>
#include <glm/glm.hpp>
#include <glm/gtx/norm.hpp>
file window.hxx
file window.test.cxx
#include <gtest/gtest.h>
#include <memory>

Functions

TEST(WindowCreationTest, WindowIsSuccessfullyCreated)
TEST(WindowCreationTest, WindowIsSuccessfullyCreatedWithRValue)
file window_properties.cxx
file window_properties.hxx
page md__home_docs_checkouts_readthedocs_org_user_builds_obscura_engine_checkouts_stable_src_CONTRIBUTING_INSTRUCTIONS

Structure should be as follows:

.
├── Target_1
│   ├── SubTarget_1
│   │   └── ...
│   ├── SubTarget_2
│   │   └── ...
│   └── ...
└── Target_2
    └── ...
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/application
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/concepts
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/window/concepts
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/timer/concepts
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/core
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/dispatcher
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/event_definitions
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/event_loops
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/events
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/exceptions
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/timer/fps
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/window/glfw
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/window/headless
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/logging
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/renderer
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/event_system/scheduler
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/timer
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/utils
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/renderer/vulkan
dir /home/docs/checkouts/readthedocs.org/user_builds/obscura-engine/checkouts/stable/src/obscura/window