1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! Concinnity is a graphics application framework. A [`World`] holds the
//! components describing what exists -- a camera, lights, geometry, text -- and
//! an [`App`] runs that world on the engine's loop. Behaviour is declared as data
//! rather than assembled from calls, so an application's job is to hand over a
//! world and let the runtime drive it.
//!
//! # Running a compiled world
//!
//! A shipped application usually plays a world that was compiled ahead of time.
//! That needs nothing but the runtime, which is the crate's default build:
//!
//! ```rust,no_run
//! use concinnity::App;
//!
//! fn main() {
//! App::from_blob("my_game.cnb")
//! .expect("my_game.cnb holds a compiled world")
//! .run()
//! .expect("the app runs");
//! }
//! ```
//!
//! Worlds are authored and compiled by the `cook` module, which is where to go
//! next: it declares assets as typed values, resolves the references between
//! them, and either compiles a [`World`] in memory or writes one out for a
//! build like the above to play. It sits behind the `cook` feature, off by
//! default.
//!
//! # Assembling a world in code
//!
//! Compiling is not always needed. Every type in the [`components`] vocabulary
//! can be handed straight to [`World::add_component`], so an application built
//! only from those runs on the default feature set alone -- no authoring step
//! and no file on disk.
//!
//! Adding a [`GraphicsConfig`](components::GraphicsConfig) is what opens a
//! window. A world without one still runs, with everything but the rendering,
//! which is how a test or a simulation-only tool drives one:
//!
//! ```no_run
//! use concinnity::components::{PhysicsConfig, TriggerVolume};
//! use concinnity::{App, World};
//!
//! fn main() {
//! let mut world = World::new();
//! world.add_component(PhysicsConfig::default());
//! world.add_component(TriggerVolume {
//! position: [0.0, 1.0, 0.0],
//! ..Default::default()
//! });
//!
//! App::from_world(world).run().expect("the app runs");
//! }
//! ```
//!
//! # Composing vs Cooking
//!
//! Add components directly when a world is small, or when it is decided at
//! runtime and there is nothing to prepare in advance. Reach for the `cook`
//! module when an asset needs work before it can run: an image or model to read
//! from disk, a room to generate geometry for, a prefab to expand into the
//! components it stands for. Both end at the same place, an `App` holding a
//! [`World`], and one application can use both.
//!
//! # Features
//!
//! The default build is the runtime alone: the world loop, the renderer, and
//! the [`components`] vocabulary, which is all the examples above need.
//!
//! `--features cook` adds the `cook` module described above. It carries the authoring half
//! of the vocabulary (textures, meshes, prefabs, menus) and pulls in the
//! importers that read them (glTF, FBX, images, fonts), so an application that
//! only plays an already-compiled world should leave it off.
//!
//! `--features vulkan` selects the Vulkan backend where the platform default is
//! Metal or DirectX.
//!
//! `--features player` builds `concinnity-run`, the standalone binary that plays
//! a compiled world, and `--features dev` builds both it and the `concinnity`
//! command-line tool. Both are for working on an application rather than for
//! linking one: nothing in the library's own API depends on either, and with
//! neither enabled this crate builds no build dependency at all.
//!
//! `--no-default-features` leaves the core `no_std` runtime: the component
//! vocabulary, a [`World`] to hold it, and a headless [`App`] that steps it,
//! with no operating system underneath.
// The test harness is a std program whichever tier is built, so the `no_std`
// build still gets one.
extern crate std;
pub use App;
pub use World;
/// The runtime component vocabulary (`Camera3D`, `Room`, `DirectionalLight`,
/// `Transform`, ...): every type a [`World`] holds, each addable with
/// [`add_component`](World::add_component).
///
/// A type an application authors but a world never stores -- a `Texture`, a
/// `Prefab`, a `MainMenu` -- belongs to the `cook` namespace instead. Where a
/// name is in both, the authoring form is `cook::X` and the runtime form
/// `components::X`; glob this module and path-qualify `cook`, since the twinned
/// names are ambiguous under two globs.