1use batbox_approx::*;
2use batbox_color::*;
3use batbox_la::*;
4use batbox_lapp::*;
5use geng_camera::*;
6use geng_font::{Font, TextAlign};
7use std::cell::RefCell;
8use ugli::Ugli;
9
10mod chain;
11mod ellipse;
12mod polygon;
13mod quad;
14mod segment;
15mod text;
16
17pub use chain::Chain;
18pub use chain::*;
19pub use ellipse::Ellipse;
20pub use ellipse::*;
21pub use polygon::*;
22pub use quad::Quad;
23pub use quad::*;
24pub use segment::Segment;
25pub use segment::*;
26pub use text::*;
27
28#[derive(ugli::Vertex, Copy, Clone, Debug)]
29pub struct ColoredVertex {
30 pub a_pos: vec2<f32>,
31 pub a_color: Rgba<f32>,
32}
33
34#[derive(ugli::Vertex, Copy, Clone, Debug)]
35pub struct Vertex {
36 pub a_pos: vec2<f32>,
37}
38
39#[derive(ugli::Vertex, Copy, Clone, Debug)]
40pub struct TexturedVertex {
41 pub a_pos: vec2<f32>,
42 pub a_color: Rgba<f32>,
43 pub a_vt: vec2<f32>,
44}
45
46impl From<vec2<f32>> for ColoredVertex {
47 fn from(v: vec2<f32>) -> ColoredVertex {
48 ColoredVertex {
49 a_pos: v,
50 a_color: Rgba::WHITE,
51 }
52 }
53}
54
55pub struct Helper {
56 ugli: Ugli,
57 geometry: RefCell<ugli::VertexBuffer<ColoredVertex>>,
58 textured_geometry: RefCell<ugli::VertexBuffer<TexturedVertex>>,
59 pub(crate) color_program: ugli::Program,
60 pub(crate) textured_program: ugli::Program,
61 unit_quad_geometry: ugli::VertexBuffer<TexturedVertex>,
62 pub(crate) ellipse_program: ugli::Program,
63}
64
65pub trait Draw2d: Transform2d<f32> {
66 fn draw2d_transformed(
67 &self,
68 helper: &Helper,
69 framebuffer: &mut ugli::Framebuffer,
70 camera: &dyn AbstractCamera2d,
71 transform: mat3<f32>,
72 );
73 fn draw2d(
74 &self,
75 helper: &Helper,
76 framebuffer: &mut ugli::Framebuffer,
77 camera: &dyn AbstractCamera2d,
78 ) {
79 self.draw2d_transformed(helper, framebuffer, camera, mat3::identity());
80 }
81}
82
83impl<T: Draw2d + ?Sized> Draw2d for Box<T> {
84 fn draw2d_transformed(
85 &self,
86 helper: &Helper,
87 framebuffer: &mut ugli::Framebuffer,
88 camera: &dyn AbstractCamera2d,
89 transform: mat3<f32>,
90 ) {
91 (**self).draw2d_transformed(helper, framebuffer, camera, transform);
92 }
93}
94
95impl<'a, T: Draw2d + ?Sized> Draw2d for Transformed2d<'a, f32, T> {
96 fn draw2d_transformed(
97 &self,
98 helper: &Helper,
99 framebuffer: &mut ugli::Framebuffer,
100 camera: &dyn AbstractCamera2d,
101 transform: mat3<f32>,
102 ) {
103 self.inner
104 .draw2d_transformed(helper, framebuffer, camera, transform * self.transform);
105 }
106}
107
108impl Helper {
109 pub fn new(ugli: &Ugli, antialias: bool) -> Self {
110 let shader_lib = geng_shader::Library::new(ugli, antialias, None);
111 Self {
112 ugli: ugli.clone(),
113 geometry: RefCell::new(ugli::VertexBuffer::new_dynamic(ugli, Vec::new())),
114 textured_geometry: RefCell::new(ugli::VertexBuffer::new_dynamic(ugli, Vec::new())),
115 color_program: shader_lib
116 .compile(include_str!("shaders/color.glsl"))
117 .unwrap(),
118 textured_program: shader_lib
119 .compile(include_str!("shaders/textured.glsl"))
120 .unwrap(),
121 unit_quad_geometry: ugli::VertexBuffer::new_static(
122 ugli,
123 vec![
124 TexturedVertex {
125 a_pos: vec2(-1.0, -1.0),
126 a_color: Rgba::WHITE,
127 a_vt: vec2(0.0, 0.0),
128 },
129 TexturedVertex {
130 a_pos: vec2(1.0, -1.0),
131 a_color: Rgba::WHITE,
132 a_vt: vec2(1.0, 0.0),
133 },
134 TexturedVertex {
135 a_pos: vec2(1.0, 1.0),
136 a_color: Rgba::WHITE,
137 a_vt: vec2(1.0, 1.0),
138 },
139 TexturedVertex {
140 a_pos: vec2(-1.0, 1.0),
141 a_color: Rgba::WHITE,
142 a_vt: vec2(0.0, 1.0),
143 },
144 ],
145 ),
146 ellipse_program: shader_lib
147 .compile(include_str!("shaders/ellipse.glsl"))
148 .unwrap(),
149 }
150 }
151
152 pub fn ugli(&self) -> &Ugli {
153 &self.ugli
154 }
155
156 pub fn draw2d(
157 &self,
158 framebuffer: &mut ugli::Framebuffer,
159 camera: &dyn AbstractCamera2d,
160 drawable: &impl Draw2d,
161 ) {
162 self.draw2d_transformed(framebuffer, camera, drawable, mat3::identity());
163 }
164 pub fn draw2d_transformed(
165 &self,
166 framebuffer: &mut ugli::Framebuffer,
167 camera: &dyn AbstractCamera2d,
168 drawable: &impl Draw2d,
169 transform: mat3<f32>,
170 ) {
171 drawable.draw2d_transformed(self, framebuffer, camera, transform);
172 }
173
174 pub fn draw<V>(
175 &self,
176 framebuffer: &mut ugli::Framebuffer,
177 camera: &impl AbstractCamera2d,
178 vertices: &[V],
179 color: Rgba<f32>,
180 mode: ugli::DrawMode,
181 ) where
182 V: Copy + Into<ColoredVertex>,
183 {
184 let framebuffer_size = framebuffer.size();
185 let mut geometry = self.geometry.borrow_mut();
186 {
187 let geometry: &mut Vec<ColoredVertex> = &mut geometry;
188 geometry.clear();
189 for &vertex in vertices {
190 geometry.push(vertex.into());
191 }
192 }
193 ugli::draw(
194 framebuffer,
195 &self.color_program,
196 mode,
197 &*geometry,
198 (
199 ugli::uniforms! {
200 u_color: color,
201 u_framebuffer_size: framebuffer_size,
202 u_model_matrix: mat3::<f32>::identity(),
203 },
204 camera.uniforms(framebuffer_size.map(|x| x as f32)),
205 ),
206 ugli::DrawParameters {
207 blend_mode: Some(ugli::BlendMode::straight_alpha()),
208 ..Default::default()
209 },
210 )
211 }
212
213 pub fn draw_textured<V>(
214 &self,
215 framebuffer: &mut ugli::Framebuffer,
216 camera: &impl AbstractCamera2d,
217 vertices: &[V],
218 texture: &ugli::Texture,
219 color: Rgba<f32>,
220 mode: ugli::DrawMode,
221 ) where
222 V: Copy + Into<TexturedVertex>,
223 {
224 let framebuffer_size = framebuffer.size();
225 let mut geometry = self.textured_geometry.borrow_mut();
226 {
227 let geometry: &mut Vec<TexturedVertex> = &mut geometry;
228 geometry.clear();
229 for &vertex in vertices {
230 geometry.push(vertex.into());
231 }
232 }
233 ugli::draw(
234 framebuffer,
235 &self.textured_program,
236 mode,
237 &*geometry,
238 (
239 ugli::uniforms! {
240 u_color: color,
241 u_texture: texture,
242 u_framebuffer_size: framebuffer_size,
243 u_model_matrix: mat3::<f32>::identity(),
244 u_texture_matrix: mat3::<f32>::identity(),
245 },
246 camera.uniforms(framebuffer_size.map(|x| x as f32)),
247 ),
248 ugli::DrawParameters {
249 blend_mode: Some(ugli::BlendMode::straight_alpha()),
250 ..Default::default()
251 },
252 )
253 }
254
255 pub fn quad(
256 &self,
257 framebuffer: &mut ugli::Framebuffer,
258 camera: &impl AbstractCamera2d,
259 position: Aabb2<f32>,
260 color: Rgba<f32>,
261 ) {
262 self.draw(
263 framebuffer,
264 camera,
265 &[
266 position.bottom_left(),
267 position.bottom_right(),
268 position.top_right(),
269 position.top_left(),
270 ],
271 color,
272 ugli::DrawMode::TriangleFan,
273 );
274 }
275
276 pub fn textured_quad(
277 &self,
278 framebuffer: &mut ugli::Framebuffer,
279 camera: &impl AbstractCamera2d,
280 position: Aabb2<f32>,
281 texture: &ugli::Texture,
282 color: Rgba<f32>,
283 ) {
284 self.draw_textured(
285 framebuffer,
286 camera,
287 &[
288 TexturedVertex {
289 a_pos: position.bottom_left(),
290 a_vt: vec2(0.0, 0.0),
291 a_color: Rgba::WHITE,
292 },
293 TexturedVertex {
294 a_pos: position.bottom_right(),
295 a_vt: vec2(1.0, 0.0),
296 a_color: Rgba::WHITE,
297 },
298 TexturedVertex {
299 a_pos: position.top_right(),
300 a_vt: vec2(1.0, 1.0),
301 a_color: Rgba::WHITE,
302 },
303 TexturedVertex {
304 a_pos: position.top_left(),
305 a_vt: vec2(0.0, 1.0),
306 a_color: Rgba::WHITE,
307 },
308 ],
309 texture,
310 color,
311 ugli::DrawMode::TriangleFan,
312 )
313 }
314
315 pub fn ellipse_with_cut(
316 &self,
317 framebuffer: &mut ugli::Framebuffer,
318 camera: &impl AbstractCamera2d,
319 position: vec2<f32>,
320 radius: vec2<f32>,
321 inner_cut: f32,
322 color: Rgba<f32>,
323 ) {
324 let framebuffer_size = framebuffer.size();
325 ugli::draw(
326 framebuffer,
327 &self.ellipse_program,
328 ugli::DrawMode::TriangleFan,
329 &self.unit_quad_geometry,
330 (
331 ugli::uniforms! {
332 u_model_matrix: mat3::translate(position) * mat3::scale(radius),
333 u_color: color,
334 u_framebuffer_size: framebuffer_size,
335 u_inner_cut: inner_cut,
336 },
337 camera.uniforms(framebuffer_size.map(|x| x as f32)),
338 ),
339 ugli::DrawParameters {
340 blend_mode: Some(ugli::BlendMode::straight_alpha()),
341 ..Default::default()
342 },
343 )
344 }
345
346 pub fn ellipse(
347 &self,
348 framebuffer: &mut ugli::Framebuffer,
349 camera: &impl AbstractCamera2d,
350 position: vec2<f32>,
351 radius: vec2<f32>,
352 color: Rgba<f32>,
353 ) {
354 self.ellipse_with_cut(framebuffer, camera, position, radius, 0.0, color);
355 }
356
357 pub fn circle_with_cut(
358 &self,
359 framebuffer: &mut ugli::Framebuffer,
360 camera: &impl AbstractCamera2d,
361 position: vec2<f32>,
362 inner_radius: f32,
363 outer_radius: f32,
364 color: Rgba<f32>,
365 ) {
366 self.ellipse_with_cut(
367 framebuffer,
368 camera,
369 position,
370 vec2(outer_radius, outer_radius),
371 inner_radius / outer_radius,
372 color,
373 );
374 }
375
376 pub fn circle(
377 &self,
378 framebuffer: &mut ugli::Framebuffer,
379 camera: &impl AbstractCamera2d,
380 position: vec2<f32>,
381 radius: f32,
382 color: Rgba<f32>,
383 ) {
384 self.ellipse(framebuffer, camera, position, vec2(radius, radius), color);
385 }
386}