Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

149 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Kuma

CI

Lightweight game engine built from scratch in C++ (with Rust where it makes sense).

Kuma is designed for small, indie games β€” prioritizing simplicity, modularity, and ease of use over being everything to everyone.

Status

🚧 Early development β€” core systems being built bottom-up.

What's Working

  • Vulkan renderer β€” graphics pipeline, three pipelines (textured opaque / debug-normal opaque / transparent particle billboards), depth buffer (D32_SFLOAT, standard direct-Z), shader compilation, configurable present mode (vsync / mailbox / immediate). Per-frame instance ring buffer for particle uploads. 96-byte shared push constant range covering view-projection + camera right/up.
  • SDL3 platform layer β€” windowing, event loop, resize handling, relative mouse mode for FPS-style camera look. 4K window (3840Γ—2160) by default in the sandbox.
  • Math β€” Vec2, Vec3, Vec4, Quat, Mat4, perspective + look-at + MVP helpers, slerp, axis-angle and Euler quaternion factories.
  • Transform β€” position + quaternion rotation + scale, producing a model matrix.
  • ECS β€” sparse-set Registry with generational EntityID handles, sparse-set component storage, and view<T...>() queries with structured bindings.
  • Debug overlay β€” Dear ImGui integration with a custom Kuma Dark style and Cascadia Mono font; F3 toggles a default panel (FPS, frame time, 1% low, 60-frame sparkline). Game code calls ImGui::* directly for custom panels.
  • Asset pipeline β€” kuma-bake (Rust) converts source assets (.obj, .png, .jpg, .tga, .gltf, .glb, .wav, .ogg) into the engine's binary formats (.kmesh, .ktex, .ksound, .kmaterial, .kscene). Engine loads only baked binaries at runtime; no source-format parsing in the hot path. CMake invokes kuma-bake during build via kuma_bake_* helpers.
  • Camera β€” reusable perspective camera plus keyboard/RMB-look free-fly controller for debug inspection.
  • Resource system β€” loads .ktex / .kmesh / .kmaterial binaries with path-and-usage-keyed caching. Texture cache distinguishes sRGB (color) from UNORM (data) uploads so normal maps don't get gamma-corrected.
  • Physics β€” Jolt Physics 5.5.0 wired through an opaque kuma::physics API. Dynamic / Static / Kinematic bodies, sphere / box / capsule shapes, fixed-step accumulator with spiral-of-death clamp. Bodies plug into the ECS via a PhysicsBody component.
  • Character controller β€” Kinematic FPS capsule on top of Jolt's CharacterVirtual. Step-and-slide collision, slope detection, auto-step over short obstacles, ground state, pushes dynamic bodies. FpsCameraController reads input and writes both character and camera (mouse-look on yaw + pitch, WASD relative to character yaw, Space jump). T toggles between FPS mode and free-fly camera.
  • Audio β€” miniaudio 0.11 wired through an opaque kuma::audio API. WAV / OGG sounds with 3D positional spatialization (distance attenuation + stereo panning). Dual API: fire-and-forget play_sound / play_sound_at returning generation-checked SoundHandle, and an AudioSource ECS component for long-running music / ambience. kuma-bake sound uses Symphonia to convert .wav to PCM .ksound or pass .ogg bytes through.
  • Scenes β€” Multi-mesh asset loading via kuma::scene::load_and_spawn. kuma-bake scene walks a glTF scene tree, dedups primitive geometry into per-primitive .kmesh files, composes parent-chain world transforms, and writes a .kscene v2 index referencing meshes AND materials. Runtime spawns one ECS entity per node with Transform + MeshRef + MaterialRef.
  • Materials β€” Per-mesh diffuse textures with PBR-ready data layout. kuma-bake extracts glTF materials into .kmaterial files (108-byte header carrying base color, metallic, roughness, alpha mode, plus paths for five PBR texture slots) and dedups referenced textures into .ktex. Runtime allocates one descriptor set per material from a 256-set pool. 5-binding descriptor set layout (diffuse / normal / metallic-roughness / occlusion / emissive) with renderer-owned 1Γ—1 defaults per glTF spec. Current shader samples only diffuse; the other slots wait for lighting.
  • Particles β€” CPU-driven billboard particles. ParticleEmitter ECS component owns a fixed 256-particle SoA pool. One-shot (burst) and continuous emitters share the same component shape. particles::simulate runs in UPDATE phase, particles::render after opaque draws (depth test on, depth write off, alpha blend on). Per-emitter back-to-front sort plus per-emitter draw_order enum (Index / Lifetime / ViewDepth) for within-emitter ordering. Five built-in presets: make_muzzle_flash, make_impact_spark, make_blood_spatter, make_death_poof, make_pickup_sparkle. Sandbox demo: F spawns an icosahedron + impact_spark burst; mouse-1 in FPS mode fires muzzle_flash.
  • Input β€” keyboard & mouse polling with edge detection (pressed/released this frame).
  • Time β€” monotonic delta / total / frame count with anti-spiral clamp.
  • Frame orchestration β€” engine-owned begin_frame() / end_frame() wrapping a 5-phase contract (input β†’ time β†’ update β†’ render β†’ present).
  • Logging β€” severity levels, colored console output.

