use crate::{
core::{
algebra::{Matrix4, Vector2, Vector3, Vector4},
parking_lot::Mutex,
},
scene::mesh::vertex::StaticVertex,
};
use fxhash::{FxHashMap, FxHashSet};
use std::{fmt::Debug, sync::Arc};
use super::*;
pub type TileMapEffectRef = Arc<Mutex<dyn TileMapEffect>>;
pub trait TileMapEffect: Send + Debug {
fn render_special_tiles(&self, context: &mut TileMapRenderContext);
}
#[derive(Debug)]
pub struct TileCursorEffect {
pub position: Option<Vector2<i32>>,
pub material: Option<MaterialResource>,
}
impl TileMapEffect for TileCursorEffect {
fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
if let Some(material) = self.material.as_ref() {
if let Some(position) = self.position {
push_cursor(position, material, context);
}
}
}
}
#[derive(Debug)]
pub struct TileSelectionEffect {
pub offset: Option<Vector2<i32>>,
pub positions: FxHashSet<Vector2<i32>>,
pub thickness: f32,
pub material: Option<MaterialResource>,
}
impl TileMapEffect for TileSelectionEffect {
fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
if let (Some(material), Some(offset)) = (self.material.as_ref(), self.offset) {
for &position in self.positions.iter() {
let position = position + offset;
push_highlight(position, material, self.thickness, context);
}
}
}
}
#[derive(Debug)]
pub struct TileEraseEffect {
pub positions: FxHashSet<Vector2<i32>>,
}
impl TileMapEffect for TileEraseEffect {
fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
for &position in self.positions.iter() {
context.set_tile_visible(position, false);
}
}
}
#[derive(Debug)]
pub struct TileOverlayEffect {
pub active: bool,
pub offset: Vector2<i32>,
pub tiles: FxHashMap<Vector2<i32>, TileDefinitionHandle>,
}
impl TileMapEffect for TileOverlayEffect {
fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
if !self.active {
return;
}
for (&position, &handle) in self.tiles.iter() {
let position = position + self.offset;
if context.is_tile_visible(position) {
context.draw_tile(position, handle);
context.set_tile_visible(position, false);
}
}
}
}
#[derive(Debug)]
pub struct TileUpdateEffect {
pub active: bool,
pub update: TransTilesUpdate,
}
impl TileMapEffect for TileUpdateEffect {
fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
if !self.active {
return;
}
for (&position, value) in self.update.iter() {
if context.is_tile_visible(position) {
context.set_tile_visible(position, false);
if let Some((transform, handle)) = value.as_ref().map(|v| v.pair()) {
let handle = context
.tile_set
.get_transformed_version(transform, handle)
.unwrap_or(handle);
context.draw_tile(position, handle);
}
}
}
}
}
fn make_highlight_vertex(transform: &Matrix4<f32>, position: Vector2<f32>) -> StaticVertex {
StaticVertex {
position: transform
.transform_point(&position.to_homogeneous().into())
.coords,
tex_coord: Vector2::default(),
normal: Vector3::new(0.0, 0.0, 1.0),
tangent: Vector4::new(0.0, 1.0, 0.0, 1.0),
}
}
fn push_highlight(
position: Vector2<i32>,
material: &MaterialResource,
thickness: f32,
ctx: &mut TileMapRenderContext,
) {
let transform = ctx.transform();
let position = position.cast::<f32>();
let t = thickness;
let vertices = [
(0.0, 1.0),
(1.0, 1.0),
(1.0, 0.0),
(0.0, 0.0),
(t, 1.0 - t),
(1.0 - t, 1.0 - t),
(1.0 - t, t),
(t, t),
]
.map(|(x, y)| Vector2::new(x, y))
.map(|p| make_highlight_vertex(transform, position + p));
let triangles = [
[0, 4, 5],
[0, 1, 5],
[1, 5, 6],
[1, 2, 6],
[2, 6, 7],
[2, 3, 7],
[3, 7, 4],
[3, 0, 4],
]
.map(TriangleDefinition);
let sort_index = ctx
.context
.calculate_sorting_index(ctx.position())
.saturating_sub(1);
ctx.context.storage.push_triangles(
ctx.context.dynamic_surface_cache,
StaticVertex::layout(),
material,
RenderPath::Forward,
sort_index,
ctx.tile_map_handle(),
&mut move |mut vertex_buffer, mut triangle_buffer| {
let start_vertex_index = vertex_buffer.vertex_count();
vertex_buffer.push_vertices(&vertices).unwrap();
triangle_buffer
.push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
},
);
}
fn push_cursor(
position: Vector2<i32>,
material: &MaterialResource,
ctx: &mut TileMapRenderContext,
) {
let transform = ctx.transform();
let position = position.cast::<f32>();
let vertices = [(0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]
.map(|(x, y)| Vector2::new(x, y))
.map(|p| make_highlight_vertex(transform, position + p));
let triangles = [[0, 1, 2], [0, 2, 3]].map(TriangleDefinition);
let sort_index = ctx.context.calculate_sorting_index(ctx.position());
ctx.context.storage.push_triangles(
ctx.context.dynamic_surface_cache,
StaticVertex::layout(),
material,
RenderPath::Forward,
sort_index,
ctx.tile_map_handle(),
&mut move |mut vertex_buffer, mut triangle_buffer| {
let start_vertex_index = vertex_buffer.vertex_count();
vertex_buffer.push_vertices(&vertices).unwrap();
triangle_buffer
.push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
},
);
}