@@ -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
100130We work around this in the following manner:
101131
0 commit comments