1use std::ops::{Deref, DerefMut};
5
6#[cfg(feature = "unifont")]
7use sdl2::{pixels::Color, render::Texture};
8use sdl2::{
9 rect::Point,
10 render::{Canvas as SdlCanvas, RenderTarget, TextureCreator},
11 surface::{Surface, SurfaceContext},
12 video::{Window, WindowContext},
13};
14#[cfg(feature = "unifont")]
15use sdl2_unifont::renderer::SurfaceRenderer as TextRenderer;
16
17pub type SurfaceCanvas<'a> = Canvas<Surface<'a>, SurfaceContext<'a>>;
19pub type WindowCanvas = Canvas<Window, WindowContext>;
21
22pub struct Canvas<T: RenderTarget, U> {
30 inner: SdlCanvas<T>,
31 texture_creator: TextureCreator<U>,
32 #[cfg(feature = "unifont")]
33 text_renderer: TextRenderer,
34 #[cfg(feature = "unifont")]
35 synced_colors: bool,
36}
37
38impl WindowCanvas {
39 pub fn new(inner: SdlCanvas<Window>) -> Self {
42 let texture_creator = inner.texture_creator();
43 #[cfg(feature = "unifont")]
44 let text_renderer = TextRenderer::new(inner.draw_color(), Color::RGBA(0, 0, 0, 0));
45 Self {
46 inner,
47 texture_creator,
48 #[cfg(feature = "unifont")]
49 text_renderer,
50 #[cfg(feature = "unifont")]
51 synced_colors: true,
52 }
53 }
54}
55
56impl<'a> SurfaceCanvas<'a> {
57 pub fn new(inner: SdlCanvas<Surface<'a>>) -> Self {
60 let texture_creator = inner.texture_creator();
61 #[cfg(feature = "unifont")]
62 let text_renderer = TextRenderer::new(inner.draw_color(), Color::RGBA(0, 0, 0, 0));
63 Self {
64 inner,
65 texture_creator,
66 #[cfg(feature = "unifont")]
67 text_renderer,
68 #[cfg(feature = "unifont")]
69 synced_colors: true,
70 }
71 }
72
73 #[cfg(feature = "unifont")]
80 pub fn draw_text_surface<P: Into<Point>>(
81 &mut self,
82 text: &str,
83 pos: P,
84 ) -> Result<Surface, String> {
85 let pos = pos.into();
86 let surface = self.text_renderer.draw(text)?;
87 let mut rect = surface.rect();
88 rect.set_x(pos.x());
89 rect.set_y(pos.y());
90 surface.blit(None, self.inner.surface_mut(), rect)?;
91 Ok(surface)
92 }
93}
94
95impl<T: RenderTarget, U> Canvas<T, U> {
96 pub fn texture_creator(&self) -> &TextureCreator<U> {
98 &self.texture_creator
99 }
100
101 pub fn texture_creator_mut(&mut self) -> &mut TextureCreator<U> {
103 &mut self.texture_creator
104 }
105
106 #[cfg(feature = "unifont")]
108 pub fn text_renderer(&self) -> &TextRenderer {
109 &self.text_renderer
110 }
111
112 #[cfg(feature = "unifont")]
114 pub fn text_renderer_mut(&mut self) -> &mut TextRenderer {
115 &mut self.text_renderer
116 }
117
118 #[cfg(feature = "unifont")]
121 pub fn set_draw_color<C: Into<Color>>(&mut self, color: C) {
122 let color = color.into();
123 if self.synced_colors {
124 self.text_renderer.fg_color = color;
125 }
126 self.inner.set_draw_color(color)
127 }
128
129 #[cfg(feature = "unifont")]
132 pub fn set_text_color<C>(&mut self, color: C)
133 where
134 C: Into<Option<Color>>,
135 {
136 self.synced_colors = if let Some(color) = color.into() {
137 self.text_renderer.fg_color = color;
138 false
139 } else {
140 self.text_renderer.fg_color = self.inner.draw_color();
141 true
142 };
143 }
144
145 #[cfg(feature = "unifont")]
148 pub fn draw_text<P: Into<Point>>(&mut self, text: &str, pos: P) -> Result<Texture, String> {
149 let pos = pos.into();
150 let surface = self.text_renderer.draw(text)?;
151 let texture = surface.as_texture(&mut self.texture_creator).unwrap();
152 let mut rect = surface.rect();
153 rect.set_x(pos.x());
154 rect.set_y(pos.y());
155 self.inner.copy(&texture, None, rect)?;
156 Ok(texture)
157 }
158
159 fn draw_circle_points(&mut self, center: Point, point: Point) -> Result<(), String> {
160 let points = &[
161 Point::new(center.x() + point.x(), center.y() + point.y()),
162 Point::new(center.x() - point.x(), center.y() + point.y()),
163 Point::new(center.x() + point.x(), center.y() - point.y()),
164 Point::new(center.x() - point.x(), center.y() - point.y()),
165 Point::new(center.x() + point.y(), center.y() + point.x()),
166 Point::new(center.x() - point.y(), center.y() + point.x()),
167 Point::new(center.x() + point.y(), center.y() - point.x()),
168 Point::new(center.x() - point.y(), center.y() - point.x()),
169 ];
170 self.inner.draw_points(points.as_ref())
171 }
172
173 fn fill_circle_lines(&mut self, center: Point, point: Point) -> Result<(), String> {
174 let points = &[
175 Point::new(center.x() + point.x(), center.y() + point.y()),
176 Point::new(center.x() - point.x(), center.y() + point.y()),
177 Point::new(center.x() + point.x(), center.y() - point.y()),
178 Point::new(center.x() - point.x(), center.y() - point.y()),
179 Point::new(center.x() + point.y(), center.y() + point.x()),
180 Point::new(center.x() - point.y(), center.y() + point.x()),
181 Point::new(center.x() + point.y(), center.y() - point.x()),
182 Point::new(center.x() - point.y(), center.y() - point.x()),
183 ];
184 self.inner.draw_lines(points.as_ref())
185 }
186
187 pub fn draw_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
189 where
190 P: Into<Point>,
191 {
192 let center = center.into();
193 let mut current = Point::new(0, radius);
194 let mut d = 3 - 2 * radius;
195 self.draw_circle_points(center, current)?;
196 while current.y() >= current.x() {
197 current = current.offset(1, 0);
199
200 if d > 0 {
202 current = current.offset(0, -1);
203 d += 4 * (current.x() - current.y()) + 10;
204 } else {
205 d += 4 * current.x() + 6;
206 self.draw_circle_points(center, current)?;
207 }
208 }
209 Ok(())
210 }
211
212 pub fn fill_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
214 where
215 P: Into<Point>,
216 {
217 let center = center.into();
218 let mut current = Point::new(0, radius);
219 let mut d = 3 - 2 * radius;
220 self.fill_circle_lines(center, current)?;
221 while current.y() >= current.x() {
222 current = current.offset(1, 0);
224
225 if d > 0 {
227 current = current.offset(0, -1);
228 d += 4 * (current.x() - current.y()) + 10;
229 } else {
230 d += 4 * current.x() + 6;
231 self.fill_circle_lines(center, current)?;
232 }
233 }
234 Ok(())
235 }
236}
237
238impl<T: RenderTarget, U> Deref for Canvas<T, U> {
239 type Target = SdlCanvas<T>;
240
241 fn deref(&self) -> &Self::Target {
242 &self.inner
243 }
244}
245
246impl<T: RenderTarget, U> DerefMut for Canvas<T, U> {
247 fn deref_mut(&mut self) -> &mut Self::Target {
248 &mut self.inner
249 }
250}