1#![warn(missing_docs)]
2
3extern crate retro_pixel;
10pub use retro_pixel::*;
11
12#[macro_use]
13extern crate glium;
14use glium::{
15 backend::glutin::DisplayCreationError, glutin::{
16 dpi::{LogicalPosition, LogicalSize}, ContextBuilder, EventsLoop, WindowBuilder,
17 },
18 program::ProgramCreationError,
19 texture::{
20 texture2d::Texture2d, unsigned_texture2d::UnsignedTexture2d, ClientFormat, MipmapsOption, RawImage2d, TextureCreationError,
21 UncompressedFloatFormat,
22 },
23 uniforms::{MagnifySamplerFilter, MinifySamplerFilter, Sampler}, vertex::BufferCreationError, Display, DrawError, Program, Surface,
24 SwapBuffersError, VertexBuffer,
25};
26
27pub use glium::glutin::*;
28
29use std::borrow::Cow;
31
32mod demo_font;
34use demo_font::*;
35
36#[derive(Copy, Clone)]
37struct Vertex {
38 position: [f32; 2],
39}
40implement_vertex!(Vertex, position);
41
42static VERTICES: [Vertex; 6] = [
43 Vertex { position: [-1.0, -1.0] },
44 Vertex { position: [-1.0, 1.0] },
45 Vertex { position: [1.0, 1.0] },
46 Vertex { position: [1.0, 1.0] },
47 Vertex { position: [1.0, -1.0] },
48 Vertex { position: [-1.0, -1.0] },
49];
50
51#[derive(Debug)]
55#[allow(missing_docs)]
56pub enum DwarfTermGliumError {
57 DisplayCreationError(DisplayCreationError),
58 ProgramCreationError(ProgramCreationError),
59 TextureCreationError(TextureCreationError),
60 BufferCreationError(BufferCreationError),
61 DrawError(DrawError),
62 SwapBuffersError(SwapBuffersError),
63}
64
65pub struct DwarfTerm {
67 fgs: VecImage<u32>,
68 bgs: VecImage<u32>,
69 ids: VecImage<u8>,
70 clear_color: (f32, f32, f32, f32),
71 events_loop: EventsLoop,
72 display: Display,
73 program: Program,
74 sprite_texture: Texture2d,
75}
76impl ::std::fmt::Debug for DwarfTerm {
77 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
78 write!(f, "DwarfTerm [ width {}, height {} ]", self.ids.width(), self.ids.height())
79 }
80}
81
82impl DwarfTerm {
83 pub fn new<T>(grid_width: u32, grid_height: u32, title: T) -> Result<Self, DwarfTermGliumError>
85 where
86 T: Into<String>,
87 {
88 let window_pixel_width = DEMO_FONT_TILE_SIZE.0 * grid_width;
90 let window_pixel_height = DEMO_FONT_TILE_SIZE.1 * grid_height;
91 let window_logical_size: LogicalSize = (window_pixel_width, window_pixel_height).into();
92 let events_loop = EventsLoop::new();
93 let window_builder = WindowBuilder::new()
94 .with_dimensions(window_logical_size)
95 .with_min_dimensions(window_logical_size)
96 .with_max_dimensions(window_logical_size)
97 .with_title(title);
98 let context_builder = ContextBuilder::new().with_vsync(true);
99 let display = Display::new(window_builder, context_builder, &events_loop).map_err(|e| DwarfTermGliumError::DisplayCreationError(e))?;
100 display.gl_window().set_position(LogicalPosition::new(500.0, 200.0));
101
102 let program = Program::from_source(&display, VERT_SRC, FRAG_SRC, None).map_err(|e| DwarfTermGliumError::ProgramCreationError(e))?;
104
105 let raw_image = RawImage2d::from_raw_rgba_reversed(&DEMO_FONT, DEMO_FONT_SHEET_SIZE);
107 let sprite_texture = Texture2d::with_format(
108 &display,
109 raw_image,
110 UncompressedFloatFormat::U8U8U8U8,
111 MipmapsOption::AutoGeneratedMipmaps,
112 ).map_err(|e| DwarfTermGliumError::TextureCreationError(e))?;
113
114 Ok(Self {
115 fgs: VecImage::new(grid_width as usize, grid_height as usize),
116 bgs: VecImage::new(grid_width as usize, grid_height as usize),
117 ids: VecImage::new(grid_width as usize, grid_height as usize),
118 events_loop,
119 display,
120 program,
121 clear_color: (1.0, 1.0, 1.0, 1.0),
122 sprite_texture,
123 })
124 }
125
126 pub fn set_all_foregrounds(&mut self, rgba: u32) {
128 self.fgs.set_all(rgba);
129 }
130
131 pub fn set_all_backgrounds(&mut self, rgba: u32) {
133 self.bgs.set_all(rgba);
134 }
135
136 pub fn set_all_ids(&mut self, tile_id: u8) {
138 self.ids.set_all(tile_id);
139 }
140
141 pub fn set_clear_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
147 self.clear_color = (r, g, b, a);
148 }
149
150 pub fn get_foreground_mut(&mut self, position: (usize, usize)) -> Option<&mut u32> {
154 self.fgs.get_mut(position)
155 }
156
157 pub fn get_background_mut(&mut self, position: (usize, usize)) -> Option<&mut u32> {
161 self.bgs.get_mut(position)
162 }
163
164 pub fn get_id_mut(&mut self, position: (usize, usize)) -> Option<&mut u8> {
168 self.ids.get_mut(position)
169 }
170
171 pub fn poll_events<F>(&mut self, mut callback: F)
178 where
179 F: FnMut(Event),
180 {
181 self.events_loop.poll_events(|event| {
182 callback(event);
183 });
184 }
185
186 pub fn layer_slices(&self) -> (ImageSlice<u32>, ImageSlice<u32>, ImageSlice<u8>) {
190 let zero = (0, 0);
191 let fg_extent = (self.fgs.width(), self.fgs.height());
192 let bg_extent = (self.bgs.width(), self.bgs.height());
193 let id_extent = (self.ids.width(), self.ids.height());
194 (
195 self.fgs.slice(zero..fg_extent),
196 self.bgs.slice(zero..bg_extent),
197 self.ids.slice(zero..id_extent),
198 )
199 }
200
201 pub fn layer_slices_mut(&mut self) -> (ImageMutSlice<u32>, ImageMutSlice<u32>, ImageMutSlice<u8>) {
205 let zero = (0, 0);
206 let fg_extent = (self.fgs.width(), self.fgs.height());
207 let bg_extent = (self.bgs.width(), self.bgs.height());
208 let id_extent = (self.ids.width(), self.ids.height());
209 (
210 self.fgs.slice_mut(zero..fg_extent),
211 self.bgs.slice_mut(zero..bg_extent),
212 self.ids.slice_mut(zero..id_extent),
213 )
214 }
215
216 pub fn clear_draw_swap(&mut self) -> Result<(), DwarfTermGliumError> {
221 debug_assert_eq!(self.ids.as_ref().len(), self.ids.width() * self.ids.height());
223 debug_assert_eq!(self.fgs.as_ref().len(), self.fgs.width() * self.fgs.height());
224 debug_assert_eq!(self.bgs.as_ref().len(), self.bgs.width() * self.bgs.height());
225
226 let the_resolution = {
227 let logical_size = self.display.gl_window().window().get_inner_size().unwrap();
228 [logical_size.width, logical_size.height]
229 };
230 let the_grid_count_f32 = [self.ids.width() as f32, self.ids.height() as f32];
231 let the_tile_id_texture = UnsignedTexture2d::new(
232 &self.display,
233 RawImage2d {
234 data: Cow::Borrowed(self.ids.as_ref()),
235 width: self.ids.width() as u32,
236 height: self.ids.height() as u32,
237 format: ClientFormat::U8,
238 },
239 ).map_err(|e| DwarfTermGliumError::TextureCreationError(e))?;
240 let the_tile_foreground_texture = Texture2d::new(
241 &self.display,
242 RawImage2d {
243 data: Cow::Borrowed(self.fgs.as_ref()),
244 width: self.fgs.width() as u32,
245 height: self.fgs.height() as u32,
246 format: ClientFormat::U8U8U8U8,
247 },
248 ).map_err(|e| DwarfTermGliumError::TextureCreationError(e))?;
249 let the_tile_background_texture = Texture2d::new(
250 &self.display,
251 RawImage2d {
252 data: Cow::Borrowed(self.bgs.as_ref()),
253 width: self.bgs.width() as u32,
254 height: self.bgs.height() as u32,
255 format: ClientFormat::U8U8U8U8,
256 },
257 ).map_err(|e| DwarfTermGliumError::TextureCreationError(e))?;
258 let vertex_buffer = VertexBuffer::new(&self.display, &VERTICES).map_err(|e| DwarfTermGliumError::BufferCreationError(e))?;
259 let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
260 let uniforms = uniform!{
261 screen_resolution: the_resolution,
262 tile_size: DEMO_FONT_TILE_SIZE_VEC2,
263 grid_count: the_grid_count_f32,
264 tile_sheet_texture: Sampler::new(&self.sprite_texture)
265 .minify_filter(MinifySamplerFilter::Nearest)
266 .magnify_filter(MagnifySamplerFilter::Nearest),
267 tile_id_texture: Sampler::new(&the_tile_id_texture)
268 .minify_filter(MinifySamplerFilter::Nearest)
269 .magnify_filter(MagnifySamplerFilter::Nearest),
270 tile_foreground_texture: Sampler::new(&the_tile_foreground_texture)
271 .minify_filter(MinifySamplerFilter::Nearest)
272 .magnify_filter(MagnifySamplerFilter::Nearest),
273 tile_background_texture: Sampler::new(&the_tile_background_texture)
274 .minify_filter(MinifySamplerFilter::Nearest)
275 .magnify_filter(MagnifySamplerFilter::Nearest),
276 };
277
278 let mut target = self.display.draw();
279 target.clear_color(self.clear_color.0, self.clear_color.1, self.clear_color.2, self.clear_color.3);
280 match target.draw(&vertex_buffer, &indices, &self.program, &uniforms, &Default::default()) {
286 Ok(()) => target.finish().map_err(|e| DwarfTermGliumError::SwapBuffersError(e)),
287 Err(draw_error) => {
288 target.finish().ok();
289 Err(DwarfTermGliumError::DrawError(draw_error))
290 }
291 }
292 }
293}
294
295static VERT_SRC: &'static str = include_str!("dwarf.vert");
300
301static FRAG_SRC: &'static str = include_str!("dwarf.frag");