geng_draw2d/
lib.rs

1use batbox_approx::*;
2use batbox_color::*;
3use batbox_la::*;
4use batbox_lapp::*;
5use geng_camera::*;
6use geng_font::{Font, TextAlign};
7use std::cell::RefCell;
8use ugli::Ugli;
9
10mod chain;
11mod ellipse;
12mod polygon;
13mod quad;
14mod segment;
15mod text;
16
17pub use chain::Chain;
18pub use chain::*;
19pub use ellipse::Ellipse;
20pub use ellipse::*;
21pub use polygon::*;
22pub use quad::Quad;
23pub use quad::*;
24pub use segment::Segment;
25pub use segment::*;
26pub use text::*;
27
28#[derive(ugli::Vertex, Copy, Clone, Debug)]
29pub struct ColoredVertex {
30    pub a_pos: vec2<f32>,
31    pub a_color: Rgba<f32>,
32}
33
34#[derive(ugli::Vertex, Copy, Clone, Debug)]
35pub struct Vertex {
36    pub a_pos: vec2<f32>,
37}
38
39#[derive(ugli::Vertex, Copy, Clone, Debug)]
40pub struct TexturedVertex {
41    pub a_pos: vec2<f32>,
42    pub a_color: Rgba<f32>,
43    pub a_vt: vec2<f32>,
44}
45
46impl From<vec2<f32>> for ColoredVertex {
47    fn from(v: vec2<f32>) -> ColoredVertex {
48        ColoredVertex {
49            a_pos: v,
50            a_color: Rgba::WHITE,
51        }
52    }
53}
54
55pub struct Helper {
56    ugli: Ugli,
57    geometry: RefCell<ugli::VertexBuffer<ColoredVertex>>,
58    textured_geometry: RefCell<ugli::VertexBuffer<TexturedVertex>>,
59    pub(crate) color_program: ugli::Program,
60    pub(crate) textured_program: ugli::Program,
61    unit_quad_geometry: ugli::VertexBuffer<TexturedVertex>,
62    pub(crate) ellipse_program: ugli::Program,
63}
64
65pub trait Draw2d: Transform2d<f32> {
66    fn draw2d_transformed(
67        &self,
68        helper: &Helper,
69        framebuffer: &mut ugli::Framebuffer,
70        camera: &dyn AbstractCamera2d,
71        transform: mat3<f32>,
72    );
73    fn draw2d(
74        &self,
75        helper: &Helper,
76        framebuffer: &mut ugli::Framebuffer,
77        camera: &dyn AbstractCamera2d,
78    ) {
79        self.draw2d_transformed(helper, framebuffer, camera, mat3::identity());
80    }
81}
82
83impl<T: Draw2d + ?Sized> Draw2d for Box<T> {
84    fn draw2d_transformed(
85        &self,
86        helper: &Helper,
87        framebuffer: &mut ugli::Framebuffer,
88        camera: &dyn AbstractCamera2d,
89        transform: mat3<f32>,
90    ) {
91        (**self).draw2d_transformed(helper, framebuffer, camera, transform);
92    }
93}
94
95impl<'a, T: Draw2d + ?Sized> Draw2d for Transformed2d<'a, f32, T> {
96    fn draw2d_transformed(
97        &self,
98        helper: &Helper,
99        framebuffer: &mut ugli::Framebuffer,
100        camera: &dyn AbstractCamera2d,
101        transform: mat3<f32>,
102    ) {
103        self.inner
104            .draw2d_transformed(helper, framebuffer, camera, transform * self.transform);
105    }
106}
107
108impl Helper {
109    pub fn new(ugli: &Ugli, antialias: bool) -> Self {
110        let shader_lib = geng_shader::Library::new(ugli, antialias, None);
111        Self {
112            ugli: ugli.clone(),
113            geometry: RefCell::new(ugli::VertexBuffer::new_dynamic(ugli, Vec::new())),
114            textured_geometry: RefCell::new(ugli::VertexBuffer::new_dynamic(ugli, Vec::new())),
115            color_program: shader_lib
116                .compile(include_str!("shaders/color.glsl"))
117                .unwrap(),
118            textured_program: shader_lib
119                .compile(include_str!("shaders/textured.glsl"))
120                .unwrap(),
121            unit_quad_geometry: ugli::VertexBuffer::new_static(
122                ugli,
123                vec![
124                    TexturedVertex {
125                        a_pos: vec2(-1.0, -1.0),
126                        a_color: Rgba::WHITE,
127                        a_vt: vec2(0.0, 0.0),
128                    },
129                    TexturedVertex {
130                        a_pos: vec2(1.0, -1.0),
131                        a_color: Rgba::WHITE,
132                        a_vt: vec2(1.0, 0.0),
133                    },
134                    TexturedVertex {
135                        a_pos: vec2(1.0, 1.0),
136                        a_color: Rgba::WHITE,
137                        a_vt: vec2(1.0, 1.0),
138                    },
139                    TexturedVertex {
140                        a_pos: vec2(-1.0, 1.0),
141                        a_color: Rgba::WHITE,
142                        a_vt: vec2(0.0, 1.0),
143                    },
144                ],
145            ),
146            ellipse_program: shader_lib
147                .compile(include_str!("shaders/ellipse.glsl"))
148                .unwrap(),
149        }
150    }
151
152    pub fn ugli(&self) -> &Ugli {
153        &self.ugli
154    }
155
156    pub fn draw2d(
157        &self,
158        framebuffer: &mut ugli::Framebuffer,
159        camera: &dyn AbstractCamera2d,
160        drawable: &impl Draw2d,
161    ) {
162        self.draw2d_transformed(framebuffer, camera, drawable, mat3::identity());
163    }
164    pub fn draw2d_transformed(
165        &self,
166        framebuffer: &mut ugli::Framebuffer,
167        camera: &dyn AbstractCamera2d,
168        drawable: &impl Draw2d,
169        transform: mat3<f32>,
170    ) {
171        drawable.draw2d_transformed(self, framebuffer, camera, transform);
172    }
173
174    pub fn draw<V>(
175        &self,
176        framebuffer: &mut ugli::Framebuffer,
177        camera: &impl AbstractCamera2d,
178        vertices: &[V],
179        color: Rgba<f32>,
180        mode: ugli::DrawMode,
181    ) where
182        V: Copy + Into<ColoredVertex>,
183    {
184        let framebuffer_size = framebuffer.size();
185        let mut geometry = self.geometry.borrow_mut();
186        {
187            let geometry: &mut Vec<ColoredVertex> = &mut geometry;
188            geometry.clear();
189            for &vertex in vertices {
190                geometry.push(vertex.into());
191            }
192        }
193        ugli::draw(
194            framebuffer,
195            &self.color_program,
196            mode,
197            &*geometry,
198            (
199                ugli::uniforms! {
200                    u_color: color,
201                    u_framebuffer_size: framebuffer_size,
202                    u_model_matrix: mat3::<f32>::identity(),
203                },
204                camera.uniforms(framebuffer_size.map(|x| x as f32)),
205            ),
206            ugli::DrawParameters {
207                blend_mode: Some(ugli::BlendMode::straight_alpha()),
208                ..Default::default()
209            },
210        )
211    }
212
213    pub fn draw_textured<V>(
214        &self,
215        framebuffer: &mut ugli::Framebuffer,
216        camera: &impl AbstractCamera2d,
217        vertices: &[V],
218        texture: &ugli::Texture,
219        color: Rgba<f32>,
220        mode: ugli::DrawMode,
221    ) where
222        V: Copy + Into<TexturedVertex>,
223    {
224        let framebuffer_size = framebuffer.size();
225        let mut geometry = self.textured_geometry.borrow_mut();
226        {
227            let geometry: &mut Vec<TexturedVertex> = &mut geometry;
228            geometry.clear();
229            for &vertex in vertices {
230                geometry.push(vertex.into());
231            }
232        }
233        ugli::draw(
234            framebuffer,
235            &self.textured_program,
236            mode,
237            &*geometry,
238            (
239                ugli::uniforms! {
240                    u_color: color,
241                    u_texture: texture,
242                    u_framebuffer_size: framebuffer_size,
243                    u_model_matrix: mat3::<f32>::identity(),
244                    u_texture_matrix: mat3::<f32>::identity(),
245                },
246                camera.uniforms(framebuffer_size.map(|x| x as f32)),
247            ),
248            ugli::DrawParameters {
249                blend_mode: Some(ugli::BlendMode::straight_alpha()),
250                ..Default::default()
251            },
252        )
253    }
254
255    pub fn quad(
256        &self,
257        framebuffer: &mut ugli::Framebuffer,
258        camera: &impl AbstractCamera2d,
259        position: Aabb2<f32>,
260        color: Rgba<f32>,
261    ) {
262        self.draw(
263            framebuffer,
264            camera,
265            &[
266                position.bottom_left(),
267                position.bottom_right(),
268                position.top_right(),
269                position.top_left(),
270            ],
271            color,
272            ugli::DrawMode::TriangleFan,
273        );
274    }
275
276    pub fn textured_quad(
277        &self,
278        framebuffer: &mut ugli::Framebuffer,
279        camera: &impl AbstractCamera2d,
280        position: Aabb2<f32>,
281        texture: &ugli::Texture,
282        color: Rgba<f32>,
283    ) {
284        self.draw_textured(
285            framebuffer,
286            camera,
287            &[
288                TexturedVertex {
289                    a_pos: position.bottom_left(),
290                    a_vt: vec2(0.0, 0.0),
291                    a_color: Rgba::WHITE,
292                },
293                TexturedVertex {
294                    a_pos: position.bottom_right(),
295                    a_vt: vec2(1.0, 0.0),
296                    a_color: Rgba::WHITE,
297                },
298                TexturedVertex {
299                    a_pos: position.top_right(),
300                    a_vt: vec2(1.0, 1.0),
301                    a_color: Rgba::WHITE,
302                },
303                TexturedVertex {
304                    a_pos: position.top_left(),
305                    a_vt: vec2(0.0, 1.0),
306                    a_color: Rgba::WHITE,
307                },
308            ],
309            texture,
310            color,
311            ugli::DrawMode::TriangleFan,
312        )
313    }
314
315    pub fn ellipse_with_cut(
316        &self,
317        framebuffer: &mut ugli::Framebuffer,
318        camera: &impl AbstractCamera2d,
319        position: vec2<f32>,
320        radius: vec2<f32>,
321        inner_cut: f32,
322        color: Rgba<f32>,
323    ) {
324        let framebuffer_size = framebuffer.size();
325        ugli::draw(
326            framebuffer,
327            &self.ellipse_program,
328            ugli::DrawMode::TriangleFan,
329            &self.unit_quad_geometry,
330            (
331                ugli::uniforms! {
332                    u_model_matrix: mat3::translate(position) * mat3::scale(radius),
333                    u_color: color,
334                    u_framebuffer_size: framebuffer_size,
335                    u_inner_cut: inner_cut,
336                },
337                camera.uniforms(framebuffer_size.map(|x| x as f32)),
338            ),
339            ugli::DrawParameters {
340                blend_mode: Some(ugli::BlendMode::straight_alpha()),
341                ..Default::default()
342            },
343        )
344    }
345
346    pub fn ellipse(
347        &self,
348        framebuffer: &mut ugli::Framebuffer,
349        camera: &impl AbstractCamera2d,
350        position: vec2<f32>,
351        radius: vec2<f32>,
352        color: Rgba<f32>,
353    ) {
354        self.ellipse_with_cut(framebuffer, camera, position, radius, 0.0, color);
355    }
356
357    pub fn circle_with_cut(
358        &self,
359        framebuffer: &mut ugli::Framebuffer,
360        camera: &impl AbstractCamera2d,
361        position: vec2<f32>,
362        inner_radius: f32,
363        outer_radius: f32,
364        color: Rgba<f32>,
365    ) {
366        self.ellipse_with_cut(
367            framebuffer,
368            camera,
369            position,
370            vec2(outer_radius, outer_radius),
371            inner_radius / outer_radius,
372            color,
373        );
374    }
375
376    pub fn circle(
377        &self,
378        framebuffer: &mut ugli::Framebuffer,
379        camera: &impl AbstractCamera2d,
380        position: vec2<f32>,
381        radius: f32,
382        color: Rgba<f32>,
383    ) {
384        self.ellipse(framebuffer, camera, position, vec2(radius, radius), color);
385    }
386}