Skip to main content

render_agnostic/renderers/
macroquad.rs

1use std::borrow::Borrow;
2
3use anchor2d::{Anchor2D, HorizontalAnchor, VerticalAnchorContext, VerticalAnchorValue};
4use macroquad::prelude::*;
5use palette::Srgba;
6
7use crate::{Renderer, image_registries::macroquad_image_registry::MacroquadImageRegistry};
8
9fn srgba_to_color(srgba: Srgba) -> Color {
10    Color {
11        r: srgba.red,
12        g: srgba.green,
13        b: srgba.blue,
14        a: srgba.alpha,
15    }
16}
17
18#[derive(Debug, Default, Clone)]
19pub struct MacroquadRenderer<R: Borrow<MacroquadImageRegistry>> {
20    font: Option<Font>,
21    image_registry: R,
22}
23
24impl<R: Borrow<MacroquadImageRegistry>> MacroquadRenderer<R> {
25    pub fn new(font: Option<Font>, image_registry: R) -> Self {
26        Self {
27            font,
28            image_registry,
29        }
30    }
31
32    pub fn get_font(&self) -> Option<&Font> {
33        self.font.as_ref()
34    }
35
36    pub fn set_font(&mut self, font: Option<Font>) {
37        self.font = font;
38    }
39
40    pub fn get_image_registry(&self) -> &R {
41        &self.image_registry
42    }
43
44    pub fn set_image_registry(&mut self, image_registry: R) {
45        self.image_registry = image_registry;
46    }
47}
48
49impl<R: Borrow<MacroquadImageRegistry>> Renderer for MacroquadRenderer<R> {
50    fn render_point(&mut self, position: ::glam::DVec2, color: Srgba) {
51        draw_rectangle(
52            position.x as f32,
53            position.y as f32,
54            1.0,
55            1.0,
56            srgba_to_color(color),
57        );
58    }
59
60    fn render_line(
61        &mut self,
62        start: ::glam::DVec2,
63        end: ::glam::DVec2,
64        thickness: f64,
65        color: Srgba,
66    ) {
67        draw_line(
68            start.x as f32,
69            start.y as f32,
70            end.x as f32,
71            end.y as f32,
72            thickness as f32,
73            srgba_to_color(color),
74        );
75    }
76
77    fn render_circle(&mut self, position: ::glam::DVec2, radius: f64, color: Srgba) {
78        draw_circle(
79            position.x as f32,
80            position.y as f32,
81            radius as f32,
82            srgba_to_color(color),
83        );
84    }
85
86    fn render_circle_lines(
87        &mut self,
88        position: ::glam::DVec2,
89        radius: f64,
90        thickness: f64,
91        color: Srgba,
92    ) {
93        draw_circle_lines(
94            position.x as f32,
95            position.y as f32,
96            radius as f32,
97            thickness as f32,
98            srgba_to_color(color),
99        );
100    }
101
102    fn render_arc(
103        &mut self,
104        position: ::glam::DVec2,
105        radius: f64,
106        rotation: f64,
107        sides: u8,
108        arc: f64,
109        color: Srgba,
110    ) {
111        // TODO: yeeeaaah... this is just the outline
112        draw_arc(
113            position.x as f32,
114            position.y as f32,
115            sides,
116            radius as f32,
117            rotation.to_degrees() as f32,
118            1.0,
119            arc.to_degrees() as f32,
120            srgba_to_color(color),
121        );
122    }
123
124    fn render_arc_lines(
125        &mut self,
126        position: ::glam::DVec2,
127        radius: f64,
128        rotation: f64,
129        sides: u8,
130        arc: f64,
131        thickness: f64,
132        color: Srgba,
133    ) {
134        draw_arc(
135            position.x as f32,
136            position.y as f32,
137            sides,
138            radius as f32,
139            rotation.to_degrees() as f32,
140            thickness as f32,
141            arc.to_degrees() as f32,
142            srgba_to_color(color),
143        );
144    }
145
146    fn render_text(
147        &mut self,
148        text: &str,
149        position: ::glam::DVec2,
150        anchor: Anchor2D,
151        size: f64,
152        color: Srgba,
153    ) {
154        let measurement = measure_text(text, self.font.as_ref(), size as u16, 1.0);
155
156        let x = match anchor.get_horizontal() {
157            HorizontalAnchor::Left => position.x,
158            HorizontalAnchor::Center => position.x - measurement.width as f64 / 2.0,
159            HorizontalAnchor::Right => position.x - measurement.width as f64,
160        };
161
162        let vertical_anchor = anchor.get_vertical();
163
164        let y = match (vertical_anchor.get_context(), vertical_anchor.get_value()) {
165            (VerticalAnchorContext::Graphics, VerticalAnchorValue::Bottom) => position.y,
166            (VerticalAnchorContext::Math, VerticalAnchorValue::Bottom) => {
167                position.y + measurement.offset_y as f64
168            }
169            (_, VerticalAnchorValue::Center) => position.y + measurement.offset_y as f64 / 2.0,
170            (VerticalAnchorContext::Graphics, VerticalAnchorValue::Top) => {
171                position.y + measurement.offset_y as f64
172            }
173            (VerticalAnchorContext::Math, VerticalAnchorValue::Top) => position.y,
174        };
175
176        draw_text_ex(
177            text,
178            x as f32,
179            y as f32,
180            TextParams {
181                font: self.font.as_ref(),
182                font_size: size as u16,
183                color: srgba_to_color(color),
184                ..TextParams::default()
185            },
186        );
187    }
188
189    fn render_text_outline(
190        &mut self,
191        text: &str,
192        position: ::glam::DVec2,
193        anchor: Anchor2D,
194        size: f64,
195        outline_thickness: f64,
196        color: Srgba,
197        outline_color: Srgba,
198    ) {
199        let measurement = measure_text(text, self.font.as_ref(), size as u16, 1.0);
200
201        let x = match anchor.get_horizontal() {
202            HorizontalAnchor::Left => position.x,
203            HorizontalAnchor::Center => position.x - measurement.width as f64 / 2.0,
204            HorizontalAnchor::Right => position.x - measurement.width as f64,
205        };
206
207        let vertical_anchor = anchor.get_vertical();
208
209        let y = match (vertical_anchor.get_context(), vertical_anchor.get_value()) {
210            (VerticalAnchorContext::Graphics, VerticalAnchorValue::Bottom) => position.y,
211            (VerticalAnchorContext::Math, VerticalAnchorValue::Bottom) => {
212                position.y + measurement.offset_y as f64
213            }
214            (_, VerticalAnchorValue::Center) => position.y + measurement.offset_y as f64 / 2.0,
215            (VerticalAnchorContext::Graphics, VerticalAnchorValue::Top) => {
216                position.y + measurement.offset_y as f64
217            }
218            (VerticalAnchorContext::Math, VerticalAnchorValue::Top) => position.y,
219        };
220
221        for i in -1..=1 {
222            for j in -1..=1 {
223                if i != 0 || j != 0 {
224                    draw_text_ex(
225                        text,
226                        x as f32 - i as f32 * outline_thickness as f32,
227                        y as f32 - j as f32 * outline_thickness as f32,
228                        TextParams {
229                            font: self.font.as_ref(),
230                            font_size: size as u16,
231                            color: srgba_to_color(outline_color),
232                            ..TextParams::default()
233                        },
234                    );
235                }
236            }
237        }
238
239        draw_text_ex(
240            text,
241            x as f32,
242            y as f32,
243            TextParams {
244                font: self.font.as_ref(),
245                font_size: size as u16,
246                color: srgba_to_color(color),
247                ..TextParams::default()
248            },
249        );
250    }
251
252    fn render_rectangle(
253        &mut self,
254        position: ::glam::DVec2,
255        width: f64,
256        height: f64,
257        offset: ::glam::DVec2,
258        rotation: f64,
259        color: Srgba,
260    ) {
261        draw_rectangle_ex(
262            position.x as f32,
263            position.y as f32,
264            width as f32,
265            height as f32,
266            DrawRectangleParams {
267                offset: vec2(offset.x as f32, offset.y as f32),
268                rotation: rotation as f32,
269                color: srgba_to_color(color),
270            },
271        );
272    }
273
274    fn render_rectangle_lines(
275        &mut self,
276        position: ::glam::DVec2,
277        width: f64,
278        height: f64,
279        offset: ::glam::DVec2,
280        rotation: f64,
281        thickness: f64,
282        color: Srgba,
283    ) {
284        draw_rectangle_lines_ex(
285            position.x as f32,
286            position.y as f32,
287            width as f32,
288            height as f32,
289            thickness as f32,
290            DrawRectangleParams {
291                offset: vec2(offset.x as f32, offset.y as f32),
292                rotation: rotation as f32,
293                color: srgba_to_color(color),
294            },
295        );
296    }
297
298    fn render_equilateral_triangle(
299        &mut self,
300        position: ::glam::DVec2,
301        radius: f64,
302        rotation: f64,
303        color: Srgba,
304    ) {
305        draw_poly(
306            position.x as f32,
307            position.y as f32,
308            3,
309            radius as f32,
310            rotation.to_degrees() as f32,
311            srgba_to_color(color),
312        );
313    }
314
315    fn render_equilateral_triangle_lines(
316        &mut self,
317        position: ::glam::DVec2,
318        radius: f64,
319        rotation: f64,
320        thickness: f64,
321        color: Srgba,
322    ) {
323        draw_poly_lines(
324            position.x as f32,
325            position.y as f32,
326            3,
327            radius as f32,
328            rotation.to_degrees() as f32,
329            thickness as f32,
330            srgba_to_color(color),
331        );
332    }
333
334    fn render_image(
335        &mut self,
336        image_name: &str,
337        position: ::glam::DVec2,
338        width: f64,
339        height: f64,
340        offset: ::glam::DVec2,
341        rotation: f64,
342    ) {
343        if let Some(image) = self.image_registry.borrow().get_image(image_name) {
344            draw_texture_ex(
345                image,
346                (position.x - width * offset.x) as f32,
347                (position.y - height * offset.y) as f32,
348                WHITE,
349                DrawTextureParams {
350                    dest_size: Some(vec2(width as f32, height as f32)),
351                    source: None,
352                    rotation: rotation as f32,
353                    flip_x: false,
354                    flip_y: false,
355                    pivot: Some(dvec2(position.x, position.y).as_vec2()),
356                },
357            );
358        }
359    }
360}