What's Next

  • Lighting β€” Forward / Forward+ / deferred decision pending. Will pay back the materials work β€” the 5-binding descriptor set finally starts sampling normal / metallic-roughness / occlusion / emissive once a lit shader exists. Render pass refactor (HDR offscreen + depth-prepass capability) likely lands as commit 1.
  • Shadows β€” directional + point light shadow maps, layered on top of lighting.
  • Renderer batching / instancing for static meshes when entity counts make per-entity draw calls a real cost.
  • BC7 / BC5 texture compression, mipmap generation in kuma-bake.
  • MP3 / FLAC support in the audio asset pipeline.

Contributing

See CONTRIBUTING.md for commit conventions, comment style, and code style. TL;DR: Conventional Commits, clang-format on save, public headers don't leak SDL/Vulkan types.

Building

Requirements

  • CMake 3.24+
  • C++20 compiler (MSVC 2022, GCC 12+, or Clang 15+)
  • Vulkan SDK
  • Rust 1.85+ (for the kuma-bake asset baker - install via rustup)

Build & Run

cmake -B build -S .
cmake --build build --config Debug
./build/bin/Debug/sandbox

Or in VS Code: press F5 (launch.json and tasks.json are included).

Sponza scene

The sandbox loads Khronos's standard Sponza with all 25 diffuse textures (~60 MB total). Source files are gitignored; download them once with:

pwsh tools\download_sponza.ps1

After that, cmake --build will bake Sponza.kscene + 103 sibling .kmesh files + 25 .kmaterial files + 25 .ktex files into build/assets/scenes/.

cmake --build invokes cargo automatically to build kuma-bake and bakes the sandbox's source assets into the engine binary format (.kmesh, .ktex) before linking the sandbox executable.

Project Structure

