use gouache::{Allocator, Color, MeshBuilder, Vec2, Mat4x4, Path, gl::Buffer, gl::Mesh, gl::Renderer}; fn main() { let mut events_loop = glutin::EventsLoop::new(); let window_builder = glutin::WindowBuilder::new() .with_dimensions(glutin::dpi::LogicalSize::new(1000.0, 800.0)) .with_title("gouache"); let context = glutin::ContextBuilder::new() .with_vsync(true) .build_windowed(window_builder, &events_loop) .unwrap(); let context = unsafe { context.make_current() }.unwrap(); gl::load_with(|symbol| context.get_proc_address(symbol) as *const _); let mut alloc = Allocator::new(4096, 16); let buffer = Buffer::new(4096, 16); let mut renderer = Renderer::new(); let mut mesh_builder = MeshBuilder::new(); let mut min = Vec2::new(std::f32::INFINITY, std::f32::INFINITY); let mut max = Vec2::new(-std::f32::INFINITY, -std::f32::INFINITY); let tree = usvg::Tree::from_file("res/tiger.svg", &usvg::Options::default()).unwrap(); for child in tree.root().children() { match *child.borrow() { usvg::NodeKind::Path(ref p) => { let mut path = Path::new(); for segment in p.data.0.iter() { match *segment { usvg::PathSegment::MoveTo { x, y } => { path.move_to(Vec2::new(x as f32, -y as f32)); } usvg::PathSegment::LineTo { x, y } => { path.line_to(Vec2::new(x as f32, -y as f32)); } usvg::PathSegment::CurveTo { x1, y1, x2, y2, x, y } => { path.cubic_to(Vec2::new(x1 as f32, -y1 as f32), Vec2::new(x2 as f32, -y2 as f32), Vec2::new(x as f32, -y as f32)); } usvg::PathSegment::ClosePath => { path.close(); } } } if let Some(ref fill) = p.fill { if let usvg::Paint::Color(color) = fill.paint { let color = Color::rgba(color.red as f32 / 255.0, color.green as f32 / 255.0, color.blue as f32 / 255.0, fill.opacity.value() as f32); let path_descr = alloc.add_path(&path).unwrap(); mesh_builder.add_path(path_descr, Mat4x4::id(), color); min = min.min(path.offset()); max = max.max(path.size()); } } if let Some(ref stroke) = p.stroke { if let usvg::Paint::Color(color) = stroke.paint { let color = Color::rgba(color.red as f32 / 255.0, color.green as f32 / 255.0, color.blue as f32 / 255.0, stroke.opacity.value() as f32); let stroke = path.stroke(stroke.width.value() as f32); let path_descr = alloc.add_path(&stroke).unwrap(); mesh_builder.add_path(path_descr, Mat4x4::id(), color); min = min.min(stroke.offset()); max = max.max(stroke.size()); } } } _ => {} } } for upload in alloc.uploads() { buffer.upload(upload.x as u32, upload.y as u32, upload.data.len() as u32, 1, &upload.data[..]); } let mesh = Mesh::new(mesh_builder.vertices(), mesh_builder.indices()); let mut z = 50.0; let mut cursor = Vec2::new(-1.0, -1.0); let mut dragging = false; let mut rotate = Mat4x4::id(); let mut running = true; while running { renderer.clear(Color::rgba(0.724, 0.844, 0.894, 1.0)); let model = Mat4x4::scale(0.05) * Mat4x4::translate(-0.5 * (max.x + min.x), -0.5 * (max.y + min.y) + 0.15 * (max.y - min.y), 0.0); let view = Mat4x4::translate(0.0, 0.0, -1.0 - z) * rotate; let proj = Mat4x4::perspective(std::f32::consts::PI / 4.0, 1000.0 / 800.0, 0.1, 10000.0); let transform = proj * view * model; renderer.draw(&mesh, &buffer, &transform, 1000.0, 800.0); context.swap_buffers().unwrap(); events_loop.poll_events(|event| match event { glutin::Event::WindowEvent { event, .. } => { use glutin::WindowEvent::*; match event { CloseRequested => { running = false; } MouseWheel { delta, .. } => match delta { glutin::MouseScrollDelta::PixelDelta(position) => { z *= 0.995f32.powf(-position.y as f32); } glutin::MouseScrollDelta::LineDelta(_dx, dy) => { z *= 0.995f32.powf(dy as f32 * 12.0); } }, MouseInput { button: glutin::MouseButton::Left, state, .. } => { match state { glutin::ElementState::Pressed => { dragging = true; } glutin::ElementState::Released => { dragging = false; } } } CursorMoved { position, .. } => { let new_cursor = Vec2::new(position.x as f32, position.y as f32); if dragging { let delta = new_cursor - cursor; rotate *= Mat4x4::rotate_zx(delta.x * std::f32::consts::PI / 512.0); rotate *= Mat4x4::rotate_yz(delta.y * std::f32::consts::PI / 512.0); } cursor = new_cursor; } _ => {} } } _ => {} }); } }