use embedded_3dgfx::K3dengine;
use embedded_3dgfx::draw::draw;
use embedded_3dgfx::mesh::{Geometry, K3dMesh, RenderMode};
use embedded_graphics_core::pixelcolor::Rgb565;
use embedded_graphics_core::prelude::*;
use nalgebra::{Point3, Vector3};
struct TestFramebuffer {
pixels: Vec<(i32, i32, Rgb565)>,
width: u32,
height: u32,
}
impl TestFramebuffer {
fn new(width: u32, height: u32) -> Self {
Self {
pixels: Vec::new(),
width,
height,
}
}
fn pixel_count(&self) -> usize {
self.pixels.len()
}
#[allow(dead_code)]
fn clear(&mut self) {
self.pixels.clear();
}
}
impl DrawTarget for TestFramebuffer {
type Color = Rgb565;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>>,
{
for pixel in pixels {
self.pixels.push((pixel.0.x, pixel.0.y, pixel.1));
}
Ok(())
}
}
impl OriginDimensions for TestFramebuffer {
fn size(&self) -> Size {
Size::new(self.width, self.height)
}
}
#[test]
fn test_full_rendering_pipeline_points() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [1.0, 0.0, -5.0], [0.0, 1.0, -5.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
mesh.set_color(Rgb565::CSS_RED);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 0);
}
#[test]
fn test_full_rendering_pipeline_lines() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0], [0.0, 0.5, -5.0]];
let faces = [[0, 1, 2]];
let geometry = Geometry {
vertices: &vertices,
faces: &faces,
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Lines);
mesh.set_color(Rgb565::CSS_GREEN);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 10);
}
#[test]
fn test_full_rendering_pipeline_solid() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0], [0.0, 0.5, -5.0]];
let faces = [[0, 1, 2]];
let geometry = Geometry {
vertices: &vertices,
faces: &faces,
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Solid);
mesh.set_color(Rgb565::CSS_BLUE);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 50);
}
#[test]
fn test_multiple_meshes() {
let engine = K3dengine::new(640, 480);
let vertices1 = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0]];
let geometry1 = Geometry {
vertices: &vertices1,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh1 = K3dMesh::new(geometry1);
mesh1.set_render_mode(RenderMode::Points);
let vertices2 = [[0.0, 0.5, -5.0], [0.5, 0.5, -5.0]];
let geometry2 = Geometry {
vertices: &vertices2,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh2 = K3dMesh::new(geometry2);
mesh2.set_render_mode(RenderMode::Points);
let mut fb = TestFramebuffer::new(640, 480);
engine.render([&mesh1, &mesh2].iter().copied(), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() >= 4);
}
#[test]
fn test_mesh_transformation() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
mesh.set_position(1.0, 0.0, 0.0);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 0);
}
#[test]
fn test_mesh_scaling() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.1, 0.0, -5.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
mesh.set_scale(2.0);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 0);
}
#[test]
fn test_backface_culling() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0], [0.0, 0.5, -5.0]];
let faces = [[0, 1, 2]];
let normals = [[0.0, 0.0, 1.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &faces,
colors: &[],
lines: &[],
normals: &normals,
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Solid);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
let pixel_count = fb.pixel_count();
println!("Backface culling pixel count: {}", pixel_count);
}
#[test]
fn test_camera_movement() {
let mut engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
engine.camera.set_position(Point3::new(1.0, 0.0, 0.0));
engine.camera.set_target(Point3::new(0.0, 0.0, -5.0));
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
}
#[test]
fn test_out_of_view_culling() {
let engine = K3dengine::new(640, 480);
let vertices = [[100.0, 100.0, -5.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert_eq!(fb.pixel_count(), 0);
}
#[test]
fn test_lighting_mode() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0], [0.0, 0.5, -5.0]];
let faces = [[0, 1, 2]];
let normals = [[0.0, 0.0, -1.0]];
let geometry = Geometry {
vertices: &vertices,
faces: &faces,
colors: &[],
lines: &[],
normals: &normals,
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
let light_dir = Vector3::new(0.0, 0.0, -1.0);
mesh.set_render_mode(RenderMode::SolidLightDir(light_dir));
mesh.set_color(Rgb565::CSS_WHITE);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
let _ = fb.pixel_count();
}
#[test]
fn test_colored_vertices() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0]];
let colors = [Rgb565::CSS_RED, Rgb565::CSS_BLUE];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &colors,
lines: &[],
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Points);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() >= 2);
}
#[test]
fn test_lines_from_explicit_edges() {
let engine = K3dengine::new(640, 480);
let vertices = [[0.0, 0.0, -5.0], [0.5, 0.0, -5.0], [0.0, 0.5, -5.0]];
let lines = [[0, 1], [1, 2]];
let geometry = Geometry {
vertices: &vertices,
faces: &[],
colors: &[],
lines: &lines,
normals: &[],
vertex_normals: &[],
uvs: &[],
texture_id: None,
};
let mut mesh = K3dMesh::new(geometry);
mesh.set_render_mode(RenderMode::Lines);
let mut fb = TestFramebuffer::new(640, 480);
engine.render(std::iter::once(&mesh), |prim| {
draw(prim, &mut fb);
});
assert!(fb.pixel_count() > 10);
}