Skip to content

Commit efa0101

Browse files
committed
Add more docs.
1 parent a4e4e1e commit efa0101

File tree

1 file changed

+33
-3
lines changed

1 file changed

+33
-3
lines changed

docs/principles.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,39 @@ destroyed.
9393

9494
### Bridging Bevy and immediate-mode APIs
9595

96-
By default, Bevy is highly optimized for throughput and includes automatic parallelization, pipelined rendering, and
97-
sophisticated rendering batching algorithms. This poses a problem for Processing which wants to present an
98-
immediate-mode API where the user can flush their current draw state to a given surface at any time.
96+
The central architectural challenge of libprocessing is reconciling two fundamentally different models of how graphics
97+
programming works.
98+
99+
Immediate mode treats drawing as a sequence of imperative commands: when you call `rect(10, 10, 50, 50)` a rectangle
100+
appears *now*. State is global and mutable where the user thinks in terms of a linear script that paints pixels onto a
101+
canvas. This is the traditional "sketch" model of Processing.
102+
103+
Retained mode in the case of Bevy's ECS treats the scene as a database of entities with components. Systems query and
104+
transform this data, often in parallel. Rendering is a separate phase that happens later, potentially pipelined across
105+
frames. The renderer batches draw calls for efficiency and has a number of optimizations that could be considered a form
106+
of eventual consistency (think of a game where objects take flicker in and out on screen as assets load). The user
107+
thinks in terms of a scene graph that is updated over time, where multiple asynchronous systems are modifying data.
108+
109+
Neither model is wrong! But they very much optimize for different things. Immediate mode is intuitive and exploratory
110+
which is why it's so well suited to learning, prototyping, and creative coding. Retained mode is efficient and scalable,
111+
perfect for games with thousands or hundreds of thousands of objects or for more complex artworks that require
112+
sophisticated rendering techniques.
113+
114+
Our job is to present the former while implementing it atop the latter.
115+
116+
This requires us to invert several of Bevy's defaults:
117+
118+
- Recording instead of executing: When user code calls a draw function, we don't spawn entities immediately.
119+
Instead, we record the intent as a `DrawCommand` in a per-graphics `CommandBuffer`. This preserves call order and
120+
allows us to process commands in a controlled batch.
121+
- Synchronous frame control: Bevy wants to manage its own main loop with pipelined rendering. We instead hold the
122+
`App` in a thread-local and call `app.update()` only when the user explicitly flushes, i.e. makes a change that
123+
requires rendering to occur in occur because of some data dependency.
124+
- Selective rendering: By default, Bevy will render all active cameras every update. We disable cameras unless the
125+
user has requested a flush, using marker components to signal which surfaces should actually render.
126+
- Transient geometry: In immediate mode, shapes exist only for the frame they're drawn. We spawn mesh entities when
127+
flushing commands and despawn them before the next frame. The ECS becomes a staging area rather than a persistent
128+
scene graph.
99129

100130
We work around this in the following manner:
101131

0 commit comments

Comments
 (0)