pub struct Renderer {
pub window: Arc<Window>,
pub post_process: PostProcessStack,
/* private fields */
}Fields§
§window: Arc<Window>§post_process: PostProcessStackPost-processing stack for “juice” effects.
Implementations§
Source§impl Renderer
impl Renderer
pub async fn new( window: Arc<Window>, png_bytes: &[u8], tile_w: u32, tile_h: u32, use_scanlines: bool, ) -> Self
Sourcepub fn load_sprite_folder(&mut self, path: &str, tile_w: u32, tile_h: u32)
pub fn load_sprite_folder(&mut self, path: &str, tile_w: u32, tile_h: u32)
Load all .png files from path (recursively) into the sprite atlas.
Sourcepub fn get_sprite_data(&self, name: &str) -> Option<SpriteData>
pub fn get_sprite_data(&self, name: &str) -> Option<SpriteData>
Returns the metadata (UVs, spans) for a named sprite if it exists.
pub fn resize(&mut self, new_size: PhysicalSize<u32>)
Sourcepub fn update_camera(&mut self, uniform: &CameraUniform)
pub fn update_camera(&mut self, uniform: &CameraUniform)
Upload a new camera view-projection matrix to the GPU.
Sourcepub fn update_entity_offsets(&mut self, offsets: &[[f32; 4]])
pub fn update_entity_offsets(&mut self, offsets: &[[f32; 4]])
Upload an array of [f32; 4] offsets for entity animation.
pub fn surface_format(&self) -> TextureFormat
Sourcepub fn set_mtsdf_distance_range(&mut self, range: f32)
pub fn set_mtsdf_distance_range(&mut self, range: f32)
Update the MTSDF distance range used by the text shader.
Call this once after registering a font via TextLayer::set_font, passing
font.distance_range from the loaded Font. The atlas dimensions are
taken from the actual GPU texture and do not need to be supplied again.
Examples found in repository?
More examples
examples/stress_test.rs (line 152)
149 fn render(&mut self, engine: &mut jEngine) {
150 if !self.font_loaded {
151 if let Ok(font) = jengine::renderer::text::Font::from_mtsdf_json(DEFAULT_FONT_METADATA) {
152 engine.renderer.set_mtsdf_distance_range(font.distance_range);
153 engine.ui.text.set_font(font);
154 }
155 self.font_loaded = true;
156 }
157
158 engine.clear();
159
160 // ── Draw Entities (as small circles for speed) ──
161 for (_e, (_m, pos)) in self.world.query_multi::<(EntityMarker, Position)>() {
162 engine.draw_particle(pos.x, pos.y, Color([0.4, 0.7, 1.0, 1.0]), 4.0);
163 }
164
165 // ── Draw Particles ──
166 for (_e, (_l, pos)) in self.world.query_multi::<(Life, Position)>() {
167 engine.draw_particle(pos.x, pos.y, Color([1.0, 0.5, 0.2, 0.8]), 2.0);
168 }
169
170 // ── Stats UI ──
171 let th = engine.tile_height() as f32;
172
173 engine.ui.ui_rect(0.0, 0.0, 350.0, th * 8.0, Color([0.0, 0.0, 0.0, 0.7]));
174
175 let mut y = 10.0;
176 let lines = [
177 format!("STRESS TEST - [Space] for Nova"),
178 format!("Entities: {} (Q/W to adj)", self.entity_target_count),
179 format!("P-Rate: {} / frame (A/S to adj)", self.particle_spawn_rate),
180 format!("Total ECS: {}", self.world.entity_count()),
181 format!("FPS: {:.1}", 1.0 / engine.dt().max(0.001)),
182 ];
183
184 for line in lines {
185 engine.ui.ui_text(10.0, y, &line, Color::WHITE, Color::TRANSPARENT, None);
186 y += th;
187 }
188 }examples/particles.rs (line 266)
263 fn render(&mut self, engine: &mut jEngine) {
264 if !self.font_loaded {
265 if let Ok(font) = jengine::renderer::text::Font::from_mtsdf_json(DEFAULT_FONT_METADATA) {
266 engine.renderer.set_mtsdf_distance_range(font.distance_range);
267 engine.ui.text.set_font(font);
268 }
269 self.font_loaded = true;
270 }
271
272 engine.clear();
273
274 let sw = engine.renderer.window.inner_size().width as f32;
275 let sh = engine.renderer.window.inner_size().height as f32;
276
277 // Set dark navy background using the tile grid (Pass 1)
278 // This ensures particles (Pass 3) are drawn ON TOP of the background.
279 for y in 0..engine.grid_height() {
280 for x in 0..engine.grid_width() {
281 engine.set_background(x, y, Color([0.01, 0.01, 0.02, 1.0]));
282 }
283 }
284
285 // --- Render System ---
286 for (_e, (pos, life, p)) in self.world.query_multi::<(Position, Life, Particle)>() {
287 let t = (life.current / life.max).clamp(0.0, 1.0);
288
289 // Lerp color
290 let mut c = [0.0; 4];
291 for i in 0..4 {
292 c[i] = p.color_end[i] + (p.color_start[i] - p.color_end[i]) * t;
293 }
294
295 // Lerp size
296 let size = p.size_end + (p.size_start - p.size_end) * t;
297
298 engine.draw_particle(pos.x, pos.y, Color(c), size);
299 }
300
301 // --- UI ---
302 let tw = engine.tile_width() as f32;
303 let th = engine.tile_height() as f32;
304
305 engine.ui.ui_text(tw, th, "PARTICLE SHOWCASE", Color::WHITE, Color::TRANSPARENT, Some(48.0));
306
307 let mut y = th * 4.0;
308 let help = [
309 "MOUSE LCLICK : Spawn Explosion",
310 "[S] KEY : Spawn Slash (at mouse)",
311 "[G] KEY : Spawn Glitch (at mouse)",
312 "CONTINUOUS : Fire & Smoke (bottom)",
313 "[ESC] : Quit demo"
314 ];
315
316 for line in help {
317 engine.ui.ui_text(tw, y, line, Color([0.6, 0.7, 0.7, 1.0]), Color::TRANSPARENT, None);
318 y += th * 1.2;
319 }
320
321 y += th;
322 let pp_help = [
323 format!("[1] Scanlines: {}", if self.pp.scanlines { "ON" } else { "OFF" }),
324 format!("[2] Vignette: {}", if self.pp.vignette { "ON" } else { "OFF" }),
325 format!("[3] Chromatic: {}", if self.pp.chromatic { "ON" } else { "OFF" }),
326 format!("[4] Bloom: {}", if self.pp.bloom { "ON" } else { "OFF" }),
327 ];
328 for line in pp_help {
329 engine.ui.ui_text(tw, y, &line, Color([0.4, 0.9, 0.6, 1.0]), Color::TRANSPARENT, None);
330 y += th * 1.2;
331 }
332
333 let count = self.world.entity_count();
334 engine.ui.ui_text(sw - tw * 18.0, sh - th * 2.5, &format!("Active Entities: {}", count), Color::CYAN, Color::TRANSPARENT, Some(20.0));
335 }Sourcepub fn render(
&mut self,
char_verts: &[TileVertex],
sprite_verts: &[TileVertex],
particle_verts: &[ParticleVertex],
ui_verts: &[UIVertex],
text_verts: &[TextVertex],
text_indices: &[u16],
) -> Result<(), SurfaceError>
pub fn render( &mut self, char_verts: &[TileVertex], sprite_verts: &[TileVertex], particle_verts: &[ParticleVertex], ui_verts: &[UIVertex], text_verts: &[TextVertex], text_indices: &[u16], ) -> Result<(), SurfaceError>
Render one frame.
Draw order within the single render pass:
char_verts— character tile atlas (bg fills + char glyphs) [camera]sprite_verts— sprite atlas (static and animated sprites) [camera]particle_verts— particle pipeline [camera]ui_verts— UI solid fills (TileVertex, Layer 2) [screen]text_verts— MTSDF text (Labels + ui_char_at) [screen]
Passes 1–3 use the camera bind group (scroll/zoom). Passes 4–5 use the plain projection bind group (screen-fixed).
Auto Trait Implementations§
impl !Freeze for Renderer
impl !RefUnwindSafe for Renderer
impl !Send for Renderer
impl !Sync for Renderer
impl Unpin for Renderer
impl UnsafeUnpin for Renderer
impl !UnwindSafe for Renderer
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.