2022-01-21 15:55:13 -05:00
|
|
|
//! Handle rendering of the viewport
|
2022-02-04 14:09:48 -05:00
|
|
|
use ::bracket_lib::prelude::*;
|
2022-02-02 10:08:11 -05:00
|
|
|
use ::specs::prelude::*;
|
2021-12-17 16:35:30 -05:00
|
|
|
|
2022-01-31 11:25:36 -05:00
|
|
|
use crate::components::{Hidden, Position, Renderable, Target, TileSize};
|
2022-01-04 15:02:50 -05:00
|
|
|
use crate::map::tile_glyph;
|
2022-01-28 11:48:25 -05:00
|
|
|
use crate::{colors, Map};
|
2021-12-17 16:35:30 -05:00
|
|
|
|
2022-01-21 15:55:13 -05:00
|
|
|
/// Whether to render an outline of the current map's boundaries
|
2022-02-04 09:52:09 -05:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
const SHOW_BOUNDARIES: bool = true;
|
|
|
|
|
|
|
|
/// Whether to render an outline of the current map's boundaries
|
|
|
|
#[cfg(not(feature = "debug"))]
|
2021-12-17 16:54:36 -05:00
|
|
|
const SHOW_BOUNDARIES: bool = false;
|
2021-12-17 16:35:30 -05:00
|
|
|
|
2022-01-21 15:55:13 -05:00
|
|
|
/// Get the rectangle representing the current viewport
|
2022-02-04 14:09:48 -05:00
|
|
|
pub fn get_screen_bounds(ecs: &World, _ctx: &mut BTerm) -> (i32, i32, i32, i32) {
|
2021-12-17 16:35:30 -05:00
|
|
|
let player_pos = ecs.fetch::<Point>();
|
2022-01-04 12:12:08 -05:00
|
|
|
// let (x_chars, y_chars) = ctx.get_char_size();
|
|
|
|
let (x_chars, y_chars) = (48, 44);
|
2021-12-17 16:35:30 -05:00
|
|
|
|
|
|
|
let center_x = (x_chars / 2) as i32;
|
|
|
|
let center_y = (y_chars / 2) as i32;
|
|
|
|
|
|
|
|
let min_x = player_pos.x - center_x;
|
|
|
|
let max_x = min_x + x_chars as i32;
|
|
|
|
let min_y = player_pos.y - center_y;
|
|
|
|
let max_y = min_y + y_chars as i32;
|
|
|
|
|
|
|
|
(min_x, max_x, min_y, max_y)
|
|
|
|
}
|
|
|
|
|
2022-01-21 15:55:13 -05:00
|
|
|
/// Render the current viewport
|
2022-02-04 14:09:48 -05:00
|
|
|
pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
|
2022-02-02 10:08:11 -05:00
|
|
|
let mut draw_batch = DrawBatch::new();
|
2021-12-17 16:35:30 -05:00
|
|
|
let map = ecs.fetch::<Map>();
|
|
|
|
let (min_x, max_x, min_y, max_y) = get_screen_bounds(ecs, ctx);
|
|
|
|
|
|
|
|
// Render the Map
|
|
|
|
let map_width = map.width - 1;
|
|
|
|
let map_height = map.height - 1;
|
|
|
|
|
2022-02-02 10:08:11 -05:00
|
|
|
for (y, ty) in (min_y..max_y).enumerate() {
|
|
|
|
for (x, tx) in (min_x..max_x).enumerate() {
|
2021-12-17 16:35:30 -05:00
|
|
|
if tx > 0 && tx < map_width && ty > 0 && ty < map_height {
|
|
|
|
let idx = map.xy_idx(tx, ty);
|
|
|
|
if map.revealed_tiles[idx] {
|
2022-01-04 15:02:50 -05:00
|
|
|
let (glyph, fg, bg) = tile_glyph(idx, &*map);
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(Point::new(x, y), ColorPair::new(fg, bg), glyph);
|
2021-12-17 16:35:30 -05:00
|
|
|
}
|
|
|
|
} else if SHOW_BOUNDARIES {
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(
|
|
|
|
Point::new(x, y),
|
|
|
|
ColorPair::new(colors::GRAY, colors::BLACK),
|
2022-02-04 14:09:48 -05:00
|
|
|
to_cp437('·'),
|
2022-02-02 10:08:11 -05:00
|
|
|
);
|
2021-12-17 16:35:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render entities
|
|
|
|
let positions = ecs.read_storage::<Position>();
|
|
|
|
let renderables = ecs.read_storage::<Renderable>();
|
|
|
|
let hidden = ecs.read_storage::<Hidden>();
|
|
|
|
let map = ecs.fetch::<Map>();
|
2022-01-28 11:48:25 -05:00
|
|
|
let sizes = ecs.read_storage::<TileSize>();
|
|
|
|
let entities = ecs.entities();
|
2022-01-31 11:25:36 -05:00
|
|
|
let targets = ecs.read_storage::<Target>();
|
2021-12-17 16:35:30 -05:00
|
|
|
|
2022-01-28 11:48:25 -05:00
|
|
|
let mut data = (&positions, &renderables, &entities, !&hidden)
|
2021-12-17 16:35:30 -05:00
|
|
|
.join()
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order));
|
2022-01-28 11:48:25 -05:00
|
|
|
for (pos, render, entity, _hidden) in data.iter() {
|
|
|
|
if let Some(size) = sizes.get(*entity) {
|
|
|
|
for cy in 0..size.y {
|
|
|
|
for cx in 0..size.x {
|
|
|
|
let tile_x = cx + pos.x;
|
|
|
|
let tile_y = cy + pos.y;
|
|
|
|
let idx = map.xy_idx(tile_x, tile_y);
|
|
|
|
if map.visible_tiles[idx] {
|
|
|
|
let entity_screen_x = (cx + pos.x) - min_x;
|
|
|
|
let entity_screen_y = (cy + pos.y) - min_y;
|
|
|
|
if entity_screen_x > 0
|
|
|
|
&& entity_screen_x < map_width
|
|
|
|
&& entity_screen_y > 0
|
|
|
|
&& entity_screen_y < map_height
|
|
|
|
{
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(
|
|
|
|
Point::new(entity_screen_x + 1, entity_screen_y + 1),
|
|
|
|
ColorPair::new(render.fg, render.bg),
|
2022-01-28 11:48:25 -05:00
|
|
|
render.glyph,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let idx = map.xy_idx(pos.x, pos.y);
|
|
|
|
if map.visible_tiles[idx] {
|
|
|
|
let entity_screen_x = pos.x - min_x;
|
|
|
|
let entity_screen_y = pos.y - min_y;
|
|
|
|
if entity_screen_x > 0
|
|
|
|
&& entity_screen_x < map_width
|
|
|
|
&& entity_screen_y > 0
|
|
|
|
&& entity_screen_y < map_height
|
|
|
|
{
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(
|
|
|
|
Point::new(entity_screen_x, entity_screen_y),
|
|
|
|
ColorPair::new(render.fg, render.bg),
|
2022-01-28 11:48:25 -05:00
|
|
|
render.glyph,
|
|
|
|
);
|
|
|
|
}
|
2021-12-17 16:35:30 -05:00
|
|
|
}
|
|
|
|
}
|
2022-01-31 11:25:36 -05:00
|
|
|
|
|
|
|
if targets.get(*entity).is_some() {
|
|
|
|
let entity_screen_x = pos.x - min_x;
|
|
|
|
let entity_screen_y = pos.y - min_y;
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(
|
|
|
|
Point::new(entity_screen_x - 1, entity_screen_y),
|
|
|
|
ColorPair::new(colors::RED, colors::YELLOW),
|
2022-02-04 14:09:48 -05:00
|
|
|
to_cp437('['),
|
2022-01-31 11:25:36 -05:00
|
|
|
);
|
2022-02-02 10:08:11 -05:00
|
|
|
draw_batch.set(
|
|
|
|
Point::new(entity_screen_x + 1, entity_screen_y),
|
|
|
|
ColorPair::new(colors::RED, colors::YELLOW),
|
2022-02-04 14:09:48 -05:00
|
|
|
to_cp437(']'),
|
2022-02-02 10:08:11 -05:00
|
|
|
);
|
2022-01-31 11:25:36 -05:00
|
|
|
}
|
2021-12-17 16:35:30 -05:00
|
|
|
}
|
2022-02-02 10:08:11 -05:00
|
|
|
|
|
|
|
draw_batch
|
|
|
|
.submit(0)
|
|
|
|
.expect("Failed to batch draw the camera");
|
2021-12-17 16:35:30 -05:00
|
|
|
}
|
|
|
|
|
2022-02-04 14:09:48 -05:00
|
|
|
pub fn render_debug_map(map: &Map, ctx: &mut BTerm) {
|
2021-12-17 16:54:36 -05:00
|
|
|
let player_pos = Point::new(map.width / 2, map.height / 2);
|
|
|
|
let (x_chars, y_chars) = ctx.get_char_size();
|
|
|
|
|
|
|
|
let center_x = (x_chars / 2) as i32;
|
|
|
|
let center_y = (y_chars / 2) as i32;
|
|
|
|
|
|
|
|
let min_x = player_pos.x - center_x;
|
|
|
|
let max_x = min_x + x_chars as i32;
|
|
|
|
let min_y = player_pos.y - center_y;
|
|
|
|
let max_y = min_y + y_chars as i32;
|
|
|
|
|
|
|
|
let map_width = map.width - 1;
|
|
|
|
let map_height = map.height - 1;
|
|
|
|
|
2022-02-02 10:08:11 -05:00
|
|
|
for (y, ty) in (min_y..max_y).enumerate() {
|
|
|
|
for (x, tx) in (min_x..max_x).enumerate() {
|
2021-12-17 16:54:36 -05:00
|
|
|
if tx > 0 && tx < map_width && ty > 0 && ty < map_height {
|
|
|
|
let idx = map.xy_idx(tx, ty);
|
|
|
|
if map.revealed_tiles[idx] {
|
2022-01-04 15:02:50 -05:00
|
|
|
let (glyph, fg, bg) = tile_glyph(idx, &*map);
|
2021-12-17 16:54:36 -05:00
|
|
|
ctx.set(x, y, fg, bg, glyph);
|
|
|
|
}
|
|
|
|
} else if SHOW_BOUNDARIES {
|
2022-02-04 14:09:48 -05:00
|
|
|
ctx.set(x, y, colors::GRAY, colors::BLACK, to_cp437('·'));
|
2021-12-17 16:54:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|