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 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}