1#![deny(missing_docs)]
2
3mod glyphs;
18pub use crate::glyphs::*;
19
20use std::{error, fmt, fs::File, ops, path::Path};
21
22use bit_vec::BitVec;
23use graphics::{draw_state::DrawState, math::Matrix2d, types::Color, Graphics, ImageSize};
24use image::{DynamicImage, GenericImageView, ImageResult, Rgba, RgbaImage};
25#[cfg(feature = "piston_window_texture")]
26use piston_window::{G2dTexture, G2dTextureContext};
27use png::{Decoder as PngDecoder, Limits};
28use rayon::prelude::*;
29use texture::{CreateTexture, Format, TextureOp, TextureSettings, UpdateTexture};
30
31pub const IDENTITY: Matrix2d = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];
33
34#[derive(Debug, Clone)]
36pub enum Error {
37 SizeMismatch(usize, usize),
39}
40
41impl fmt::Display for Error {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Error::SizeMismatch(len, area) => write!(
45 f,
46 "Container is too small for the given dimensions. \
47 \nContainer has {} bytes, which encode {} pixels, \
48 \nbut the given demensions contain {} pixels",
49 len,
50 len / 4,
51 area
52 ),
53 }
54 }
55}
56
57impl error::Error for Error {}
58
59#[derive(Debug, Clone, PartialEq, Eq, Hash)]
63pub struct RenderBuffer {
64 inner: RgbaImage,
65 used: Vec<BitVec>,
66}
67
68impl RenderBuffer {
69 pub fn new(width: u32, height: u32) -> RenderBuffer {
71 RenderBuffer {
72 inner: RgbaImage::new(width, height),
73 used: vec![BitVec::from_elem(height as usize, false); width as usize],
74 }
75 }
76 pub fn open<P: AsRef<Path>>(path: P) -> Result<RenderBuffer, Box<dyn error::Error>> {
78 if path
79 .as_ref()
80 .extension()
81 .map(|ext| ext == "png")
82 .unwrap_or(false)
83 {
84 let (info, mut reader) = PngDecoder::new_with_limits(
85 File::open(&path)?,
86 Limits {
87 bytes: std::usize::MAX,
88 },
89 )
90 .read_info()?;
91 let mut buf = vec![0; info.buffer_size()];
92 reader.next_frame(&mut buf)?;
93 Ok(
94 if let Some(image) = image::RgbaImage::from_raw(info.width, info.height, buf) {
95 image.into()
96 } else {
97 image::open(path)?.into()
98 },
99 )
100 } else {
101 Ok(image::open(path)?.into())
102 }
103 }
104 pub fn decode_from_bytes(bytes: &[u8]) -> ImageResult<RenderBuffer> {
106 image::load_from_memory(bytes).map(RenderBuffer::from)
107 }
108 pub fn clear(&mut self, color: [f32; 4]) {
110 self.clear_color(color);
111 }
112 pub fn pixel(&self, x: u32, y: u32) -> [f32; 4] {
114 color_rgba_f32(*self.inner.get_pixel(x, y))
115 }
116 pub fn set_pixel(&mut self, x: u32, y: u32, color: [f32; 4]) {
118 self.inner.put_pixel(x, y, color_f32_rgba(&color));
119 }
120 fn reset_used(&mut self) {
121 let (width, height) = self.inner.dimensions();
122 self.used = vec![BitVec::from_elem(height as usize, false); width as usize];
123 }
124 #[cfg(feature = "piston_window_texture")]
126 pub fn to_g2d_texture(
127 &self,
128 context: &mut G2dTextureContext,
129 settings: &TextureSettings,
130 ) -> Result<G2dTexture, Box<dyn error::Error>> {
131 Ok(G2dTexture::from_image(context, &self.inner, settings)?)
132 }
133}
134
135impl TextureOp<()> for RenderBuffer {
136 type Error = Error;
137}
138
139impl CreateTexture<()> for RenderBuffer {
140 fn create<S: Into<[u32; 2]>>(
141 _factory: &mut (),
142 _format: Format,
143 memory: &[u8],
144 size: S,
145 _settings: &TextureSettings,
146 ) -> Result<Self, Error> {
147 let size = size.into();
148 Ok(RenderBuffer::from(
149 RgbaImage::from_raw(size[0], size[1], memory.to_vec())
150 .ok_or_else(|| Error::SizeMismatch(memory.len(), (size[0] * size[1]) as usize))?,
151 ))
152 }
153}
154
155impl UpdateTexture<()> for RenderBuffer {
156 fn update<O, S>(
157 &mut self,
158 _factory: &mut (),
159 _format: Format,
160 memory: &[u8],
161 offset: O,
162 size: S,
163 ) -> Result<(), Self::Error>
164 where
165 O: Into<[u32; 2]>,
166 S: Into<[u32; 2]>,
167 {
168 let offset = offset.into();
169 let size = size.into();
170 let new_image = RenderBuffer::from(
171 RgbaImage::from_raw(size[0], size[1], memory.to_vec())
172 .ok_or_else(|| Error::SizeMismatch(memory.len(), (size[0] * size[1]) as usize))?,
173 );
174 for i in 0..size[0] {
175 for j in 0..size[1] {
176 let color = new_image.pixel(i, j);
177 self.set_pixel(i + offset[0], j + offset[1], color);
178 }
179 }
180 Ok(())
181 }
182}
183
184impl From<RgbaImage> for RenderBuffer {
185 fn from(image: RgbaImage) -> Self {
186 let (width, height) = image.dimensions();
187 RenderBuffer {
188 inner: image,
189 used: vec![BitVec::from_elem(height as usize, false); width as usize],
190 }
191 }
192}
193
194impl From<DynamicImage> for RenderBuffer {
195 fn from(image: DynamicImage) -> Self {
196 let (width, height) = image.dimensions();
197 RenderBuffer {
198 inner: image.to_rgba8(),
199 used: vec![BitVec::from_elem(height as usize, false); width as usize],
200 }
201 }
202}
203
204impl ops::Deref for RenderBuffer {
205 type Target = RgbaImage;
206 fn deref(&self) -> &Self::Target {
207 &self.inner
208 }
209}
210
211impl ImageSize for RenderBuffer {
212 fn get_size(&self) -> (u32, u32) {
213 self.inner.dimensions()
214 }
215}
216
217impl Graphics for RenderBuffer {
218 type Texture = RenderBuffer;
219 fn clear_color(&mut self, color: Color) {
220 for (_, _, pixel) in self.inner.enumerate_pixels_mut() {
221 *pixel = color_f32_rgba(&color);
222 }
223 }
224 fn clear_stencil(&mut self, _value: u8) {}
225 fn tri_list<F>(&mut self, _draw_state: &DrawState, color: &[f32; 4], mut f: F)
226 where
227 F: FnMut(&mut dyn FnMut(&[[f32; 2]])),
228 {
229 self.reset_used();
230 f(&mut |vertices| {
232 for tri in vertices.chunks(3) {
233 let mut tl = [0f32, 0f32];
235 let mut br = [0f32, 0f32];
236 for v in tri {
237 tl[0] = tl[0].min(v[0]);
238 tl[1] = tl[1].min(v[1]);
239 br[0] = br[0].max(v[0]);
240 br[1] = br[1].max(v[1]);
241 }
242 let tl = [tl[0].floor().max(0.0) as i32, tl[1].floor().max(0.0) as i32];
243 let br = [
244 br[0].ceil().min(self.width() as f32) as i32,
245 br[1].ceil().min(self.height() as f32) as i32,
246 ];
247 let inner = &self.inner;
249 let used = &self.used;
250 (tl[0]..br[0]).into_par_iter().for_each(|x| {
251 let mut entered = false;
252 for y in tl[1]..br[1] {
253 if triangle_contains(tri, [x as f32, y as f32]) {
254 entered = true;
255 if !used[x as usize].get(y as usize).unwrap_or(true) {
256 let under_color =
257 color_rgba_f32(*inner.get_pixel(x as u32, y as u32));
258 let layered_color = layer_color(&color, &under_color);
259 unsafe {
260 (inner as *const RgbaImage as *mut RgbaImage)
261 .as_mut()
262 .unwrap()
263 .put_pixel(
264 x as u32,
265 y as u32,
266 color_f32_rgba(&layered_color),
267 );
268 (used as *const Vec<BitVec> as *mut Vec<BitVec>)
269 .as_mut()
270 .unwrap()[x as usize]
271 .set(y as usize, true);
272 }
273 }
274 } else if entered {
275 break;
276 }
277 }
278 });
279 }
280 });
281 }
282 fn tri_list_uv<F>(
283 &mut self,
284 _draw_state: &DrawState,
285 color: &[f32; 4],
286 texture: &Self::Texture,
287 mut f: F,
288 ) where
289 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]])),
290 {
291 self.reset_used();
292 f(&mut |vertices, tex_vertices| {
294 for (tri, tex_tri) in vertices.chunks(3).zip(tex_vertices.chunks(3)) {
295 let mut tl = [0f32, 0f32];
297 let mut br = [0f32, 0f32];
298 for v in tri {
299 tl[0] = tl[0].min(v[0]);
300 tl[1] = tl[1].min(v[1]);
301 br[0] = br[0].max(v[0]);
302 br[1] = br[1].max(v[1]);
303 }
304 let tl = [tl[0].floor().max(0.0) as i32, tl[1].floor().max(0.0) as i32];
305 let br = [
306 br[0].ceil().min((self.width() - 1) as f32) as i32,
307 br[1].ceil().min((self.height() - 1) as f32) as i32,
308 ];
309 let avg_y = ((tri[0][1] + tri[1][1] + tri[2][1]) / 3.0) as i32;
310 let vert_center = (br[1] - tl[1]) / 2;
311 let vertical_balance_top = avg_y < vert_center;
312 let scaled_tex_tri = tri_image_scale(tex_tri, texture.get_size());
314 let inner = &self.inner;
315 let used = &self.used;
316 (tl[0]..br[0]).into_par_iter().for_each(|x| {
317 let mut entered = false;
318 let range: Box<dyn Iterator<Item = i32>> = if vertical_balance_top {
319 Box::new(tl[1]..br[1])
320 } else {
321 Box::new((tl[1]..br[1]).rev())
322 };
323 for y in range {
324 if triangle_contains(tri, [x as f32, y as f32]) {
325 entered = true;
326 let mapped_point =
327 map_to_triangle([x as f32, y as f32], tri, &scaled_tex_tri);
328 let texel = color_rgba_f32(*texture.get_pixel(
329 (mapped_point[0].round() as u32).min(texture.width() - 1),
330 (mapped_point[1].round() as u32).min(texture.height() - 1),
331 ));
332 let over_color = color_mul(color, &texel);
333 let under_color = color_rgba_f32(*inner.get_pixel(x as u32, y as u32));
334 let layered_color = layer_color(&over_color, &under_color);
335 unsafe {
336 (inner as *const RgbaImage as *mut RgbaImage)
337 .as_mut()
338 .unwrap()
339 .put_pixel(x as u32, y as u32, color_f32_rgba(&layered_color));
340 (used as *const Vec<BitVec> as *mut Vec<BitVec>)
341 .as_mut()
342 .unwrap()[x as usize]
343 .set(y as usize, true);
344 }
345 } else if entered {
346 break;
347 }
348 }
349 });
350 }
351 });
352 }
353
354 fn tri_list_c<F>(&mut self, _: &DrawState, _: F)
355 where
356 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]])),
357 {
358 unimplemented!("<RenderBuffer as Graphics>::tri_list_c is currently unimplemented")
359 }
360
361 fn tri_list_uv_c<F>(&mut self, _: &DrawState, _: &Self::Texture, _: F)
362 where
363 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]])),
364 {
365 unimplemented!("<RenderBuffer as Graphics>::tri_list_uv_c is currently unimplemented")
366 }
367}
368
369fn color_f32_rgba(color: &[f32; 4]) -> Rgba<u8> {
370 Rgba([
371 (color[0] * 255.0) as u8,
372 (color[1] * 255.0) as u8,
373 (color[2] * 255.0) as u8,
374 (color[3] * 255.0) as u8,
375 ])
376}
377
378fn color_rgba_f32(color: Rgba<u8>) -> [f32; 4] {
379 [
380 f32::from(color[0]) / 255.0,
381 f32::from(color[1]) / 255.0,
382 f32::from(color[2]) / 255.0,
383 f32::from(color[3]) / 255.0,
384 ]
385}
386
387fn color_mul(a: &[f32; 4], b: &[f32; 4]) -> [f32; 4] {
388 [a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]]
389}
390
391fn layer_color(over: &[f32; 4], under: &[f32; 4]) -> [f32; 4] {
392 let over_weight = 1.0 - (1.0 - over[3]).powf(2.0);
393 let under_weight = 1.0 - over_weight;
394 [
395 over_weight * over[0] + under_weight * under[0],
396 over_weight * over[1] + under_weight * under[1],
397 over_weight * over[2] + under_weight * under[2],
398 (over[3].powf(2.0) + under[3].powf(2.0)).sqrt().min(1.0),
399 ]
400}
401
402fn sign(p1: [f32; 2], p2: [f32; 2], p3: [f32; 2]) -> f32 {
403 (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
404}
405
406fn triangle_contains(tri: &[[f32; 2]], point: [f32; 2]) -> bool {
407 let b1 = sign(point, tri[0], tri[1]) < 0.0;
408 let b2 = sign(point, tri[1], tri[2]) < 0.0;
409 let b3 = sign(point, tri[2], tri[0]) < 0.0;
410 b1 == b2 && b2 == b3
411}
412
413#[allow(clippy::many_single_char_names)]
414fn map_to_triangle(point: [f32; 2], from_tri: &[[f32; 2]], to_tri: &[[f32; 2]]) -> [f32; 2] {
415 let t = from_tri;
416 let p = point;
417 let a = t[1][1] - t[2][1];
419 let b = p[0] - t[2][0];
420 let c = t[2][0] - t[1][0];
421 let d = p[1] - t[2][1];
422 let e = t[0][0] - t[2][0];
423 let f = t[0][1] - t[2][1];
424 let g = t[2][1] - t[0][1];
425 let ae_cf = a * e + c * f;
426 let bary_a = (a * b + c * d) / ae_cf;
427 let bary_b = (g * b + e * d) / ae_cf;
428 let bary_c = 1.0 - bary_a - bary_b;
429 [
430 bary_a * to_tri[0][0] + bary_b * to_tri[1][0] + bary_c * to_tri[2][0],
431 bary_a * to_tri[0][1] + bary_b * to_tri[1][1] + bary_c * to_tri[2][1],
432 ]
433}
434
435fn point_image_scale(point: [f32; 2], size: (u32, u32)) -> [f32; 2] {
436 [point[0] * size.0 as f32, point[1] * size.1 as f32]
437}
438
439fn tri_image_scale(tri: &[[f32; 2]], size: (u32, u32)) -> [[f32; 2]; 3] {
440 [
441 point_image_scale(tri[0], size),
442 point_image_scale(tri[1], size),
443 point_image_scale(tri[2], size),
444 ]
445}