Skip to content

Freya

A Vulkan-based rendering engine powered by Skirnir for dependency injection.

Features

  • Vulkan-backed rendering - Modern graphics API with high performance
  • Deferred rendering - G-buffer path with SSAO, TAA, bloom, and HDR composite
  • Composable frame stages - Insert or replace steps in Renderer::EndScene
  • Feature flags - Toggle SSAO / TAA / Bloom and set shaderRoot via options
  • Custom render targets - Offscreen composite via Renderer::SetViewportTarget / ClearOutputTarget, with opaque Vulkan/SDL handles (Renderer::GetImGuiNativeHandles, GetViewportImage) for hosting the scene in an application-level ImGui viewport; quality and vsync via FreyaOptions
  • ImGui seam - Renderer::BeginUI / EndUI open the swapchain UI pass so apps draw Dear ImGui over an offscreen viewport without leaking vk::/SDL types into public headers
  • Asset management - Meshes, textures (file or memory), and PBR materials
  • Skinned animation - AnimGraph, bake, CPU or GPU skin palettes, LOD (see Animation)
  • Event system - Flexible pub/sub event handling for window, keyboard, mouse, and gamepad
  • Builder pattern - Fluent API plus FreyaExtension configure hooks
  • Skirnir integration - IoC container for dependency injection

Headers

#include <Freya/Freya.hpp>    // app surface (no Vulkan / SDL types)

See API boundary and Flexibility.

Dependencies

  • Vulkan SDK
  • SDL3
  • GLM
  • Assimp (for 3D model loading)
  • Skirnir (IoC Container)

Quick Start

#include <Freya/Freya.hpp>

class MainApp final : public fra::AbstractApplication
{
  public:
    explicit MainApp(const skr::Arc<skr::ServiceProvider>& serviceProvider)
        : AbstractApplication(serviceProvider)
    {
        mMeshPool     = serviceProvider->GetService<fra::MeshPool>();
        mTexturePool  = serviceProvider->GetService<fra::TexturePool>();
        mMaterialPool = serviceProvider->GetService<fra::MaterialPool>();
    }

    void StartUp() override
    {
        mRenderer->ClearProjections();
        // Initialize your assets here
    }

    void Update() override
    {
        mRenderer->BeginFrame();
        // Render your scene here
        mRenderer->EndFrame();
    }
};

int main(int argc, const char** argv)
{
    const auto app =
        skr::ApplicationBuilder()
            .WithExtension<fra::FreyaExtension>([](fra::FreyaExtension& freya) {
                freya.WithOptions([](fra::FreyaOptionsBuilder& freyaOptions) {
                    freyaOptions.SetTitle("My App")
                        .SetWidth(1920)
                        .SetHeight(1080)
                        .SetVSync(false)
                        .SetSampleCount(8);
                });
            })
            .Build<MainApp>();

    app->Run();
    return 0;
}

Project Structure

Freya/
├── include/Freya/      # Public headers (Freya.hpp, glm/Skirnir types)
├── src/Freya/          # .cpp + internal Vulkan headers + Vendor/
├── Examples/           # Example applications
├── Shaders/            # GLSL/Vulkan shaders
└── docs/               # Documentation

Configuration

Configure Freya using the FreyaOptionsBuilder:

freya.WithOptions([](fra::FreyaOptionsBuilder& freyaOptions) {
    freyaOptions.SetTitle("My Window")
        .SetWidth(1920)
        .SetHeight(1080)
        .SetVSync(true)
        .SetFullscreen(false)
        .SetSampleCount(4)
        .SetDrawDistance(1000.0f);
});

Available Options

Option Type Default Description
title std::string "Freya Window" Window title
width std::uint32_t 800 Window width
height std::uint32_t 600 Window height
vSync bool true Vertical synchronization
fullscreen bool true Fullscreen mode
sampleCount std::uint32_t 1 Retained for compatibility (scene path is single-sample)
frameCount std::uint32_t 4 Number of frames in flight
drawDistance float 1000.0f Render distance
maxLights std::uint32_t 64 Max analytical lights (kMaxLights)
iblIntensity float 0.7f Image-based lighting scale
exposure float 0.7f HDR exposure before ACES tonemap
ambientIntensity float 0.03f Flat ambient fill
environmentMapPath std::string ./Resources/Environments/studio_small_09_4k.hdr Radiance .hdr (empty = procedural sky)
shadowCascadeCount std::uint32_t 4 Directional CSM cascade count (1–4)
shadowMapResolution std::uint32_t 2048 Shadow map resolution (square)
shadowBias float 0.002f Depth bias when sampling shadows
maxSpotShadows std::uint32_t 4 Max concurrent spot shadow maps
maxPointShadows std::uint32_t 2 Max concurrent point cube shadows
shadowSampleCount std::uint32_t 16 Soft-shadow Poisson taps (1–16)
shaderRoot std::string ./Resources/Shaders SPIR-V directory root
enableSsao bool true Run SSAO compute pass
enableTaa bool true Run TAA resolve + jitter
enableBloom bool true Run bloom extract/blur
ssaoResolutionDivisor uint 2 SSAO res = full / N (1,2,4)
taaCurrentWeight float 0.1 TAA blend toward current
bloomStrength float 0.8 Bloom mix in composite

Use SetShadowQuality / SetSsaoQuality / SetTaaQuality / SetBloomQuality (LowUltra) for presets; runtime mirrors on Renderer.

Use FreyaOptionsBuilder::SetShadowQuality(Low|Medium|High|Ultra) to set resolution, cascades, spot/point slots, and tap count together.

Services

Freya provides the following services via Skirnir's service provider:

Service Type Description
Window skr::Arc<Window> Window management
Renderer skr::Arc<Renderer> Main renderer
EventManager skr::Arc<EventManager> Event system
MeshPool skr::Arc<MeshPool> Mesh asset management
TexturePool skr::Arc<TexturePool> Texture asset management
MaterialPool skr::Arc<MaterialPool> Material asset management
LightService skr::Arc<LightService> Point / directional / spot / area lights
IBLService skr::Arc<IBLService> Environment / irradiance / BRDF LUT
ShadowPass skr::Arc<ShadowPass> CSM / spot / point shadow maps