use std::{num::NonZeroU32, time::Instant}; use alligator_render::{ ImageFormat, Instance, InstanceId, RenderWindowConfig, Renderer, TextureId, }; fn xorshift_plus(seed: &mut [u64; 2]) -> u64 { let mut t = seed[0]; let s = seed[1]; t ^= t << 23; t ^= t >> 18; t ^= s ^ (s >> 5); seed[0] = s; seed[1] = t; t + s } #[derive(Debug)] struct State { texture_id: TextureId, bunnies: Vec, previous_timestamp: Option, seed: [u64; 2], stopped: bool, } impl State { fn new(texture_id: TextureId) -> Self { Self { texture_id, bunnies: Vec::with_capacity(10_000_000), previous_timestamp: None, seed: [0x0D15EA5E8BADF00D, 0xDECAFBADDEADBEAF], stopped: false, } } #[profiling::function] fn update(&mut self, renderer: &mut Renderer) { let Some(instant) = self.previous_timestamp else { self.previous_timestamp = Some(Instant::now()); return; }; let frame_time = instant.elapsed(); let fps = 1.0 / frame_time.as_secs_f32(); renderer.set_title(&format!( "BunnyMark - {} bunnies - {} FPS", self.bunnies.len(), fps.round() )); if fps < 15.0 { self.stopped = true; } self.previous_timestamp = Some(Instant::now()); if self.stopped { return; } for bunny in self.bunnies.iter_mut() { let instance = renderer .instances_mut() .get_instance_mut(bunny.instance_id) .unwrap(); instance.position[0] += bunny.velocity_x; instance.position[1] += bunny.velocity_y; if !(-1.5..1.5).contains(&instance.position[0]) { instance.position[0] = instance.position[0].clamp(-1.0, 1.0); bunny.velocity_x = -bunny.velocity_x; } if !(-0.75..0.75).contains(&instance.position[1]) { instance.position[1] = instance.position[1].clamp(-0.5, 0.5); bunny.velocity_y *= -0.90; } bunny.velocity_y -= 0.005; } for _ in 0..=(fps as u64 * 50) { let texture_x = renderer.textures().texture_x(self.texture_id).unwrap(); let texture_y = renderer.textures().texture_x(self.texture_id).unwrap(); let texture_height = renderer.textures().texture_height(self.texture_id).unwrap(); let texture_width = renderer.textures().texture_width(self.texture_id).unwrap(); let instance_id = renderer.instances_mut().push_instance(Instance { texture_coordinates: [texture_x, texture_y], texture_size: [texture_width, texture_height], size: [0.08, 0.08], position: [-1.5, 0.70], ..Default::default() }); let velocity_x = (xorshift_plus(&mut self.seed) % 1_000_000) as f32 / 25_000_000.0; let velocity_y = (xorshift_plus(&mut self.seed) % 1_000_000) as f32 / 25_000_000.0; self.bunnies.push(Bunny { instance_id, velocity_x, velocity_y, }); } } } #[derive(Debug, Clone, Copy)] struct Bunny { instance_id: InstanceId, velocity_x: f32, velocity_y: f32, } fn main() { #[cfg(feature = "profile-with-tracy")] profiling::tracy_client::Client::start(); profiling::register_thread!("main"); // configure the render window let config = RenderWindowConfig { title: "BunnyMark", instance_capacity: 10_000_000, default_width: NonZeroU32::new(1280).unwrap(), default_height: NonZeroU32::new(720).unwrap(), vsync: false, low_power: false, ..Default::default() }; let bunny = include_bytes!("res/bunny.ff"); let mut renderer = Renderer::new(&config).unwrap(); let texture_id = renderer .textures_mut() .load_from_memory(bunny, ImageFormat::Farbfeld) .unwrap(); let state = Box::leak(Box::new(State::new(texture_id))); renderer.run(|r| state.update(r)); }