1use std::iter::FromIterator;
2use vec_map::VecMap;
3
4use nsys::{self, color, geometry, math};
5use nsys::gl::{self, glium, image};
6
7use crate::Tree;
8use crate::interface::{self, view, View};
9
10pub (crate) fn update <V : AsRef <View>> (
11 render : &mut gl::Render,
12 tileset_id : Option <gl::render::resource::DefaultTilesetId>,
13 view_tree : &Tree <V>,
14 draw_crosshair : bool
15) {
16 use gl::render::resource::{draw2d, MAIN_VIEWPORT};
17 use view::component::{Canvas, Kind};
18 log::trace!("update...");
19 let tileset_id = tileset_id.unwrap_or_default();
20 let mut rectangles = vec![];
21 let mut tiles = vec![];
22 let mut rectangles_64x64 = vec![];
23 let mut draw_indices = vec![];
24 let screen_id = view_tree.root_node_id().unwrap();
26 let mut view_ids = view_tree.traverse_pre_order_ids (screen_id).unwrap();
27 let mut style = view::Style::default();
28 let mut draw_pointer = None;
29 view_ids.next().map (|screen_id|{
30 let screen_view = view_tree.get (&screen_id).unwrap().data().as_ref();
31 set_screen_view (render, screen_view);
32 screen_view.appearance.style.as_ref().map (|s| style = s.clone());
35 draw_pointer = screen_view.appearance.pointer.clone();
36 let (fg, bg) = {
37 let fg = color::rgba_u8_to_rgba_f32 (style.fg.raw());
38 let bg = color::rgba_u8_to_rgba_f32 (style.bg.raw());
39 (fg, bg)
40 };
41 let canvas = Canvas::try_ref (&screen_view.component).unwrap();
42 let border_tiles = canvas_border (canvas);
44 if !border_tiles.is_empty() {
45 let border_tiles = border_tiles.into_iter().map (
47 |gl::vertex::Vert2dTile { tile, row, column }|
48 gl::vertex::Vert2dTileColor { tile, row, column, fg, bg }
49 ).collect::<Vec<_>>();
50 let tiles_len = tiles.len() as u32;
51 draw_indices.push (draw2d::DrawIndices {
52 rectangle: None,
53 draw_tiles: None,
54 draw_color_tiles: Some (
55 draw2d::Tiles {
56 vertex_range: tiles_len..tiles_len + border_tiles.len() as u32,
57 origin: (0, 0).into(),
58 tileset_id
59 }
60 )
61 });
62 tiles.extend (border_tiles);
63 }
64 }).unwrap();
65 for id in view_ids {
66 let view = view_tree.get (&id).unwrap().data().as_ref();
67 if view.appearance.pointer.is_some() {
68 draw_pointer = view.appearance.pointer.clone();
69 }
70 match &view.component {
71 view::Component::Canvas (canvas) => {
72 let style = view.appearance.style.as_ref().unwrap_or (&style);
73 let rectangle =
74 if let Some (vertex) = canvas_background (canvas, style) {
75 rectangles.push (vertex);
76 Some (rectangles.len() as u32 - 1)
77 } else {
78 None
79 };
80 let border_tiles = canvas_border (canvas);
81 let (body_tiles, body_rectangles_64x64) = {
82 let mut tiles = vec![];
83 let mut rectangles_64x64 = vec![];
84 for child in view_tree.children (&id).unwrap()
85 .map (|node| node.data().as_ref())
86 {
87 match &child.component {
88 view::Component::Body (body) => {
89 let style = child.appearance.style.as_ref().unwrap_or (style);
90 tiles.extend (canvas_body (canvas, body, style))
91 }
92 view::Component::Image (image) =>
93 rectangles_64x64.push (canvas_rectangle_uv (canvas, image)),
94 _ => {}
95 }
96 }
97 (tiles, rectangles_64x64)
98 };
99 let draw_color_tiles = if !border_tiles.is_empty() ||
100 !body_tiles.is_empty()
101 {
102 let (fg, bg) = {
107 let style = view.appearance.style.clone().unwrap_or_default();
108 ( color::rgba_u8_to_rgba_f32 (style.fg.raw()),
109 color::rgba_u8_to_rgba_f32 (style.bg.raw()) )
110 };
111 let border_tiles = border_tiles.into_iter().map (
112 |gl::vertex::Vert2dTile { tile, row, column }|
113 gl::vertex::Vert2dTileColor { tile, row, column, fg, bg }
114 ).collect::<Vec<_>>();
115 let tiles_len = tiles.len() as u32;
116 let vertex_range = tiles_len..tiles_len +
117 border_tiles.len() as u32 + body_tiles.len() as u32;
118 tiles.extend (border_tiles);
119 tiles.extend (body_tiles);
120 Some (draw2d::Tiles {
121 vertex_range, tileset_id, origin: (0, 0).into()
122 })
123 } else {
124 None
125 };
126 if rectangle.is_some() || draw_color_tiles.is_some() {
127 draw_indices.push (draw2d::DrawIndices {
128 rectangle,
129 draw_color_tiles,
130 draw_tiles: None
131 });
132 }
133 rectangles_64x64.extend (body_rectangles_64x64);
134 }
135 _ => {}
137 }
138 }
139 if draw_pointer.is_some() {
140 let (x, y) = {
141 let pointer = interface::POINTER.read().unwrap();
142 (pointer.position_horizontal, pointer.position_vertical)
143 };
144 render.resource.set_pointer_position (&render.glium_display, [x, y].into())
145 }
146 render.resource.draw2d.draw_pointer = draw_pointer.map (|pointer| pointer.0);
147 render.resource.draw2d.rectangle_2d_vertices =
149 glium::VertexBuffer::dynamic (&render.glium_display, &rectangles).unwrap();
150 render.resource.draw2d.tile_color_2d_vertices =
151 glium::VertexBuffer::dynamic (&render.glium_display, &tiles).unwrap();
152 render.resource.draw2d.rectangle_64x64_vertices =
153 glium::VertexBuffer::dynamic (&render.glium_display, &rectangles_64x64)
154 .unwrap();
155 render.resource.draw2d.viewport_resources_set (MAIN_VIEWPORT,
158 draw2d::ViewportResources {
159 draw_crosshair, draw_indices, .. draw2d::ViewportResources::default()
160 }
161 );
162 log::trace!("...update");
163}
164
165pub (crate) fn set_screen_view (render : &mut gl::Render, view : &View) {
168 use view::component::{canvas, Canvas, Kind};
169 let canvas = Canvas::try_ref (&view.component).unwrap();
170 match canvas.coordinates.dimensions() {
173 view::coordinates::Dimensions::Pixel (pixel) => {
174 let width = pixel.width();
176 let height = pixel.height();
177 render.window_resized ([
178 u32::max (width, 1),
179 u32::max (height, 1)
180 ].into());
181 render.camera2d_move_origin_to_bottom_left();
182 }
183 view::coordinates::Dimensions::Tile (_) => unreachable!()
184 }
185 let mut set_clear_color = |color|
187 render.clear_color = color::rgba_u8_to_rgba_f32 (color);
188 match canvas.clear_color {
189 canvas::ClearColor::Appearance => {
190 if let Some (style) = view.appearance.style.as_ref() {
191 set_clear_color (style.bg.raw());
192 } else {
193 log::debug!("TODO: no appearance clear color");
194 }
195 }
196 canvas::ClearColor::Fixed (Some (color)) => set_clear_color (color.raw()),
197 canvas::ClearColor::Fixed (None) => {
198 log::warn!("TODO: no fixed clear color");
199 }
200 }
201 if let Some (_border) = canvas.border.as_ref() {
203 log::warn!("TODO: screen border");
204 }
205}
206
207pub (crate) fn load_pointer (
208 render : &mut gl::Render,
209 key : gl::render::resource::PointerTextureIndexRepr,
210 bytes : &[u8],
211 offset : math::Vector2 <i16>
212) {
213 let texture = gl::texture::texture2d_with_mipmaps_from_bytes (
214 &render.glium_display,
215 bytes,
216 image::ImageFormat::Png,
217 glium::texture::MipmapsOption::NoMipmap
218 ).unwrap();
219 render.resource.textures_pointer.insert (key as usize, (texture, offset));
220}
221
222pub (crate) fn load_textures (
225 render : &mut gl::Render,
226 textures_16x16 : &[&'static str],
227 textures_64x64 : &[&'static str],
228 textures_anysize : &[&'static str]
229) {
230 if !textures_16x16.is_empty() {
232 let textures = gl::texture::texture2darray_with_mipmaps_from_files (
233 &render.glium_display,
234 textures_16x16,
235 image::ImageFormat::Png,
236 glium::texture::MipmapsOption::NoMipmap
237 ).unwrap();
238 render.resource.set_textures_16x16 (textures);
239 }
240 if !textures_64x64.is_empty() {
241 let textures = gl::texture::texture2darray_with_mipmaps_from_files (
242 &render.glium_display,
243 textures_64x64,
244 image::ImageFormat::Png,
245 glium::texture::MipmapsOption::NoMipmap
246 ).unwrap();
247 render.resource.set_textures_64x64 (textures);
248 }
249 render.resource.textures_anysize = VecMap::from_iter (textures_anysize.iter()
250 .map (|path| {
251 gl::texture::texture2d_with_mipmaps_from_file (
252 &render.glium_display,
253 path,
254 image::ImageFormat::Png,
255 glium::texture::MipmapsOption::NoMipmap
256 ).unwrap()
257 }).enumerate().map (|(i, texture)| (i+1, texture))
258 );
259}
260
261fn canvas_background (
267 canvas : &view::component::Canvas,
268 style : &view::Style
269) -> Option <gl::vertex::Vert2dRectColor> {
270 use view::coordinates;
271 use view::component::canvas;
272 let color = {
273 let color = match canvas.clear_color {
274 canvas::ClearColor::Appearance => style.bg.raw(),
275 canvas::ClearColor::Fixed (Some (color)) => color.raw(),
276 canvas::ClearColor::Fixed (None) => return None
277 };
278 color::rgba_u8_to_rgba_f32 (color)
279 };
280 let (bottom_left, dimensions) = {
281 let body_coordinates = canvas.body_coordinates();
282 if body_coordinates.dimensions().horizontal() == 0 ||
283 body_coordinates.dimensions().vertical() == 0
284 {
285 return None
286 }
287 let aabb = geometry::integer::Aabb2::from (body_coordinates);
288 let aabb_pixel = match canvas.coordinates.kind() {
289 coordinates::Kind::Tile => coordinates::tile_to_pixel_aabb (aabb),
290 coordinates::Kind::Pixel => aabb
291 };
292 ( aabb_pixel.min().numcast().unwrap().0.into_array(),
293 [aabb_pixel.width() as f32, aabb_pixel.height() as f32]
294 )
295 };
296 Some (gl::vertex::Vert2dRectColor { bottom_left, dimensions, color })
297}
298
299fn canvas_border (canvas : &view::component::Canvas)
301 -> Vec <gl::vertex::Vert2dTile>
302{
303 use gl::vertex::Vert2dTile;
304 use view::coordinates;
305 let mut tiles = vec![];
306 if let Some (border) = canvas.border.as_ref() {
307 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile,
308 "TODO: support pixel borders");
309 debug_assert!(border.top <= u8::MAX as u32);
310 debug_assert!(border.left <= u8::MAX as u32);
311 debug_assert!(border.right <= u8::MAX as u32);
312 debug_assert!(border.bottom <= u8::MAX as u32);
313 debug_assert!(border.top_left <= u8::MAX as u32);
314 debug_assert!(border.top_right <= u8::MAX as u32);
315 debug_assert!(border.bottom_left <= u8::MAX as u32);
316 debug_assert!(border.bottom_right <= u8::MAX as u32);
317 let [row, column] = [
318 canvas.coordinates.position_vertical(),
319 canvas.coordinates.position_horizontal()
320 ];
321 let [rows, columns] = [
322 canvas.coordinates.dimensions_vertical() as i32,
323 canvas.coordinates.dimensions_horizontal() as i32
324 ];
325 if rows > 0 && columns > 0 {
326 let (thickness_top, thickness_bottom, thickness_left, thickness_right) = (
327 border.thickness_top as i32,
328 border.thickness_bottom as i32,
329 border.thickness_left as i32,
330 border.thickness_right as i32
331 );
332 let mut push_tile = |row, column, tile|
333 tiles.push (Vert2dTile { row, column, tile: tile as u8 });
334 for r in row..row+thickness_top {
336 for c in column..column+thickness_left {
337 push_tile (r, c, border.top_left);
338 }
339 for c in column+thickness_left..column+columns-thickness_right {
340 push_tile (r, c, border.top);
341 }
342 for c in column+columns-thickness_right..column+columns {
343 push_tile (r, c, border.top_right);
344 }
345 }
346 for r in row+thickness_top..row+rows-thickness_bottom {
348 for c in column..column+thickness_left {
349 push_tile (r, c, border.left);
350 }
351 for c in column+columns-thickness_right..column+columns {
352 push_tile (r, c, border.right);
353 }
354 }
355 for r in row+rows-thickness_bottom..row+rows {
357 for c in column..column+thickness_left {
358 push_tile (r, c, border.bottom_left);
359 }
360 for c in column+thickness_left..column+columns-thickness_right {
361 push_tile (r, c, border.bottom);
362 }
363 for c in column+columns-thickness_right..column+columns {
364 push_tile (r, c, border.bottom_right);
365 }
366 }
367 }
368 }
369 tiles
370}
371
372fn canvas_body (
374 canvas : &view::component::Canvas,
375 body : &view::component::Body,
376 style : &view::Style
377) -> Vec <gl::vertex::Vert2dTileColor> {
378 use gl::vertex::Vert2dTileColor;
379 let (fg, bg) = {
380 let fg = color::rgba_u8_to_rgba_f32 (style.fg.raw());
381 let bg = color::rgba_u8_to_rgba_f32 (style.bg.raw());
382 (fg, bg)
383 };
384 let mut tiles = vec![];
385 let (rc_min, _rc_max) = {
386 let [row, col] = [
387 canvas.coordinates.position_vertical(),
388 canvas.coordinates.position_horizontal()
389 ];
390 let [rows, cols] = [
391 canvas.coordinates.dimensions_vertical() as i32,
392 canvas.coordinates.dimensions_horizontal() as i32
393 ];
394 ( (row, col),
395 (row + rows-1, col + cols-1) )
396 };
397 let (border_thickness_top, border_thickness_left) =
398 canvas.border.as_ref().map (|border|
399 ( border.thickness_top as i32,
400 border.thickness_left as i32 )
401 ).unwrap_or_default();
402 for (i, line) in body.0.lines().enumerate() {
403 let row = rc_min.0 + border_thickness_top + i as i32;
404 for (j, ch) in line.chars().enumerate().skip_while (|(_, c)| *c == '\0') {
405 let column = rc_min.1 + border_thickness_left + j as i32;
406 tiles.push (Vert2dTileColor {
407 row, column, tile: ch as u8, fg, bg
408 });
409 }
410 }
411 tiles
412}
413
414fn canvas_rectangle_uv (
416 canvas : &view::component::Canvas,
417 image : &view::component::Image
418) -> gl::vertex::Vert2dRectUvLayer {
419 use view::coordinates;
420 let (_resource, layer) = match image {
421 view::component::Image::Texture (view::Texture { resource, index }) =>
422 (*resource, *index),
423 _ => unimplemented!()
424 };
425 let (bottom_left, dimensions) = {
426 let body_coordinates = canvas.body_coordinates();
427 let horizontal = body_coordinates.position_horizontal();
428 let vertical = body_coordinates.position_vertical();
429 let width = body_coordinates.dimensions_horizontal();
430 let height = body_coordinates.dimensions_vertical();
431 let ([x, y], [w, h]) = if
432 body_coordinates.kind() == coordinates::Kind::Tile
433 {
434 let [tile_w, tile_h] = *coordinates::TILE_WH;
435 ( coordinates::tile_to_pixel (vertical + height as i32, horizontal),
436 [width * tile_w, height * tile_h]
437 )
438 } else {
439 ([horizontal, vertical], [width, height])
440 };
441 ([x as f32, y as f32], [w as f32, h as f32])
442 };
443 let uv = [0.0, 0.0];
445 gl::vertex::Vert2dRectUvLayer { bottom_left, dimensions, uv, layer }
446}