use core::marker::PhantomData;
use super::*;
use crate::math::{Quat, Vec2, Vec3, Vec4};
use crate::mesh::{Cube, Frame, Mesh, MeshData, Part, Plane, Quad, Sheet, Sphere, Vertex};
use crate::meshes;
use crate::{
Assets, ButtonBinding, Camera, Catalog, Color, Cursor, DrawPass, EffectStage, FrameContext,
Holds, Key, Light, Material, MouseButton, NoInputActions, NoSkyboxes, NoSounds, PostEffect,
PostEffects, Projection, ReliefData, ShaderValues, ShadingData, SkyboxData, Skyboxes,
SoundData, Sounds, Startup, SurfaceStyle, TextureData, TickContext, Tonemap, Transform, View,
post_effects, surface_styles,
};
const FLAT: Camera = Camera::new(
View::look_at(Vec3::new(0.0, 0.0, 2.0), Vec3::ZERO),
Projection::orthographic(1.0),
);
const SIDE: u32 = 32;
const DIM: Color = Color::rgb(0.3, 0.3, 0.3);
const WIDE: u32 = 64;
const BEHIND: [u8; 4] = [u8::MAX, 0, 0, u8::MAX];
const IN_FRONT: [u8; 4] = [0, 0, u8::MAX, u8::MAX];
const YARD: u32 = 64;
const ACROSS: f32 = 8.0;
meshes! { enum CubeSet { Cube } }
meshes! { enum CutSet { Cut } }
meshes! { enum GroundSet { Ground } }
meshes! { enum QuadSet { Quad } }
fn raw(title: &str) -> Config {
Config::new(title).with_tonemap(Tonemap::Off)
}
fn rendered<G: Game>(config: Config, game: G) -> Option<Vec<u8>> {
sized(config, UVec2::splat(SIDE), game)
}
fn sized<G: Game>(config: Config, size: UVec2, game: G) -> Option<Vec<u8>> {
let mut session = started(config, size, |_ctx| Ok(game))?;
session.step();
Some(session.pixels().expect("the target reads back"))
}
fn started<G: Game>(
config: Config,
size: UVec2,
init: impl FnOnce(&mut InitContext<'_, G>) -> Result<G, Error>,
) -> Option<Session<G>> {
match Session::new(config, size, init) {
Ok(session) => Some(session),
Err(error) if error.to_string().starts_with(NO_ADAPTER) => None,
Err(error) => panic!("the session did not start: {error}"),
}
}
fn center<G: Game>(game: G) -> Option<[u8; 4]> {
Some(middle(&rendered(raw("headless center"), game)?))
}
fn pixel(pixels: &[u8], x: u32, y: u32) -> [u8; 4] {
let at = ((y * SIDE + x) * 4) as usize;
[pixels[at], pixels[at + 1], pixels[at + 2], pixels[at + 3]]
}
fn middle(pixels: &[u8]) -> [u8; 4] {
pixel(pixels, SIDE / 2, SIDE / 2)
}
fn drawn_pixels(pixels: &[u8]) -> usize {
let sky = &pixels[..4];
pixels.chunks(4).filter(|pixel| *pixel != sky).count()
}
struct Panes {
panes: Vec<(f32, Material)>,
}
impl Panes {
fn new(panes: Vec<(f32, Material)>) -> Self {
Self { panes }
}
}
impl Game for Panes {
type Meshes = QuadSet;
type Sounds = NoSounds;
type InputActions = NoInputActions;
type Skyboxes = NoSkyboxes;
type SurfaceStyles = ();
type PostEffects = ();
fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {}
fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
ctx.set_camera(Camera::new(
View::look_at(Vec3::Z * 2.0, Vec3::ZERO),
Projection::orthographic(1.0),
));
for &(depth, material) in &self.panes {
ctx.draw(
Quad.at(Transform::from_scale_rotation_translation(
Vec3::new(0.9, 0.9, 1.0),
Quat::IDENTITY,
Vec3::Z * depth,
))
.material(material),
);
}
}
}
fn column(pixels: &[u8], across: u32) -> [u8; 4] {
let at = ((SIDE / 2 * SIDE + across) * 4) as usize;
[pixels[at], pixels[at + 1], pixels[at + 2], pixels[at + 3]]
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
enum Cut {
Holed,
Solid,
}
impl Catalog for Cut {
fn catalog() -> Vec<Self> {
vec![Self::Holed, Self::Solid]
}
}
impl Mesh for Cut {
fn build(&self, assets: &Assets) -> MeshData {
let square = Quad.build(assets);
match self {
Self::Holed => {
let texels = [[0; 4], [0; 4], IN_FRONT, IN_FRONT];
square.with_texture(TextureData::rgba8(UVec2::new(4, 1), texels.concat()))
}
Self::Solid => square,
}
}
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
enum Ground {
Floor,
Blocker,
}
impl Catalog for Ground {
fn catalog() -> Vec<Self> {
vec![Self::Floor, Self::Blocker]
}
}
impl Mesh for Ground {
fn build(&self, assets: &Assets) -> MeshData {
match self {
Self::Floor => Plane.build(assets),
Self::Blocker => Cube.build(assets),
}
}
}
fn wide_pixel(pixels: &[u8], x: u32, y: u32) -> [u8; 4] {
let at = ((y * WIDE + x) * 4) as usize;
[pixels[at], pixels[at + 1], pixels[at + 2], pixels[at + 3]]
}
mod assets;
mod cache;
mod culling;
#[cfg(feature = "ui")]
mod fonts;
mod image;
mod machines;
mod maps;
mod materials;
mod passes;
mod planes;
mod poses;
mod post_effects;
mod session;
mod shadows;
mod skyboxes;
mod sprites;
mod styles;
#[cfg(feature = "ui")]
mod text;