truck-rendimpl 0.6.0

visualization of shape and polygon mesh based on platform
Documentation
mod common;
use image::{DynamicImage, ImageBuffer, Rgba};
use std::sync::Arc;
use truck_meshalgo::prelude::obj;
use truck_platform::*;
use truck_rendimpl::*;
use wgpu::*;

const PICTURE_SIZE: (u32, u32) = (256, 256);

fn bgcheck_shaders(handler: &DeviceHandler) -> PolygonShaders {
    let source = include_str!("shaders/mesh-bindgroup.wgsl");
    let module = Arc::new(
        handler
            .device()
            .create_shader_module(ShaderModuleDescriptor {
                source: ShaderSource::Wgsl(source.into()),
                label: None,
            }),
    );
    PolygonShaders::new(
        Arc::clone(&module),
        "vs_main",
        Arc::clone(&module),
        "nontex_main",
        Arc::clone(&module),
        "tex_main",
    )
}

fn bgcheck_anti_shaders(handler: &DeviceHandler) -> PolygonShaders {
    let source = include_str!("shaders/mesh-bindgroup.wgsl");
    let module = Arc::new(
        handler
            .device()
            .create_shader_module(ShaderModuleDescriptor {
                source: ShaderSource::Wgsl(source.into()),
                label: None,
            }),
    );
    PolygonShaders::new(
        Arc::clone(&module),
        "vs_main",
        Arc::clone(&module),
        "nontex_main_anti",
        Arc::clone(&module),
        "tex_main_anti",
    )
}

const ATTRS_OBJ: &str = "
v -1.0 2.0 -1.0\nv 1.0 2.0 -1.0\nv -1.0 2.0 1.0\nv 1.0 2.0 1.0
vt -1.0 -1.0\nvt 1.0 -1.0\nvt 1.0 1.0\nvt -1.0 1.0
vn -1.0 0.2 -1.0\nvn 1.0 0.2 -1.0\nvn -1.0 0.2 1.0\nvn 1.0 0.2 1.0
";
const TRIS_OBJ: &str = "f 1/1/1 2/2/3 3/4/2\nf 3/4/2 2/2/3 4/3/4\n";
const QUADS_OBJ: &str = "f 1/1/1 2/2/3 4/3/4 3/4/2\n";

fn test_polygons() -> [PolygonMesh; 2] {
    [
        obj::read((ATTRS_OBJ.to_string() + TRIS_OBJ).as_bytes()).unwrap(),
        obj::read((ATTRS_OBJ.to_string() + QUADS_OBJ).as_bytes()).unwrap(),
    ]
}

fn nontex_inst_state() -> PolygonState {
    PolygonState {
        matrix: Matrix4::from_cols(
            [1.0, 2.0, 3.0, 4.0].into(),
            [5.0, 6.0, 7.0, 8.0].into(),
            [9.0, 10.0, 11.0, 12.0].into(),
            [13.0, 14.0, 15.0, 16.0].into(),
        ),
        material: Material {
            albedo: Vector4::new(0.2, 0.4, 0.6, 1.0),
            roughness: 0.31415,
            reflectance: 0.29613,
            ambient_ratio: 0.92,
            background_ratio: 0.32,
            alpha_blend: false,
        },
        texture: None,
        backface_culling: true,
    }
}

fn exec_polygon_bgtest(
    scene: &mut Scene,
    instance: &PolygonInstance,
    answer: &[u8],
    id: usize,
    out_dir: String,
) -> bool {
    let buffer = common::render_one(scene, instance);
    let path = format!("{out_dir}polygon-bgtest-{id}.png");
    common::save_buffer(path, &buffer, PICTURE_SIZE);
    common::same_buffer(answer, &buffer)
}

fn exec_polymesh_nontex_bind_group_test(backend: Backends, out_dir: &str) {
    let out_dir = out_dir.to_string();
    std::fs::create_dir_all(&out_dir).unwrap();
    let instance = wgpu::Instance::new(InstanceDescriptor {
        backends: backend,
        ..Default::default()
    });
    let handler = common::init_device(&instance);
    let mut scene = Scene::new(
        handler,
        &SceneDescriptor {
            render_texture: RenderTextureConfig {
                canvas_size: PICTURE_SIZE,
                ..Default::default()
            },
            ..Default::default()
        },
    );
    let answer = common::nontex_answer_texture(&mut scene);
    let inst_desc = nontex_inst_state();
    test_polygons()
        .iter()
        .enumerate()
        .for_each(move |(i, polygon)| {
            let instance: PolygonInstance = polygon.to_instance(
                scene.device_handler(),
                &bgcheck_shaders(scene.device_handler()),
                &inst_desc,
            );
            assert!(exec_polygon_bgtest(
                &mut scene,
                &instance,
                &answer,
                i,
                out_dir.clone()
            ));
            let instance: PolygonInstance = polygon.to_instance(
                scene.device_handler(),
                &bgcheck_anti_shaders(scene.device_handler()),
                &inst_desc,
            );
            assert!(!exec_polygon_bgtest(
                &mut scene,
                &instance,
                &answer,
                i,
                out_dir.clone()
            ));
        })
}

#[test]
fn polymesh_nontex_bind_group_test() {
    common::os_alt_exec_test(exec_polymesh_nontex_bind_group_test)
}

fn exec_polymesh_tex_bind_group_test(backend: Backends, out_dir: &str) {
    let out_dir = out_dir.to_string();
    std::fs::create_dir_all(&out_dir).unwrap();
    let instance = wgpu::Instance::new(InstanceDescriptor {
        backends: backend,
        ..Default::default()
    });
    let handler = common::init_device(&instance);
    let mut scene = Scene::new(
        handler,
        &SceneDescriptor {
            render_texture: RenderTextureConfig {
                canvas_size: PICTURE_SIZE,
                ..Default::default()
            },
            ..Default::default()
        },
    );
    let buffer = common::random_texture(&mut scene);
    let pngpath = out_dir.clone() + "random-texture.png";
    common::save_buffer(pngpath, &buffer, PICTURE_SIZE);
    let mut state = nontex_inst_state();
    let image_buffer =
        ImageBuffer::<Rgba<_>, _>::from_raw(PICTURE_SIZE.0, PICTURE_SIZE.1, buffer.clone())
            .unwrap();
    let attach = image2texture::image2texture(
        scene.device_handler(),
        &DynamicImage::ImageRgba8(image_buffer),
    );
    state.texture = Some(Arc::new(attach));
    test_polygons()
        .iter()
        .enumerate()
        .for_each(move |(i, polygon)| {
            let instance: PolygonInstance = polygon.to_instance(
                scene.device_handler(),
                &bgcheck_shaders(scene.device_handler()),
                &state,
            );
            assert!(exec_polygon_bgtest(
                &mut scene,
                &instance,
                &buffer,
                i + 3,
                out_dir.clone(),
            ));
            let instance: PolygonInstance = polygon.to_instance(
                scene.device_handler(),
                &bgcheck_anti_shaders(scene.device_handler()),
                &state,
            );
            assert!(!exec_polygon_bgtest(
                &mut scene,
                &instance,
                &buffer,
                i + 3,
                out_dir.clone(),
            ));
        })
}

#[test]
fn polymesh_tex_bind_group_test() { common::os_alt_exec_test(exec_polymesh_tex_bind_group_test) }