1use macroquad::prelude::*;
18
19pub struct Canvas2D {
20 camera: Camera2D,
21 width: f32,
22 height: f32,
23}
24
25impl Canvas2D {
26 #[must_use]
28 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
29 pub fn new(width: f32, height: f32) -> Self {
30 let mut camera = Camera2D::from_display_rect(Rect::new(0.0, 0.0, width, height));
31 camera.render_target = Some(render_target(width as u32, height as u32));
32 camera.zoom.y = -camera.zoom.y;
35 Canvas2D {
36 camera,
37 width,
38 height,
39 }
40 }
41
42 #[must_use]
44 pub fn width(&self) -> f32 {
45 self.width
46 }
47
48 #[must_use]
50 pub fn height(&self) -> f32 {
51 self.height
52 }
53
54 #[must_use]
56 pub fn width_height(&self) -> (f32, f32) {
57 (self.width, self.height)
58 }
59
60 #[must_use]
62 #[allow(clippy::missing_panics_doc)]
63 pub fn get_texture(&self) -> &Texture2D {
64 &self.camera.render_target.as_ref().unwrap().texture
65 }
66
67 #[must_use]
69 #[allow(clippy::missing_panics_doc)]
70 pub fn get_texture_mut(&mut self) -> &mut Texture2D {
71 &mut self.camera.render_target.as_mut().unwrap().texture
72 }
73
74 pub fn set_camera(&self) {
78 set_camera(&self.camera);
79 }
80
81 #[must_use]
84 pub fn calculate_size_and_padding(
85 &self,
86 target_width: f32,
87 target_height: f32,
88 ) -> (f32, f32, Vec2) {
89 let new_size: Vec2 = self.calculate_size(target_width, target_height);
90
91 let left_padding: f32 = (target_width - new_size.x) / 2.0;
93 let top_padding: f32 = (target_height - new_size.y) / 2.0;
94
95 (left_padding, top_padding, new_size)
96 }
97
98 #[must_use]
101 pub fn calculate_size(&self, target_width: f32, target_height: f32) -> Vec2 {
102 let min_scale_factor: f32 = self.calculate_min_scale_factor(target_width, target_height);
103
104 let new_width: f32 = self.width * min_scale_factor;
106 let new_height: f32 = self.height * min_scale_factor;
107
108 Vec2::new(new_width, new_height)
109 }
110
111 #[must_use]
114 pub fn calculate_min_scale_factor(&self, target_width: f32, target_height: f32) -> f32 {
115 let (scale_factor_w, scale_factor_h) =
116 self.calculate_scale_factor(target_width, target_height);
117 f32::min(scale_factor_w, scale_factor_h)
118 }
119
120 #[must_use]
122 pub fn calculate_scale_factor(&self, target_width: f32, target_height: f32) -> (f32, f32) {
123 (target_width / self.width, target_height / self.height)
124 }
125
126 #[must_use]
131 pub fn parent_coordinates_to_canvas_coordinates(
132 &self,
133 parent_width: f32,
134 parent_height: f32,
135 screen_x: f32,
136 screen_y: f32,
137 offset_x: f32,
138 offset_y: f32,
139 ) -> (f32, f32) {
140 let scale_factor = self.calculate_min_scale_factor(parent_width, parent_height);
141
142 let camera_offset = self.camera.offset / self.camera.zoom;
143
144 let x = (screen_x - offset_x) / scale_factor - camera_offset.x;
145 let y = (screen_y - offset_y) / scale_factor - camera_offset.y;
146 (x, y)
147 }
148
149 #[must_use]
153 pub fn canvas_coordinates_to_parent_coordinates(
154 &self,
155 parent_width: f32,
156 parent_height: f32,
157 canvas_x: f32,
158 canvas_y: f32,
159 offset_x: f32,
160 offset_y: f32,
161 ) -> (f32, f32) {
162 let scale_factor = self.calculate_min_scale_factor(parent_width, parent_height);
163 let camera_offset = self.camera.offset / self.camera.zoom;
164
165 let x = ((canvas_x + camera_offset.x) * scale_factor) + offset_x;
166 let y = ((canvas_y + camera_offset.y) * scale_factor) + offset_y;
167 (x, y)
168 }
169
170 #[must_use]
176 pub fn screen_coordinates_to_canvas_coordinates(
177 &self,
178 screen_x: f32,
179 screen_y: f32,
180 offset_x: f32,
181 offset_y: f32,
182 ) -> (f32, f32) {
183 self.parent_coordinates_to_canvas_coordinates(
184 screen_width(),
185 screen_height(),
186 screen_x,
187 screen_y,
188 offset_x,
189 offset_y,
190 )
191 }
192
193 #[must_use]
198 pub fn canvas_coordinates_to_screen_coordinates(
199 &self,
200 canvas_x: f32,
201 canvas_y: f32,
202 offset_x: f32,
203 offset_y: f32,
204 ) -> (f32, f32) {
205 self.canvas_coordinates_to_parent_coordinates(
206 screen_width(),
207 screen_height(),
208 canvas_x,
209 canvas_y,
210 offset_x,
211 offset_y,
212 )
213 }
214
215 #[must_use]
219 pub fn screen_mouse_position_to_canvas(&self, offset_x: f32, offset_y: f32) -> (f32, f32) {
220 let (x, y) = mouse_position();
221 self.screen_coordinates_to_canvas_coordinates(x, y, offset_x, offset_y)
222 }
223
224 pub fn draw_to_screen(&self) {
227 set_default_camera();
228 let (left_padding, top_padding, dimensions) =
230 self.calculate_size_and_padding(screen_width(), screen_height());
231
232 draw_texture_ex(
234 self.get_texture(),
235 left_padding,
236 top_padding,
237 WHITE,
238 DrawTextureParams {
239 dest_size: Some(dimensions),
240 ..Default::default()
241 },
242 );
243 }
244
245 pub fn zoom(&mut self, zoom: f32) {
247 self.camera.zoom += zoom;
248 }
249
250 pub fn set_zoom(&mut self, zoom: f32) {
252 self.camera.zoom = vec2(zoom, zoom);
253 }
254
255 pub fn rotate(&mut self, angle: f32) {
258 self.camera.rotation += angle;
259 }
260
261 pub fn set_rotation(&mut self, angle: f32) {
264 self.camera.rotation = angle;
265 }
266
267 pub fn move_camera_by(&mut self, x_amount: f32, y_amount: f32) {
269 let offset = vec2(x_amount * self.camera.zoom.x, y_amount * self.camera.zoom.y);
270 self.camera.offset += offset;
271 }
272
273 pub fn move_camera_to(&mut self, x_position: f32, y_position: f32) {
275 let offset = vec2(
276 x_position * self.camera.zoom.x,
277 y_position * self.camera.zoom.y,
278 );
279 self.camera.offset = offset;
280 }
281}