Files
snow_trail/.pi/skills/panopticon/structure.md
2026-04-05 09:29:49 +02:00

12 KiB

Structure

Modules

src/entity.rs

Manages entity lifecycle with EntityHandle (u64 alias) and EntityManager tracking alive entities. Entities are opaque IDs; all data lives in component storages on World.

src/world.rs

Core ECS container holding EntityManager, 20+ typed Storage<T> collections (one per component type), and intent queues (follow_player_intents, stop_following_intents, camera_transition_intents). One-frame intents are inserted and consumed within a single frame. World also holds singleton state: snow_layer, debug_mode, gizmo_mesh.

src/components/

Component types define entity data. Key storages:

  • Transforms (Transform): position, rotation, scale
  • Physics (PhysicsComponent): rapier3d rigidbody/collider handles
  • Movement (MovementComponent): walking speed, acceleration, damping state
  • Jump (JumpComponent): jump height, air control, jump curve
  • State machines (stored per-entity): IdleState, WalkingState, JumpingState, FallingState, LeapingState, RollingState
  • Input (InputComponent): current move direction, jump/parry key states
  • Camera (CameraComponent): FOV, aspect, yaw/pitch; CameraTransition for animated transitions
  • Dialog (DialogBubbleComponent, DialogProjectileComponent, DialogSourceComponent): Ink story state, projectile tracking, outcome events
  • Rendering (MeshComponent): mesh reference, pipeline, instance buffer, dissolve/snow-light flags
  • Misc: FollowComponent, RotateComponent, DissolveComponent, TriggerComponent, ParticleEmitterConfig

src/states/state.rs

Per-entity state machine: StateMachine holds current TypeId, registered state types, and transitions. State trait defines lifecycle (on_enter, on_physics_update, on_exit). Transitions are condition predicates checked each update. Player entity uses this for locomotion states.

src/systems/

Flat list of update functions called in main loop. No cross-system coupling; all communication via world state and intents.

  • Camera: camera_input_system → generates intents; camera_intent_system consumes them; camera_follow_system (follows player), camera_noclip_system, camera_transition_system, camera_ground_clamp_system
  • Input: player_input_system reads SDL3 InputState, writes InputComponent
  • Physics: state_machine_physics_system (fixed-step), PhysicsManager::physics_step(), physics_sync_system (copies rapier bodies back to transforms), trigger_system (AABB overlap → events)
  • Dialog: dialog_system (ticks story state), dialog_projectile_system (moves projectiles), dialog_camera_system (focuses camera on speaker), dialog_bubble_render_system (generates billboard/text draw calls)
  • Rendering: render_system collects DrawCall from meshes/transforms; spotlight_sync_system syncs light positions to shader uniform
  • State machine: state_machine_system (per-frame), state_machine_physics_system (fixed-step) tick state lifecycle
  • Trees: tree_occlusion_system (culls trees behind camera), tree_dissolve_update_system (animates dissolve), tree_instance_buffer_update_system (writes GPU buffer)
  • Snow: snow_system deforms snow layer at physics contacts; particle_intent_system/particle_update_system manage particle emitters
  • Rotate: rotate_system rotates entities by delta

src/bundles/

Factory functions to spawn pre-configured entity groups:

  • PlayerBundle: player character with all locomotion components
  • TestCharBundle: test NPC
  • CameraBundle: camera entity
  • TerrainBundle: terrain mesh + collider
  • SpotlightBundle + spawn_spotlights(): light entities from scene data

src/render/

