Skip to main content

Architecture

Rhea is a modular C++ framework for building virtual worlds and interactive 3D applications. An application combines the engine runtime, selected capabilities, and the platform integrations it needs.

This page introduces the main boundaries and follows the application model used in Getting Started and Your First Project. Rhea is experimental; its interfaces and composition mechanisms may change. An editor is planned but is not included in the initial public release.

Engine and rendering layers​

The SDK separates application and scene management from rendering:

Your application
|
+-- Rhea Engine
| +-- application lifecycle
| +-- scenes, objects, components, and resources
| +-- services and selected Fabrics
|
+-- RheaClient
+-- Poseidon renderer
+-- Hippios graphics backend

The diagram shows the main composition of a graphical application, rather than every library dependency. Platform, input, audio, and physics integrations support this composition.

Library or integrationResponsibility
Rhea (Rhea::Core)Application runtime, object hierarchy, scenes, resources, and service coordination.
RheaClient (Rhea::Client)Connects the engine to Poseidon for the standard graphical client.
PoseidonRendering abstractions and the rendering pipeline; can also be used independently of Rhea.
HippiosGraphics and platform backends used by the rendering stack.
PsioPlatform facilities used by the runtime, including input and I/O support.
OrionResource addressing and access to resource data.
RheaPhysics / RheaPhysicsBulletPhysics interfaces and the supplied Bullet integration.
RheaAudioAudio integration using miniaudio.

A graphical application normally links the engine, client, and selected Fabrics. Applications that do not need rendering can use the engine without the client and rendering layers. Linking only the core is not itself a complete headless configuration: the application must also select appropriate services and Fabrics.

Application lifecycle​

Applications derive from rhea::Application. BasicApp illustrates the startup sequence:

BasicApp app;
app.setAppname("BasicApp");
app.init(argc, argv);
app.setup();
return app.loop();

This is an excerpt from the sample; BasicApp supplies the application-specific overrides.

  1. init() prepares the runtime, registers core types, creates the application tree, and registers the selected Fabrics.
  2. setup() initializes services. BasicApp calls the base implementation before loading resources and constructing its scene.
  3. loop() processes input and I/O, runs service update phases, and invokes the application's frame callbacks.

The runtime provides onFrameBegin() and onFrameEnd() hooks. Input travels through events in the object tree; unhandled input can reach the application's onInput() override. In BasicApp, Escape sets an exit flag that onFrameEnd() returns to the runtime.

Rendering and other subsystem work are supplied through the configured services. Choose update hooks according to the subsystem's lifecycle; there is no guarantee of an ordering between unrelated services within the same update phase.

Units, scenes, and components​

The runtime maintains a UnitTree. It is a hierarchy used to organize objects, find them by path, and dispatch events.

ConceptRole
UnitA node that can contain child components, including other Units.
UnitTreeThe application's root hierarchy, with helpers for object creation and binding lookup.
RealmA named grouping in the hierarchy; BasicApp places its scene under a basic_app Realm.
SceneGroups related scene objects and provides scene readiness, visibility, and activation operations.
ItemA scene object with a spatial role; components add behavior or visual representation.
ComponentA building block attached to an object, such as a transform, mesh association, or physics data.

For example, BasicApp creates a scene containing a camera, lighting, and a cube Item. The cube uses a VisualComponent and MeshComponent, with a procedural mesh and material.

This is a hierarchical object and component model. Scene contents can be created directly in C++, as in BasicApp, or constructed from loaded scene definitions.

Object lifetime​

The hierarchy participates in ownership: the current Unit destructor deletes its child components. Pointers retrieved from the tree are not independent owners. Avoid deleting attached children directly or giving them a second owning pointer; use the relevant attachment and removal lifecycle.

Removal and destruction are distinct operations whose behavior depends on the API. Code that stores pointers to scene objects must account for those objects being removed or destroyed. The application owns its UnitTree and registered Fabric instances through std::unique_ptr; services use a separate registration and lifecycle mechanism.

Fabrics and services​

A Fabric groups the code that adds a capability to an application. It may register types, resource loaders, services, components, or other subsystem integration. Examples include geometry, asset-format support, animation, terrain, text, and GUI.

A service provides an application-level runtime function. For example, resource loading is exposed through a resource service. Services participate in initialization and frame processing and can be looked up through Application::getService().

The distinction is between assembling a capability and providing its runtime behavior. Fabrics are registered during the build; the generated registry creates selected Fabric instances, which register their capabilities when the application initializes.

Applications may add their own Fabrics or supply alternative subsystem implementations. Replacement requires compatible interfaces and registrations when other selected capabilities depend on them.

Resources and assets​

Resource loading connects external asset data to runtime objects:

Resource identifier
-> resolve asset data
-> load the requested resource type
-> use the resource in the application or scene

BasicApp loads an engine shader and an application texture using identifiers such as:

//rhea/shaders/standard.shader
//basic_app/kies.png

These are resource identifiers, rather than ordinary operating-system paths. Their resolution depends on the resource configuration. In the introductory examples, the build stages assets beside the executable:

Data/
rhea/ engine assets
basic_app/ sample or application assets

Use rhea_copy_assets() to stage these directories in your own project, as described in Your First Project. Resource loading may be asynchronous; do not assume that every request finishes before the calling function returns.

Scene resources and instances​

A loaded .scene resource describes a reusable object structure. A scene instance is a runtime tree created from that definition. Loading the resource alone does not place an instance in the world.

See Runtime Scene Instancing for scene definitions, references, and instantiation.

Build-time composition and runtime setup​

Rhea uses CMake for integration and capability selection. The two stages have different responsibilities:

Build timeRuntime
Select engine libraries and backend integrations.Initialize configured services and platform facilities.
Register Fabrics and select a Fabric profile.Register the capabilities supplied by selected Fabric instances.
Generate registries using Python.Load assets and create scenes and objects.
Compile code and stage application assets.Process input and execute update phases.

For a consumer project using add_subdirectory, the composition sequence is:

  1. Set project options and, optionally, RHEA_ENABLED_PROFILE_JSON.
  2. Include Rhea/cmake/rhea_project.cmake.
  3. Add the engine and any additional packages that register Fabrics.
  4. Link the application to its engine libraries and RheaFabrics.
  5. Call rhea_project_end() after Fabric registration is complete.

An enabled.json profile selects registered Fabrics for the generated registry. When no profile is supplied or discovered, all registered Fabrics are enabled. This mechanism assembles capabilities at build time; it is not a runtime plugin loader.

Python generates the Fabric registry and, when enabled, the type registry used by development tools. It is a build dependency, not an embedded runtime scripting language. mwpkg can help organize packages, but standard CMake integration does not require it.

Where to add your own functionality​

You want to…Start with…
Define application startup and scene constructionAn Application subclass, following BasicApp.
Add behavior or data to scene objectsThe component model and the relevant object lifecycle.
Load another asset formatResource types and resource loaders.
Provide an application-wide runtime functionA service and its initialization and update hooks.
Package reusable engine capabilitiesA Fabric that registers the required types and integrations.
Use a different subsystem implementationIts interface boundary and the requirements of dependent capabilities.

Start with Your First Project for a complete integration structure. Extend one capability at a time before changing lower-level backends.