#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::{num::NonZeroU32, sync::Arc, time::Instant};
use alligator_render::{Instance, InstanceId, RenderWindowConfig, Renderer};
use alligator_resources::texture::{ImageFormat, TextureId, TextureManager, TextureManagerConfig};
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.wrapping_add(s)
}
#[derive(Debug)]
struct State {
texture_id: TextureId,
bunnies: Vec<Bunny>,
previous_timestamp: Option<Instant>,
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_mut().texture_x(self.texture_id).unwrap();
let texture_y = renderer.textures_mut().texture_y(self.texture_id).unwrap();
let texture_height = renderer
.textures_mut()
.texture_height(self.texture_id)
.unwrap();
let texture_width = renderer
.textures_mut()
.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 render_config = RenderWindowConfig {
title: "BunnyMark",
instance_capacity: 150_000,
default_width: NonZeroU32::new(1280).unwrap(),
default_height: NonZeroU32::new(720).unwrap(),
vsync: false,
low_power: false,
..Default::default()
};
let texture_config = TextureManagerConfig {
initial_capacity: 1,
max_size: 10_000,
};
let bunny = include_bytes!("res/bunny.ff");
let texture_manager = Arc::new(TextureManager::new(&texture_config));
let mut renderer = Renderer::new(&render_config, texture_manager.clone()).unwrap();
let texture_id = texture_manager
.load_from_memory(bunny, ImageFormat::Farbfeld)
.unwrap();
renderer.textures_mut().load_texture(texture_id).unwrap();
let state = Box::leak(Box::new(State::new(texture_id)));
renderer.run(|r| state.update(r));
}
|