dunge 0.3.13

Typesafe and portable 3d render library
Documentation
#![cfg(not(target_family = "wasm"))]

use {
    dunge::{
        buffer::{Filter, Sampler, Size, Texture},
        color::{Format, Rgb},
        prelude::*,
    },
    glam::{Vec2, Vec4},
    helpers::image::Image,
    std::env,
};

#[derive(Clone, Copy, Value, Bytes)]
struct Vert {
    pos: Vec2,
    uv: Vec2,
}

#[derive(Input)]
struct Map {
    texture: Texture,
    sampler: Sampler,
}

#[derive(Clone, Copy, Value)]
struct Io {
    #[position]
    pos: Vec4,
    uv: Vec2,
}

#[dunge(vertex)]
fn vs(v: Vert) -> Io {
    Io {
        pos: sl::concat(v.pos, Vec2::new(0., 1.)),
        uv: v.uv,
    }
}

#[dunge(fragment)]
fn fs(io: Io, m: Map) -> Vec4 {
    sl::texture_sample(m.texture, m.sampler, io.uv)
}

type Error = Box<dyn std::error::Error>;

#[test]
fn render() -> Result<(), Error> {
    let cx = dunge::block_on(dunge::context())?;
    let triangle = cx.make_shader(
        render! {
            vertex: Vert,
            groups: [Map],
            shaders: [vs, fs],
        }
        .inspect(|r| {
            helpers::eq_lines(r.debug().to_string(), include_str!("triangle_group.wgsl"));
        })?,
    );

    let map = {
        let texture = {
            let gradient = Image::decode(include_bytes!("gradient.png"));
            let size = Size::try_from(gradient.size)?;
            let data = TextureData::new(size, Format::SrgbAlpha, &gradient.data)?.bind();
            cx.make_texture(data)
        };

        let map = Map {
            texture: texture.texture(),
            sampler: cx.make_sampler(Filter::Nearest).sampler(),
        };

        cx.make_set(&triangle, map)
    };

    let size = (300, 300);
    let layer = cx.make_layer(&triangle, Format::SrgbAlpha);
    let view = {
        let size = Size::try_from(size)?;
        let data = TextureData::empty(size, Format::SrgbAlpha)
            .render()
            .copy_from();

        cx.make_texture(data)
    };

    let mesh = {
        const VERTS: [Vert; 3] = [
            Vert {
                pos: Vec2::new(0., -0.75),
                uv: Vec2::new(0., 1.),
            },
            Vert {
                pos: Vec2::new(0.866, 0.75),
                uv: Vec2::new(1., 1.),
            },
            Vert {
                pos: Vec2::new(-0.866, 0.75),
                uv: Vec2::new(1., 0.),
            },
        ];

        let data = MeshData::from_verts(&VERTS).expect("mesh data");
        cx.make_mesh(&data)
    };

    let mut buf = {
        let data = view.copy_buffer_data().read();
        cx.make_buffer(data)
    };

    let read = dunge::block_on(async {
        let bg = Rgb::from_bytes([0; 3]);
        cx.shed(|s| {
            s.render(&view, bg).layer(&layer).set(map).draw(&mesh);
            s.copy(&view, &buf);
        })
        .await;

        cx.read(&mut buf).await
    })?;

    let data = bytemuck::cast_slice(&read);
    let row = view.bytes_per_row_aligned() / view.format().bytes();
    let image = Image::from_fn(size, |x, y| {
        let idx = x + y * row;
        data[idx as usize]
    });

    if env::var("DUNGE_TEST_OUTPUT").is_ok() {
        std::fs::write("tests/triangle_group_actual.png", image.encode())?;
    }

    Ok(())
}