use notan::draw::*; use notan::math::{Mat3, Vec2}; use notan::prelude::*; // Hierarchy // - A // - B // - C // - D // - E #[derive(AppState)] struct State { count: f32, container_a: Container, container_b: Container, container_c: Container, container_d: Container, container_e: Container, } impl State { fn new() -> Self { let container_a = Container::new(500.0, 500.0, Color::WHITE); let container_b = Container::new(230.0, 350.0, Color::from_rgb(1.0, 1.0, 0.5)); let container_c = Container::new(130.0, 130.0, Color::from_rgb(0.5, 1.0, 0.5)); let container_d = Container::new(130.0, 130.0, Color::from_rgb(1.0, 0.5, 1.0)); let container_e = Container::new(130.0, 130.0, Color::from_rgb(0.5, 1.0, 1.0)); Self { count: 0.0, container_a, container_b, container_c, container_d, container_e, } } } fn draw_container( draw: &mut Draw, container: &Container, mut f: F, ) { // Push the matrix to the stack draw.transform().push(container.matrix()); draw.rect((0.0, 0.0), (container.size.x, container.size.y)) .color(container.color) .stroke(5.0); // Anything draw after the push will behave as a "children" of this container f(draw, container); // After we finish drawing this container we pop the matrix from the stack draw.transform().pop(); } #[notan_main] fn main() -> Result<(), String> { notan::init_with(State::new) .add_config(DrawConfig) .update(update) .draw(draw) .build() } fn draw(gfx: &mut Graphics, state: &mut State) { let mut draw = gfx.create_draw(); draw.clear(Color::BLACK); // Draw Container A as root draw_container(&mut draw, &state.container_a, |draw, _c| { // B is a child of A draw_container(draw, &state.container_b, |draw, _c| { // C is a child of B draw_container(draw, &state.container_c, |draw, c| { draw_triangle(draw, c.size, state.count.cos()); }); }); // D is a child of A draw_container(draw, &state.container_d, |draw, c| { draw_triangle(draw, c.size, state.count.cos()); }); // E is a child of A draw_container(draw, &state.container_e, |draw, c| { draw_triangle(draw, c.size, state.count.cos()); }); }); // Render the frame gfx.render(&draw); } // Animate the containers to show how the matrix of the parents affects the children fn update(app: &mut App, state: &mut State) { let offset = state.count.sin(); let center_x = app.window().width() as f32 * 0.5; let center_y = app.window().height() as f32 * 0.5; // Container A, relative to the screen state.container_a.pos.x = center_x - state.container_a.size.x * 0.5 + offset * 120.0; state.container_a.pos.y = center_y - state.container_a.size.y * 0.5; // Container B, relative to Container A state.container_b.pos.x = 20.0; state.container_b.pos.y = state.container_a.size.y * 0.5 - state.container_b.size.y * 0.5 + offset * 50.0; // Container C, relative to Container B state.container_c.pos.x = state.container_b.size.x * 0.5 - state.container_c.size.x * 0.5 - offset * 32.0; state.container_c.pos.y = state.container_b.size.y * 0.5 - state.container_c.size.y * 0.5 - offset * 90.0; // Container D, relative to Container A state.container_d.pos.x = state.container_a.size.x * 0.75 - state.container_d.size.x * 0.5; state.container_d.pos.y = state.container_a.size.y * 0.25 - state.container_d.size.y * 0.5; state.container_d.rotation = offset * 1.0; // Container E, relative to Container A state.container_e.pos.x = state.container_a.size.x * 0.75 - state.container_e.size.x * 0.5; state.container_e.pos.y = state.container_a.size.y * 0.75 - state.container_e.size.y * 0.5; state.container_e.scale.x = 1.0 - offset * 0.3; state.container_e.scale.y = 1.0 + offset * 0.3; state.count += app.timer.delta_f32(); } struct Container { pos: Vec2, rotation: f32, scale: Vec2, size: Vec2, color: Color, } impl Container { fn new(width: f32, height: f32, color: Color) -> Self { Self { pos: Vec2::new(0.0, 0.0), rotation: 0.0, scale: Vec2::new(1.0, 1.0), size: Vec2::new(width, height), color, } } // Returns a matrix calculated from the container's attributes fn matrix(&self) -> Mat3 { let translation = Mat3::from_translation(self.pos); let rotation = Mat3::from_angle(self.rotation); let scale = Mat3::from_scale(self.scale); translation * rotation * scale } } // Draw a triangle with a local matrix fn draw_triangle(draw: &mut Draw, size: Vec2, offset: f32) { let a = (size.x * 0.5, size.y * 0.2); let b = (size.x * 0.2, size.y * 0.8); let c = (size.x * 0.8, size.y * 0.8); let rotation = offset * 360.0 * 0.5; draw.triangle(a, b, c) .alpha(0.7) .rotate_degrees_from((size.x * 0.5, size.y * 0.5), rotation) .color_vertex(Color::RED, Color::GREEN, Color::BLUE); }