1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#[cfg(feature = "crossterm")]
mod crossterm;
#[cfg(feature = "embedded-graphics")]
mod embedded_graphics;
#[cfg(feature = "embedded-graphics")]
pub use embedded_graphics::EmbeddedGraphicsRenderTarget;
#[cfg(feature = "crossterm")]
pub use crossterm::CrosstermRenderTarget;
mod fixed_text_buffer;
pub use fixed_text_buffer::FixedTextBuffer;
use crate::{
font::{self, FontMetrics as _},
image::EmptyImage,
primitives::{geometry::Shape, Point, Size},
surface::Surface,
};
pub trait RenderTarget {
type ColorFormat;
/// The drawable size of the target
fn size(&self) -> Size;
/// Clears the target using the provided color
fn clear(&mut self, color: Self::ColorFormat);
/// Fills a shape using the specified style and brush.
fn fill<C: Into<Self::ColorFormat>>(
&mut self,
transform_offset: Point,
brush: &impl Brush<ColorFormat = C>,
brush_offset: Option<Point>,
shape: &impl Shape,
);
/// Strokes a shape using the specified style and brush.
fn stroke<C: Into<Self::ColorFormat>>(
&mut self,
stroke: &Stroke,
transform_offset: Point,
brush: &impl Brush<ColorFormat = C>,
brush_offset: Option<Point>,
shape: &impl Shape,
);
/// Draws a series of glyphs using the specified style and brush.
fn draw_glyphs<C: Into<Self::ColorFormat>>(
&mut self,
offset: Point,
brush: &impl Brush<ColorFormat = C>,
glyphs: impl Iterator<Item = Glyph>,
font: &impl font::FontRender<Self::ColorFormat>,
);
/// Draws a string using the specified style and brush.
///
/// This performs the same operation as `draw_glyphs`, but also handles
/// glyph indexing and positioning.
fn draw_str<C: Into<Self::ColorFormat>>(
&mut self,
offset: Point,
brush: &impl Brush<ColorFormat = C>,
text: &str,
font: &impl font::FontRender<Self::ColorFormat>,
) {
let metrics = font.metrics();
let mut x = 0;
self.draw_glyphs(
offset,
brush,
text.chars().map(|c| {
let glyph = Glyph {
character: c,
offset: Point::new(x, 0),
};
x += metrics.advance(glyph.character) as i32;
glyph
}),
font,
);
}
/// Obtain a raw surface to directly write pixels.
///
/// This is most often useful for bridging `embedded_graphics` types
/// that are designed to render to a `DrawTarget`.
///
/// ```
/// # use buoyant::primitives::Size;
/// # use buoyant::render_target::RenderTarget;
/// # use buoyant::render_target::EmbeddedGraphicsRenderTarget;
/// # use embedded_graphics::prelude::*;
/// # use embedded_graphics::pixelcolor::Rgb888;
/// # use embedded_graphics::mock_display::MockDisplay;
/// use tinytga::Tga;
/// use crate::buoyant::surface::AsDrawTarget;
///
/// # let mut display = MockDisplay::<Rgb888>::new();
/// # let mut target = EmbeddedGraphicsRenderTarget::new(&mut display);
/// // let mut target = EmbeddedGraphicsRenderTarget::new(...);
/// # let data = include_bytes!("../tests/assets/rhombic-dodecahedron.tga");
///
/// let img: Tga<Rgb888> = Tga::from_slice(data).unwrap();
///
/// img.draw(&mut target.raw_surface().draw_target());
/// ```
fn raw_surface(&mut self) -> &mut impl Surface<Color = Self::ColorFormat>;
}
/// Positioned glyph.
#[derive(Copy, Clone, Default, Debug)]
pub struct Glyph {
/// The character represented by the glyph.
pub character: char,
/// Offset in run, relative to transform.
pub offset: Point,
}
/// Describes the color content of a filled or stroked shape.
pub trait Brush {
type ColorFormat;
/// Computes the color at a specific point
fn color_at(&self, point: Point) -> Option<Self::ColorFormat>;
/// Solid color brush.
fn as_solid(&self) -> Option<Self::ColorFormat>;
/// Image brush.
fn as_image(&self) -> Option<&impl ImageBrush<ColorFormat = Self::ColorFormat>>;
}
pub trait ImageBrush: Brush {
/// Dimensions of the image.
fn size(&self) -> Size;
/// Iterator over the contiguous pixels of the image.
fn color_iter(&self) -> impl Iterator<Item = Self::ColorFormat>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SolidBrush<C> {
color: C,
}
impl<C: Copy> SolidBrush<C> {
#[must_use]
pub const fn new(color: C) -> Self {
Self { color }
}
}
impl<C: Copy> Brush for SolidBrush<C> {
type ColorFormat = C;
fn color_at(&self, _point: Point) -> Option<Self::ColorFormat> {
Some(self.color)
}
fn as_solid(&self) -> Option<Self::ColorFormat> {
Some(self.color)
}
fn as_image(&self) -> Option<&impl ImageBrush<ColorFormat = Self::ColorFormat>> {
Option::<&EmptyImage<Self::ColorFormat>>::None
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Stroke {
/// Width of the stroke.
pub width: u32,
}
impl Stroke {
#[must_use]
pub const fn new(width: u32) -> Self {
Self { width }
}
}