Skip to main content

primase_core/
lib.rs

1//! primase core: the world store, the core components, the frame, the pass manager and gates.
2//!
3//! See `docs/DESIGN.md` ยง3-4 and CONTRIBUTING.md for the conventions every crate follows.
4//! Game-independent animation descriptions (events, draw groups, material parameters and
5//! controllers) are data only. Readers retain source facts; programs select lowering passes,
6//! and toolkit evaluators supply time-dependent behavior. JSON contracts are in `docs/FORMAT.md`.
7#![deny(clippy::disallowed_methods, clippy::disallowed_types)]
8
9pub mod asset;
10mod atmosphere;
11pub mod report_card;
12pub use atmosphere::{
13    Atmosphere, AutoExposure, ColourLut, ColourMatrix, Exposure, ExposureMeter, Fog, FogFalloff,
14    PostProcessingStatus, PostStage, PostStageStatus, PostStageStatusKind, ReinhardCurve, ToneMap,
15    VolumetricFog,
16};
17pub mod clip;
18mod clip_identity;
19mod clip_transition;
20pub use clip_identity::{ClipKey, ClipLength};
21pub use clip_transition::{EffectBlend, IncomingTransition};
22mod clip_effects;
23pub use clip_effects::{ClipEffects, ClipSpawn};
24mod clip_events;
25pub use clip_events::{ClipEvent, ClipEvents, EventValue, EventValueData};
26mod content;
27pub use content::{ContentNote, DisplayName, NameOrigin, Record};
28mod controller;
29pub use controller::{
30    Controller, ControllerBinding, ControllerLayer, ControllerParameter, ControllerParameterKind,
31    ControllerState, LayerBlending, LayerMask, MaskedJoint, Motion,
32};
33mod draw_groups;
34pub use draw_groups::{DrawGroupDefaults, DrawGroups};
35mod material_parameters;
36pub use material_parameters::MaterialParameters;
37mod primitive_keys;
38pub use primitive_keys::PrimitiveKeys;
39pub mod components;
40pub mod convert;
41pub mod detail;
42mod environment;
43pub mod opening;
44pub mod read_scope;
45pub use environment::{Ambient, AmbientLight, Environment, TimeOfDay};
46mod irradiance_volume;
47mod light_falloff;
48mod light_unit;
49pub use light_falloff::LightFalloff;
50mod light_translucency;
51pub use irradiance_volume::IrradianceVolume;
52pub use light_translucency::LightTranslucency;
53mod spot_frustum;
54pub use spot_frustum::SpotFrustum;
55mod reflection_probe;
56pub use light_unit::{DirectionalLightUnit, LightUnit};
57pub use reflection_probe::{EnvironmentProbeBlend, ProbeMipPolicy, ProbeState, ReflectionProbeRegion};
58pub mod frame;
59pub mod json;
60pub mod layered;
61pub mod ledger;
62mod lod;
63pub mod names;
64pub use lod::{LodChoice, LodForm, Lods, SELECT_LOD, SelectLod};
65mod lod_switch;
66pub use lod_switch::{LodBand, LodBoundary, LodSwitch, LodSwitchView};
67mod texture_forms;
68pub use texture_forms::{SELECT_TEXTURE_FORM, SelectTextureForm, TextureChoice, TextureForm, TextureForms};
69mod texture_switch;
70pub use texture_switch::{
71    TEXTURE_SWITCH_START, TextureSwitch, TextureSwitchState, TextureSwitchView, box_distance, world_box,
72};
73mod marker;
74pub use marker::{Curve, Marker, kind_is_valid};
75pub mod particles;
76pub use particles::ParticleSystem;
77mod spawn;
78pub use spawn::{PLACE_SPAWN, PlaceSpawn, SpawnAt, centre_ground};
79mod collider;
80pub use collider::{Collider, Diagonal, Heightfield, Shape};
81mod draw_order;
82pub use draw_order::{DrawLayer, DrawOrder};
83mod sky_anchor;
84pub use sky_anchor::SkyAnchor;
85mod material_usage;
86pub use material_usage::MaterialUsage;
87mod water_body;
88pub use water_body::{WaterBody, WaveLayer};
89mod vertex_color;
90pub use vertex_color::{VertexColor, color0_drawn, uses_color0};
91pub mod morphs;
92pub mod parallel;
93pub mod pass;
94mod pass_options;
95pub mod pbr;
96pub mod print;
97pub mod provenance;
98pub mod render_graph;
99mod step_bindings;
100pub use step_bindings::{StepBinding, StepBindings, StepDraws, StepProgram};
101pub mod rig;
102pub mod shader;
103pub mod skeleton;
104pub mod skin;
105pub use asset::{
106    Asset, AssetField, PARTITION_BY_ASSET, PLACE_ASSETS, PartitionByAsset, PlaceAssets, Role, SELECT_ASSETS,
107    SelectAssets,
108};
109pub use clip::{
110    AdditiveReference, Channel, Clip, ClipBinding, ClipTarget, Extrapolation, Interpolation, Property,
111    RootMotion, RootSpace,
112};
113pub use morphs::{Deltas, Frame as MorphFrame, MorphId, Morphs, Target as MorphTarget};
114pub use provenance::{Origin, Provenance};
115pub use rig::{
116    Attachment, JointMap, JointOffset, JointPlacement, MorphWeights, RigInstance, RigPose, SkinInstance,
117    Socket, SocketId, Sockets,
118};
119pub use skeleton::{AssemblyReference, Joint, JointId, Rest, Skeleton};
120pub use skin::{Binding, BindingId, Deformation, Influences, Skin, Slot, WeightRule};
121mod priority;
122pub use priority::{DROP_OPTIONAL, DropOptional, Priority};
123pub mod state;
124pub mod summary;
125pub mod texformat;
126mod texture_layers;
127pub use texture_layers::{TextureLayers, TextureShape};
128pub mod translate;
129mod unreferenced;
130pub use unreferenced::{DROP_UNREFERENCED_TEXTURES, DropUnreferencedTextures};
131pub mod vector;
132pub mod world;
133
134pub use components::*;
135pub use detail::DetailedMaterial;
136pub use json::JsonError;
137pub use layered::{Layer, LayerWeights, LayeredMaterial, WeightMapping};
138pub use texformat::TexFormat;
139pub use world::{
140    Column, ColumnMut, Component, ComponentJson, ComponentJsonError, Dropped, Entity, Geometry, IdError,
141    Linearity, NameClash, Opaque, OpaqueData, Part, Resource, VertexBlend, World, remap_list,
142};
143
144/// Register core's generic passes by their declarations, as every crate registers its own: a program builds its
145/// registry from these. What each takes: [`pass::PassRegistry::describe`], or the declaration ([`SELECT_LOD`],
146/// [`SELECT_TEXTURE_FORM`],
147/// [`DROP_OPTIONAL`], [`DROP_UNREFERENCED_TEXTURES`], [`PLACE_SPAWN`], [`PLACE_ASSETS`], [`SELECT_ASSETS`], [`PARTITION_BY_ASSET`],
148/// [`state::RESOLVE_STATE`], [`state::SELECT_OUTFIT`], [`shader::SELECT_VARIANT`],
149/// [`translate::TRANSLATE_WORLD`]).
150pub fn register(reg: &mut pass::PassRegistry) {
151    for spec in [
152        &SELECT_LOD,
153        &SELECT_TEXTURE_FORM,
154        &DROP_OPTIONAL,
155        &DROP_UNREFERENCED_TEXTURES,
156        &PLACE_SPAWN,
157        &PLACE_ASSETS,
158        &SELECT_ASSETS,
159        &PARTITION_BY_ASSET,
160        &state::RESOLVE_STATE,
161        &state::SELECT_OUTFIT,
162        &shader::SELECT_VARIANT,
163        &translate::TRANSLATE_WORLD,
164    ] {
165        reg.add(spec);
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    /// Core registers exactly these passes by their declarations: the ones with a required option or group are made
172    /// only with their options, every one says what it takes, and a pipeline without a required option is refused in
173    /// the declaration's words.
174    #[test]
175    fn the_core_passes_register_by_name() {
176        let mut reg = crate::pass::PassRegistry::new();
177        super::register(&mut reg);
178        let names = [
179            "drop-optional",
180            "drop-unreferenced-textures",
181            "partition-by-asset",
182            "place-assets",
183            "place-spawn",
184            "resolve-state",
185            "select-assets",
186            "select-lod",
187            "select-outfit",
188            "select-texture-form",
189            "select-variant",
190            "translate-world",
191        ];
192        assert_eq!(format!("{reg:?}"), format!("{names:?}"));
193        let requiring = [
194            "place-spawn",
195            "select-assets",
196            "select-lod",
197            "select-outfit",
198            "select-texture-form",
199            "select-variant",
200            "translate-world",
201        ];
202        for name in names {
203            assert_eq!(reg.requires_options(name), requiring.contains(&name), "{name}");
204            let described = reg
205                .describe(name)
206                .unwrap_or_else(|| panic!("{name} has no declaration"));
207            assert!(described.starts_with(name), "{described}");
208            let bare = reg.make(name, &crate::pass::Options::new());
209            assert_eq!(bare.is_err(), requiring.contains(&name), "{name}");
210        }
211        let refused = |name: &str| {
212            reg.make(name, &crate::pass::Options::new())
213                .err()
214                .unwrap()
215                .to_string()
216        };
217        assert_eq!(
218            refused("translate-world"),
219            "pass translate-world: by is required: X,Y,Z, metres in core's frame: the offset is the program's choice"
220        );
221        assert!(
222            refused("select-assets").starts_with("pass select-assets: one of keys or names is required (")
223        );
224        assert!(refused("select-lod").starts_with("pass select-lod: form is required: "));
225        assert!(refused("place-spawn").starts_with("pass place-spawn: one of at or east is required ("));
226        assert!(
227            reg.describe("select-assets")
228                .unwrap()
229                .starts_with("select-assets{(keys|names)*}\n")
230        );
231    }
232}