Lysa Nodes  0.0
Lysa Nodes — Scene Graph for the Lysa Engine
Architecture overview

Overview

Lysa Nodes is organized as a set of C++23 modules (.ixx interfaces paired with .cpp implementations) that live in the lysa::nodes namespace. The single top-level module lysa.nodes re-exports every public node type and serves as the only import needed by application code.

The library sits on top of the Lysa Engine and relies entirely on the engine context (lysa::ctx()) for rendering, physics, resource management, and event dispatch. It does not introduce any additional singletons.

Entry Point — SceneTree

lysa::nodes::SceneTree is the root of every scene. It extends the engine's lysa::Scene class and owns a flat list of root Node children. The SceneTree:

  • Attaches to a RenderingWindow or RenderTarget to receive render callbacks.
  • Subscribes to the engine event system for PROCESS, PHYSICS_PROCESS, input, resize, pause, and resume events, and fans them out to its node tree.
  • Provides addChild / removeChild template methods to safely insert or remove nodes within the correct frame boundary.

Virtual callbacks (onReady, onProcess, onPhysicsProcess, onInput, onResize, onPause, onResume, onAttach, onDetach) are intended to be overridden by application-level subclasses.

Node Base Class

lysa::nodes::Node is the base of every scene object. Key responsibilities:

Concern Details
Identity Unique unique_id, display name, Type enum, and optional group membership
Transform Local and world-space float4x4 matrices; decomposed helpers for position, rotation (quaternion + Euler), and scale
Hierarchy addChild / removeChild templates; findFirstChild, findAllChildren, getChildByPath, getRelativePath
Lifecycle onReady, onEnterScene, onExitScene, onProcess, onPhysicsProcess, onInput virtual hooks
Visibility setVisible / isVisible; propagated to mesh instances in VRAM
Duplication duplicate() produces a deep copy of the subtree
Process mode ProcessMode enum controls whether a node processes while the scene is paused

The internal _process, _physicsProcess, _enterScene, _exitScene, _ready, _pause, _resume, and _input methods are called by the SceneTree and should not be invoked directly by application code.

Node Hierarchy

Node
├── Camera (also lysa::Camera resource)
├── AnimationPlayer
├── Environment
├── Viewport
├── MeshInstance
├── Light (also lysa::Light resource)
│ ├── DirectionalLight
│ └── OmniLight
│ └── SpotLight
└── CollisionObject (also lysa::CollisionObject resource)
├── CollisionArea
├── Character
├── PhysicsBody
│ ├── StaticBody
│ ├── KinematicBody
│ └── RigidBody
└── RayCast (also lysa::RayCast resource)

Rendering Nodes

Camera

lysa::nodes::Camera extends both Node and the engine's lysa::Camera resource. It supports perspective (FOV + near/far) and orthographic (left/right/top/bottom + near/far) projections. When attached to a scene, the camera registers a resize handler so the projection matrix is automatically updated when the render target changes size. The active camera is set on the SceneTree via setCamera().

MeshInstance

lysa::nodes::MeshInstance wraps a lysa::MeshInstance GPU resource. Each surface can have an override Material that replaces the mesh's original material for that surface. Shadow casting is configurable per instance. The world-space AABB is kept up to date whenever the global transform changes.

Environment

lysa::nodes::Environment sets the ambient light color and intensity for the scene. Only one Environment node is active at a time; attaching it to the scene registers its values with the renderer.

Viewport

lysa::nodes::Viewport overrides the renderer's viewport rectangle and scissor. If no Viewport node is present in the scene, the full render target surface is used.

Light Nodes

All light nodes inherit from lysa::nodes::Light which manages color, intensity, shadow-map parameters, and registration with the engine's light pool (up to Light::MAX_LIGHTS per scene).

Node Description
DirectionalLight Parallel light (sun-like). Supports cascaded shadow maps (up to MAX_SHADOW_MAP_CASCADES = 3 cascades, configurable split lambda).
OmniLight Point light with configurable range and near-clip distance for shadow cube maps.
SpotLight Extends OmniLight with inner and outer cone cutoff angles.

Physics Nodes

Physics nodes mirror the engine's collision-object hierarchy and delegate all physics work to the active backend (Jolt or PhysX). The backend is selected exclusively at compile time.

CollisionObject

lysa::nodes::CollisionObject is the base for all physics nodes. It forwards position and rotation changes to the physics body, subscribes to the engine's contact/collision events, and routes them through the node's onEnterScene / onExitScene lifecycle.

CollisionArea

lysa::nodes::CollisionArea is a passive sensor. It detects overlapping bodies (via CHARACTER_COLLISION_STARTS events) without generating reaction forces.

PhysicsBody and Subclasses

lysa::nodes::PhysicsBody is the base for active bodies:

Class Motion Type Description
StaticBody Static Immovable solid; other bodies collide with it
KinematicBody Kinematic Moved by explicit velocity; ignores forces
RigidBody Dynamic Fully simulated; responds to forces, impulses, and gravity

RigidBody exposes density, mass, gravity factor, per-frame force application (addForce, addImpulse), and linear velocity read/write.

Character

lysa::nodes::Character uses a virtual capsule controller (Jolt CharacterVirtual or PhysX PxCapsuleController). It provides:

  • Ground detection (isOnGround, isGround, getGroundVelocity).
  • Collision list via getCollisions().
  • Up-vector configuration for sloped surfaces.
  • Maximum slope angle and explicit velocity control.
  • CharacterEventType::ON_COLLISION event fired on each contact.

RayCast

lysa::nodes::RayCast performs a layer-filtered ray query each physics tick from its world-space position toward a local-space target point. The result is available via getCollider().

Animation

lysa::nodes::AnimationPlayer manages one or more AnimationLibrary instances. Each library contains named Animation objects composed of AnimationTrack keyframe channels (position, rotation, scale). Playback features include:

  • play(name) / playBackwards(name) / stop(keepState) / seek(seconds).
  • Auto-start on scene entry.
  • AnimationPlayerEvent::START and FINISH events dispatched through the engine event system.
  • setTargetPath to redirect all track targets to a different node path.

Asset Loading

The lysa::nodes module provides two free functions that instantiate node trees from Lysa asset packs (.lys files exported by the Blender add-on):

Function Description
load(URI) Synchronous load; blocks until the node tree is ready
loadAsync(URI, callback) Loads on a background thread; invokes callback at the start of the next frame

Both functions return a std::shared_ptr<Node> pointing to the root of the loaded subtree.

Lua Scripting

When the engine is compiled with LUA_BINDINGS=ON, every node type inherits from LuaScript and exposes its full public API to Lua via LuaBridge. Lua callbacks integrate with the same EventManager::on() mechanism used by C++ listeners, enabling hybrid C++/Lua scene hierarchies.