Kuma/
β”œβ”€β”€ engine/                     Engine static library
β”‚   β”œβ”€β”€ include/kuma/           Public API headers
β”‚   β”‚   β”œβ”€β”€ kuma.h              Main entry point
β”‚   β”‚   β”œβ”€β”€ audio.h             Sound playback + listener pose
β”‚   β”‚   β”œβ”€β”€ camera.h            Camera + free-fly controller
β”‚   β”‚   β”œβ”€β”€ character.h         Character controller component
β”‚   β”‚   β”œβ”€β”€ debug.h             ImGui debug overlay
β”‚   β”‚   β”œβ”€β”€ ecs.h               Registry + view + EntityID
β”‚   β”‚   β”œβ”€β”€ fps_camera.h        FPS character + camera controller
β”‚   β”‚   β”œβ”€β”€ input.h             Keyboard and mouse polling
β”‚   β”‚   β”œβ”€β”€ material.h          Material runtime struct + TextureUsage
β”‚   β”‚   β”œβ”€β”€ math.h              Vec2/3/4, Quat, Mat4
β”‚   β”‚   β”œβ”€β”€ particles.h         ParticleEmitter component + presets
β”‚   β”‚   β”œβ”€β”€ physics.h           Jolt-backed physics module
β”‚   β”‚   β”œβ”€β”€ platform.h          exe_relative path helper
β”‚   β”‚   β”œβ”€β”€ renderer.h          Renderer interface
β”‚   β”‚   β”œβ”€β”€ resource_manager.h  Asset loading + caching
β”‚   β”‚   β”œβ”€β”€ scene.h             Multi-mesh scene loading
β”‚   β”‚   β”œβ”€β”€ time.h              Frame delta / total time
β”‚   β”‚   β”œβ”€β”€ transform.h         Position + rotation + scale
β”‚   β”‚   β”œβ”€β”€ window.h            Window management
β”‚   β”‚   β”œβ”€β”€ log.h               Logging system
β”‚   β”‚   └── asset_format.h      On-disk binary format definitions
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ core/               Engine init, frame loop, logging, ECS, debug
β”‚   β”‚   β”œβ”€β”€ platform/           SDL3 windowing, input, paths
β”‚   β”‚   β”œβ”€β”€ renderer/           Vulkan device, swapchain, pipelines, resources
β”‚   β”‚   β”œβ”€β”€ resources/          ResourceManager (.kmesh/.ktex/.kmaterial loading)
β”‚   β”‚   β”œβ”€β”€ physics/            Jolt integration
β”‚   β”‚   β”œβ”€β”€ character/          CharacterVirtual + FpsCameraController
β”‚   β”‚   β”œβ”€β”€ audio/              miniaudio integration
β”‚   β”‚   β”œβ”€β”€ scene/              .kscene parser + spawn
β”‚   β”‚   └── particles/          Sim, render, presets
β”‚   └── shaders/                GLSL shaders (compiled to SPIR-V at build time)
β”œβ”€β”€ sandbox/                    Test application (Sponza walkaround + FX demo)
β”œβ”€β”€ tools/
β”‚   β”œβ”€β”€ kuma-bake/              Rust asset converter (mesh/tex/sound/scene/gltf)
β”‚   └── download_sponza.ps1     Fetch Sponza glTF + textures
β”œβ”€β”€ assets/                     Game-side baked assets (engine defaults)
β”œβ”€β”€ tests/                      GoogleTest unit + integration tests
β”œβ”€β”€ cmake/                      Helper modules (kuma-bake.cmake, etc)
└── .vscode/                    VS Code launch + build tasks

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Game / Application                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        Scene / ECS (Registry, components, views)            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Renderer β”‚  Audio   β”‚ Physics  β”‚Particles β”‚   Character     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Resources (ResourceManager + asset cache)           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              Platform (SDL3 window, input, paths)           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Core (frame loop, time, log, math, debug)           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Dependencies

Library Purpose Integration
SDL3 Windowing, input FetchContent (automatic)
Vulkan GPU rendering System install (Vulkan SDK)
Jolt Physics Rigid body + character FetchContent (automatic)
miniaudio Audio playback Single header, vendored
Dear ImGui Debug overlay FetchContent (automatic)
stb_image Image loading (Rust side via image crate; engine takes baked .ktex only) Indirect
GoogleTest Unit + integration tests FetchContent (automatic)

Rust-side (kuma-bake):

Crate Purpose
gltf glTF / GLB parsing
image PNG / JPG / TGA decoding
tobj OBJ parsing
symphonia WAV / OGG audio decoding
bytemuck Safe POD struct ↔ bytes conversion

License

TBD

About

Lightweight Game Engine - 🐻

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages