use spottedcat::{Context, DrawOption3D, Image, Model, Pt, Spot, WindowConfig};
use std::sync::Arc;
use std::time::Duration;
struct RenderStateStress {
models: Vec<Model>,
transparent_plane: Model,
instanced_cube: Model,
instanced_transforms: Arc<[[[f32; 4]; 4]]>,
time: f32,
}
fn checker_texture(ctx: &mut Context, a: [u8; 4], b: [u8; 4]) -> Image {
let rgba = vec![
a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3], b[0], b[1], b[2], b[3], a[0], a[1], a[2],
a[3],
];
Image::new_from_rgba8(ctx, Pt::from(2.0), Pt::from(2.0), &rgba)
.expect("checker texture should be created")
}
impl Spot for RenderStateStress {
fn initialize(ctx: &mut Context) -> Self {
let red = checker_texture(ctx, [255, 96, 96, 255], [160, 32, 32, 255]);
let green = checker_texture(ctx, [96, 255, 160, 255], [24, 120, 64, 255]);
let blue = checker_texture(ctx, [96, 168, 255, 255], [24, 56, 144, 255]);
let gold = checker_texture(ctx, [255, 220, 96, 255], [160, 120, 24, 255]);
let glass = checker_texture(ctx, [180, 220, 255, 180], [80, 120, 180, 120]);
let cube_red = Model::cube(ctx, 0.9).unwrap().with_material(red);
let cube_green = Model::cube(ctx, 0.9).unwrap().with_material(green);
let sphere_blue = Model::sphere(ctx, 0.55).unwrap().with_material(blue);
let sphere_gold = Model::sphere(ctx, 0.55).unwrap().with_material(gold);
let transparent_plane = Model::plane(ctx, 1.8, 1.8).unwrap().with_material(glass);
let instanced_cube = Model::cube(ctx, 0.35).unwrap().with_material(gold);
let mut instanced_transforms = Vec::with_capacity(80 * 40);
for z in 0..40 {
for x in 0..80 {
let px = (x as f32 - 40.0) * 0.9;
let py = ((x as f32 * 0.35).sin() + (z as f32 * 0.25).cos()) * 0.8;
let pz = -20.0 - z as f32 * 1.4;
instanced_transforms.push([
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[px, py, pz, 1.0],
]);
}
}
Self {
models: vec![cube_red, sphere_blue, cube_green, sphere_gold],
transparent_plane,
instanced_cube,
instanced_transforms: Arc::from(instanced_transforms),
time: 0.0,
}
}
fn update(&mut self, ctx: &mut Context, dt: Duration) {
self.time += dt.as_secs_f32();
ctx.set_camera_pos([0.0, 14.0, 26.0]);
ctx.set_camera_target(0.0, 0.0, -28.0);
}
fn draw(&mut self, ctx: &mut Context) {
let columns = 32;
let rows = 24;
for row in 0..rows {
for col in 0..columns {
let draw_index = row * columns + col;
let model_index = (draw_index * 7 + row * 3) % self.models.len();
let x = (col as f32 - columns as f32 * 0.5) * 1.8;
let y = (row as f32 - rows as f32 * 0.5) * 1.35;
let z = -6.0 - ((row + col) % 5) as f32 * 1.6;
let spin = self.time * 0.8 + draw_index as f32 * 0.03;
let opts = DrawOption3D::default()
.with_position([x, y, z])
.with_rotation([spin * 0.4, spin, 0.0]);
self.models[model_index].draw(ctx, opts);
}
}
for idx in 0..18 {
let x = -14.0 + idx as f32 * 1.7;
let z = -2.0 - idx as f32 * 0.4;
let opts = DrawOption3D::default()
.with_position([x, 0.0, z])
.with_rotation([0.0, self.time * 0.25 + idx as f32 * 0.1, 0.0])
.with_opacity(0.35);
self.transparent_plane.draw(ctx, opts);
}
self.instanced_cube.draw_instanced_shared(
ctx,
DrawOption3D::default()
.with_position([0.0, -10.0, 0.0])
.with_rotation([0.15, self.time * 0.15, 0.0]),
self.instanced_transforms.clone(),
);
}
fn remove(&mut self, _ctx: &mut Context) {}
}
fn main() {
unsafe {
std::env::set_var("SPOT_PROFILE_RENDER", "1");
}
spottedcat::run::<RenderStateStress>(WindowConfig {
title: "Render State Stress".to_string(),
width: Pt::from(1440.0),
height: Pt::from(900.0),
..Default::default()
});
}