render_agnostic/renderers/
macroquad.rs

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