// Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later use canary::{DrawCommand, Vec2, PX_PER_MM}; use glium::{program::ProgramCreationInput, Surface}; #[derive(Copy, Clone)] pub struct Vertex { pub position: [f32; 2], pub color: [u8; 4], } glium::implement_vertex!(Vertex, position normalize(false), color normalize(true)); impl Vertex { pub fn from_canary(size: Vec2, v: &canary::MeshVertex) -> Self { // TODO do this in the vertex shader with a size uniform let (r, g, b, a) = v.color.to_rgba_unmultiplied(); Self { position: [ (v.position.x / size.x) * 2.0 - 1.0, (v.position.y / size.y) * -2.0 + 1.0, ], color: [r, g, b, a], } } } const VERTEX_SHADER_SRC: &str = r#" #version 330 in vec2 position; in vec4 color; out vec4 frag_color; void main() { gl_Position = vec4(position, 0.0, 1.0); frag_color = color; } "#; const FRAGMENT_SHADER_SRC: &str = r#" #version 330 in vec4 frag_color; out vec4 fb_color; void main() { fb_color = frag_color; } "#; pub struct Graphics { pub display: glium::Display, pub program: glium::Program, } impl Graphics { pub fn new(display: glium::Display) -> Self { let program = glium::Program::new( &display, ProgramCreationInput::SourceCode { vertex_shader: VERTEX_SHADER_SRC, tessellation_control_shader: None, tessellation_evaluation_shader: None, geometry_shader: None, fragment_shader: FRAGMENT_SHADER_SRC, transform_feedback_varyings: None, outputs_srgb: true, // don't automatically apply gamma correction uses_point_size: false, }, ) .unwrap(); Self { display, program } } pub fn draw(&mut self, commands: &[DrawCommand]) { let mut joined_vs: Vec = Vec::new(); let mut joined_is = Vec::new(); let (width, height) = { let size = self.display.gl_window().window().inner_size(); let (width, height) = (size.width as f32, size.height as f32); (width * PX_PER_MM, height * PX_PER_MM) }; let size = Vec2 { x: width, y: height, }; for command in commands.iter() { match command { canary::DrawCommand::Mesh { vertices, indices } => { let voff = joined_vs.len() as canary::MeshIndex; joined_vs.extend(vertices.iter().map(|v| Vertex::from_canary(size, v))); joined_is.extend(indices.iter().map(|i| i + voff)); } _ => unimplemented!(), } } let vertex_buffer = glium::VertexBuffer::new(&self.display, &joined_vs).unwrap(); let index_buffer = glium::IndexBuffer::new( &self.display, glium::index::PrimitiveType::TrianglesList, &joined_is, ) .unwrap(); let params = glium::DrawParameters { blend: glium::Blend::alpha_blending(), ..Default::default() }; let mut target = self.display.draw(); target.clear_color(0.0, 0.0, 0.0, 0.0); target .draw( &vertex_buffer, &index_buffer, &self.program, &glium::uniforms::EmptyUniforms, ¶ms, ) .unwrap(); target.finish().unwrap(); } }