GPU rendering pipeline via wgpu. Singleton Renderer stored in thread-local (global.rs).

  • Renderer: wgpu device/queue/surface, framebuffer, pipelines, bind groups, shadow map texture, spotlight data
  • DrawCall (types.rs): vertex/index buffers, model matrix, pipeline enum, instance buffer, entity ref
  • Pipelines (pipeline.rs): create_main_pipeline(), create_snow_clipmap_pipeline(), create_wireframe_pipeline(), create_shadow_pipeline(), create_debug_lines_pipeline()
  • Uniforms (types.rs): model/view/projection, 4 spotlights, camera position, height scale, player position, time, tile scale, debug mode
  • Shadow: render_shadow_pass() renders scene depth to shadow map from each spotlight
  • Snow: SnowLayer deforms snow heightfield via compute; ClipmapConfig manages multi-level clipmap grid; deform_at_position() marks terrain changed
  • Snow light: SnowLightAccumulation ping-pong texture accumulates light contributions from spotlights onto snow surface
  • Billboard pipeline + Text pipeline: render dialog bubbles and text overlays
  • Particle pipeline: billboarded particles with per-instance color/velocity
  • Font atlas: pre-rasterized glyph texture from embedded font file

src/loaders/

Load scene data from glTF files:

  • scene.rs Space::load_space(): loads meshes, lights, player spawn, test char spawn from single glTF
  • mesh.rs Mesh::load_gltf_with_instances(): parses glTF buffers, vertex/index data, multi-instance mesh batches; InstanceData (position/rotation/scale/dissolve); Vertex (position/normal/UV)
  • lights.rs: extracts spotlight transforms/params from glTF nodes
  • empty.rs: extracts named empty (spawn point) transforms from glTF
  • heightmap.rs: loads EXR heightfield texture for terrain collision
  • terrain.rs: builds rapier heightfield collider from EXR matrix

src/physics.rs

Thread-local PhysicsManager wrapping rapier3d. physics_step() runs one integration step; add_rigidbody(), add_collider() register bodies; raycast() queries. HeightfieldData caches terrain height matrix.

src/utility/

  • transform.rs Transform: matrix conversions to/from nalgebra Isometry3; getters/setters for position/rotation/scale
  • input.rs InputState: SDL3 key states (WASD, Space, Shift, Ctrl) and mouse delta; handle_event() updates state; clear_just_pressed() resets one-frame flags
  • time.rs: Time::get_time_elapsed() returns seconds since init (static Instant)

src/debug/

  • mode.rs DebugMode enum: None, Normals, UV, Depth, Wireframe, Colliders, ShadowMap, SnowLight; cycle() steps through
  • collider_debug.rs: renders rapier collider AABBs as line meshes
  • gizmo.rs: renders 3D transform gizmo (position/rotation/scale) for editor

src/editor/

  • inspector.rs Inspector: wraps Dear ImGui context; render() draws frame to texture; build_ui() draws entity inspector panels
  • mod.rs EditorState: manages editor active state, selected entity, mouse capture; editor_loop() calls inspector, handles picking

src/picking.rs, src/postprocess.rs, src/texture.rs, src/paths.rs

Utility modules: ray casting for mouse pick, fullscreen blit/framebuffer downsampling, dither/flowmap texture loading, paths to asset files.

Data Flow

  1. Initialization (main.rs init()): SDL3 window → wgpu renderer (Vulkan) → World creation → load scene (Space from glTF) → spawn bundles (player, terrain, camera, lights) → initialize physics
  2. Main loop (main.rs main() with 60 Hz fixed physics + variable-rate graphics):
    • Per-frame (delta): Input events → player_input_system (fills InputComponent) + camera_input_system (generates intents)
    • Intent processing: camera_intent_system consumes intents, updates CameraComponent/CameraTransition
    • Camera systems: follow player, noclip, transition, clamp to ground
    • Fixed physics (1/60s accumulator):
      • state_machine_physics_system: tick state's on_physics_update()
      • PhysicsManager::physics_step(): rapier integration
      • physics_sync_system: copy rigidbody poses to Transform
      • trigger_system: detect collisions, emit events
      • dialog_system, dialog_projectile_system: Ink story tick, projectile movement
    • Per-frame systems: state_machine_system (non-physics update), rotate, particle, tree dissolve, snow deformation, spotlight sync
    • Render collection: render_systemVec<DrawCall> from all meshes; snow layer adds clipmap draw calls; debug adds collider/gizmo calls
    • Submission: submit_frame() renders draw calls, dialog bubbles/text, particles to framebuffer; blit to screen; optional ImGui overlay
  3. Frame cleanup: InputState::clear_just_pressed() (flags reset for next frame)

