fyrox_impl/scene/tilemap/
effect.rs1use crate::{
30 core::{
31 algebra::{Matrix4, Vector2, Vector3, Vector4},
32 parking_lot::Mutex,
33 },
34 scene::mesh::vertex::StaticVertex,
35};
36use fxhash::{FxHashMap, FxHashSet};
37use std::{fmt::Debug, sync::Arc};
38
39use super::*;
40
41pub type TileMapEffectRef = Arc<Mutex<dyn TileMapEffect>>;
44
45pub trait TileMapEffect: Send + Debug {
50 fn render_special_tiles(&self, context: &mut TileMapRenderContext);
52}
53
54#[derive(Debug)]
56pub struct TileCursorEffect {
57 pub position: Option<Vector2<i32>>,
59 pub material: Option<MaterialResource>,
61}
62
63impl TileMapEffect for TileCursorEffect {
64 fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
65 if let Some(material) = self.material.as_ref() {
66 if let Some(position) = self.position {
67 push_cursor(position, material, context);
68 }
69 }
70 }
71}
72
73#[derive(Debug)]
75pub struct TileSelectionEffect {
76 pub offset: Option<Vector2<i32>>,
78 pub positions: FxHashSet<Vector2<i32>>,
80 pub thickness: f32,
82 pub material: Option<MaterialResource>,
84}
85
86impl TileMapEffect for TileSelectionEffect {
87 fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
88 if let (Some(material), Some(offset)) = (self.material.as_ref(), self.offset) {
89 for &position in self.positions.iter() {
90 let position = position + offset;
91 push_highlight(position, material, self.thickness, context);
92 }
93 }
94 }
95}
96
97#[derive(Debug)]
99pub struct TileEraseEffect {
100 pub positions: FxHashSet<Vector2<i32>>,
102}
103
104impl TileMapEffect for TileEraseEffect {
105 fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
106 for &position in self.positions.iter() {
107 context.set_tile_visible(position, false);
108 }
109 }
110}
111
112#[derive(Debug)]
115pub struct TileOverlayEffect {
116 pub active: bool,
118 pub offset: Vector2<i32>,
120 pub tiles: FxHashMap<Vector2<i32>, TileDefinitionHandle>,
122}
123
124impl TileMapEffect for TileOverlayEffect {
125 fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
126 if !self.active {
127 return;
128 }
129 for (&position, &handle) in self.tiles.iter() {
130 let position = position + self.offset;
131 if context.is_tile_visible(position) {
132 context.draw_tile(position, handle);
133 context.set_tile_visible(position, false);
134 }
135 }
136 }
137}
138
139#[derive(Debug)]
142pub struct TileUpdateEffect {
143 pub active: bool,
145 pub update: TransTilesUpdate,
147}
148
149impl TileMapEffect for TileUpdateEffect {
150 fn render_special_tiles(&self, context: &mut TileMapRenderContext) {
151 if !self.active {
152 return;
153 }
154 for (&position, value) in self.update.iter() {
155 if context.is_tile_visible(position) {
156 context.set_tile_visible(position, false);
157 if let Some((transform, handle)) = *value {
158 let handle = context
159 .tile_set
160 .get_transformed_version(transform, handle)
161 .unwrap_or(handle);
162 context.draw_tile(position, handle);
163 }
164 }
165 }
166 }
167}
168
169fn make_highlight_vertex(transform: &Matrix4<f32>, position: Vector2<f32>) -> StaticVertex {
170 StaticVertex {
171 position: transform
172 .transform_point(&position.to_homogeneous().into())
173 .coords,
174 tex_coord: Vector2::default(),
175 normal: Vector3::new(0.0, 0.0, 1.0),
176 tangent: Vector4::new(0.0, 1.0, 0.0, 1.0),
177 }
178}
179
180fn push_highlight(
181 position: Vector2<i32>,
182 material: &MaterialResource,
183 thickness: f32,
184 ctx: &mut TileMapRenderContext,
185) {
186 let transform = ctx.transform();
187 let position = position.cast::<f32>();
188 let t = thickness;
189 let vertices = [
190 (0.0, 1.0),
191 (1.0, 1.0),
192 (1.0, 0.0),
193 (0.0, 0.0),
194 (t, 1.0 - t),
195 (1.0 - t, 1.0 - t),
196 (1.0 - t, t),
197 (t, t),
198 ]
199 .map(|(x, y)| Vector2::new(x, y))
200 .map(|p| make_highlight_vertex(transform, position + p));
201
202 let triangles = [
203 [0, 4, 5],
204 [0, 1, 5],
205 [1, 5, 6],
206 [1, 2, 6],
207 [2, 6, 7],
208 [2, 3, 7],
209 [3, 7, 4],
210 [3, 0, 4],
211 ]
212 .map(TriangleDefinition);
213
214 let sort_index = ctx
215 .context
216 .calculate_sorting_index(ctx.position())
217 .saturating_sub(1);
218
219 ctx.context.storage.push_triangles(
220 StaticVertex::layout(),
221 material,
222 RenderPath::Forward,
223 sort_index,
224 ctx.tile_map_handle(),
225 &mut move |mut vertex_buffer, mut triangle_buffer| {
226 let start_vertex_index = vertex_buffer.vertex_count();
227
228 vertex_buffer.push_vertices(&vertices).unwrap();
229
230 triangle_buffer
231 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
232 },
233 );
234}
235
236fn push_cursor(
237 position: Vector2<i32>,
238 material: &MaterialResource,
239 ctx: &mut TileMapRenderContext,
240) {
241 let transform = ctx.transform();
242 let position = position.cast::<f32>();
243 let vertices = [(0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]
244 .map(|(x, y)| Vector2::new(x, y))
245 .map(|p| make_highlight_vertex(transform, position + p));
246
247 let triangles = [[0, 1, 2], [0, 2, 3]].map(TriangleDefinition);
248
249 let sort_index = ctx.context.calculate_sorting_index(ctx.position());
250
251 ctx.context.storage.push_triangles(
252 StaticVertex::layout(),
253 material,
254 RenderPath::Forward,
255 sort_index,
256 ctx.tile_map_handle(),
257 &mut move |mut vertex_buffer, mut triangle_buffer| {
258 let start_vertex_index = vertex_buffer.vertex_count();
259
260 vertex_buffer.push_vertices(&vertices).unwrap();
261
262 triangle_buffer
263 .push_triangles_iter_with_offset(start_vertex_index, triangles.into_iter());
264 },
265 );
266}