Key Types

Type Module Description
EntityHandle entity u64 opaque entity ID
Storage<T> world HashMap storage for per-entity component data
World world ECS container: entities, 20+ storages, intent queues, singleton state
Transform utility/transform Position (Vec3), rotation (Quat), scale (Vec3); matrix conversions
StateMachine states/state Per-entity state machine: current state TypeId, registered states, transitions
State trait states/state Lifecycle: on_enter, on_physics_update, on_exit, on_update
PhysicsComponent components/physics Rapier3d rigidbody + optional collider handles
MovementComponent components/movement Walking speed, acceleration, damping, context (floored, last floor time)
JumpComponent components/jump Jump height, duration, air control, context (in progress, origin height)
CameraComponent components/camera FOV, aspect, yaw/pitch angles, is_active flag
InputComponent components/input Current frame: move direction, jump/parry key states (flags)
MeshComponent components/mesh Mesh ref, pipeline enum, instance buffer, dissolve/snow-light flags
DialogBubbleComponent components/dialog Ink story, current text, dialog phase (displaying/projectile in flight), parry button
DrawCall render/types GPU command: vertex/index buffers, model matrix, pipeline, instance count, entity ID
Uniforms render/types Per-frame shader data: matrices, spotlight array, debug flags
Renderer render/mod GPU state: device, queue, surface, all pipelines, framebuffer, texture samplers
Space loaders/scene Loaded scene: mesh batches, spotlight data, spawn positions
Mesh loaders/mesh GPU vertex/index buffers, AABB, CPU vertex data for physics
SnowLayer render/snow Snow heightfield: deform bind groups, depth texture, clipmap grid levels
SnowLightAccumulation render/snow_light Ping-pong textures + pipeline accumulating spotlight contributions onto snow
InputState utility/input SDL3 event state: key flags, mouse delta, relative mode
PhysicsManager physics Rapier3d bodies/colliders/pipeline; thread-local singleton
DebugMode debug/mode Enum: None, Normals, UV, Depth, Wireframe, Colliders, ShadowMap, SnowLight

Entry Points

  1. main() in src/main.rs
    • Calls init() → initializes SDL3, wgpu, loads world from scene glTF, spawns entities
    • Runs infinite loop: event poll → systems (camera/input/physics/render) → frame submit → sleep to 60 Hz
  2. Game::init() in src/main.rs
    • SDL3 window + Vulkan surface
    • Renderer::new() initializes all GPU pipelines and textures
    • init_world() loads space, spawns bundles, sets up terrain/snow/lights
  3. World::new() in src/world.rs
    • Creates empty storages for all 20+ component types and intent queues

Dependencies

  • Engine: wgpu (GPU), rapier3d (physics), glam (math), nalgebra (nalgebra for physics conversions), SDL3 (windowing/input)
  • Content: bladeink (Ink story scripting), image crate (EXR heightmaps), gltf (scene loading)
  • Editor: Dear ImGui via imgui crate + SDL3 integration
  • Internal: All systems read/write World; systems are called in fixed sequence from main loop; no circular dependencies
  • Thread-local singletons: Renderer (render/global.rs), PhysicsManager (physics.rs), GLOBAL_RENDERER, GLOBAL_PHYSICS

Initialization Order

  1. SDL3 init → window creation → Vulkan adapter/device
  2. Renderer::new() → wgpu device/queue, create all pipelines, load textures (dither, flowmap, font atlas, shadow map, blue noise)
  3. Load scene from glTF → meshes, lights, spawns
  4. Spawn bundles: player (with input/movement/jump/state machine), terrain (mesh + heightfield collider), camera (follows player), lights (spotlights)
  5. Initialize snow layer (deform by tree positions)
  6. Initialize snow light accumulation (bind to spotlight data)
  7. Main loop: process events → run systems in sequence → submit frame