average composite on terrain sprites
This commit is contained in:
+2
-30
@@ -315,9 +315,6 @@ fn calculate_path(tilemap: &TileMap, start: IVec3, goal: IVec3) -> Vec<Vec3> {
|
|||||||
open_set.push(neighbor_node);
|
open_set.push(neighbor_node);
|
||||||
in_open_set.insert(neighbor_pos);
|
in_open_set.insert(neighbor_pos);
|
||||||
} else {
|
} else {
|
||||||
// For nodes already in the open set, we need to update their priority
|
|
||||||
// This is tricky with a binary heap - one approach is to add a new entry
|
|
||||||
// The old one will still be there but will be ignored when we check the closed set
|
|
||||||
let neighbor_node = PathNode {
|
let neighbor_node = PathNode {
|
||||||
position: neighbor_pos,
|
position: neighbor_pos,
|
||||||
f_score: f,
|
f_score: f,
|
||||||
@@ -342,8 +339,6 @@ fn octile_distance_3d(a: IVec3, b: IVec3) -> i32 {
|
|||||||
let cost2 = 14; // 2D Diagonal
|
let cost2 = 14; // 2D Diagonal
|
||||||
let cost3 = 17; // 3D Diagonal
|
let cost3 = 17; // 3D Diagonal
|
||||||
|
|
||||||
// The heuristic calculation sorts the dimensions implicitly
|
|
||||||
// It calculates the minimum number of diagonal steps needed
|
|
||||||
let mut diffs = [dx, dy, dz];
|
let mut diffs = [dx, dy, dz];
|
||||||
diffs.sort_unstable(); // Sorts ascending: [dmin, dmid, dmax]
|
diffs.sort_unstable(); // Sorts ascending: [dmin, dmid, dmax]
|
||||||
|
|
||||||
@@ -375,6 +370,8 @@ fn reconstruct_path(came_from: HashMap<IVec3, IVec3>, mut current: IVec3) -> Vec
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
println!("spawning citizens");
|
||||||
|
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
// Spawn a handful of citizens
|
// Spawn a handful of citizens
|
||||||
@@ -387,28 +384,3 @@ pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
commands.spawn(Citizen::new(&asset_server, position));
|
commands.spawn(Citizen::new(&asset_server, position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn check_citizen_positions_for_chunks(
|
|
||||||
// query: Query<&Transform, With<Ambulatory>>,
|
|
||||||
// chunk_map: Res<tilemap::ChunkMap>,
|
|
||||||
// mut event_writer: EventWriter<tilemap::LoadChunkEvent>,
|
|
||||||
// ) {
|
|
||||||
// for transform in query.iter() {
|
|
||||||
// let position = transform.translation;
|
|
||||||
|
|
||||||
// // Convert citizen position to chunk coordinates
|
|
||||||
// let chunk_x =
|
|
||||||
// (position.x / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32;
|
|
||||||
// let chunk_y =
|
|
||||||
// (position.y / (tilemap::CHUNK_SIZE as f32 * constants::TILE_SIZE)).floor() as i32;
|
|
||||||
|
|
||||||
// let chunk_pos = IVec2::new(chunk_x, chunk_y);
|
|
||||||
|
|
||||||
// // // Load chunk if not already loaded
|
|
||||||
// // if !chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
|
||||||
// // event_writer.send(tilemap::LoadChunkEvent {
|
|
||||||
// // chunk_position: chunk_pos,
|
|
||||||
// // });
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
+2
-3
@@ -1,5 +1,4 @@
|
|||||||
pub const PIXEL_RATIO: f32 = 2.0;
|
pub const PIXEL_RATIO: f32 = 2.0;
|
||||||
pub const TILE_PIXELS: f32 = 16.0;
|
pub const TILE_PIXELS: u32 = 16;
|
||||||
pub const TILE_SIZE: f32 = TILE_PIXELS * PIXEL_RATIO;
|
pub const TILE_SIZE: f32 = TILE_PIXELS as f32 * PIXEL_RATIO;
|
||||||
pub const ITILE_SIZE: i32 = TILE_SIZE as i32;
|
pub const ITILE_SIZE: i32 = TILE_SIZE as i32;
|
||||||
pub const UTILE_SIZE: u32 = TILE_SIZE as u32;
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.set(ImagePlugin::default_nearest()),
|
.set(ImagePlugin::default_nearest()),
|
||||||
)
|
)
|
||||||
.insert_resource(ClearColor(Color::srgb(0.0, 0.0, 0.0)))
|
.insert_resource(ClearColor(Color::srgb(0., 0., 0.)))
|
||||||
.add_plugins(tilemap::TilemapPlugin)
|
.add_plugins(tilemap::TilemapPlugin)
|
||||||
.add_plugins(citizen::PathfindingPlugin)
|
.add_plugins(citizen::PathfindingPlugin)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
|||||||
+1
-3
@@ -76,7 +76,6 @@ pub struct TileMap {
|
|||||||
pub fixture_tiles: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
pub fixture_tiles: HashMap<IVec3, (u32, bool, [u32; 8])>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This system updates sprite visibility based on current z-index
|
|
||||||
pub fn update_tile_visibility(
|
pub fn update_tile_visibility(
|
||||||
z_index: Res<game::ZIndex>,
|
z_index: Res<game::ZIndex>,
|
||||||
mut query: Query<(&tiles::TerrainSprite, &mut Visibility)>,
|
mut query: Query<(&tiles::TerrainSprite, &mut Visibility)>,
|
||||||
@@ -85,10 +84,9 @@ pub fn update_tile_visibility(
|
|||||||
|
|
||||||
let current_z = z_index.0 as isize;
|
let current_z = z_index.0 as isize;
|
||||||
|
|
||||||
// Update visibility for all terrain sprites
|
|
||||||
for (terrain_sprite, mut visibility) in query.iter_mut() {
|
for (terrain_sprite, mut visibility) in query.iter_mut() {
|
||||||
*visibility =
|
*visibility =
|
||||||
if terrain_sprite.z_index <= ((current_z + tilemap::Z_BELOW as isize) as usize) {
|
if terrain_sprite.z_index == ((current_z + tilemap::Z_BELOW as isize) as usize) {
|
||||||
Visibility::Visible
|
Visibility::Visible
|
||||||
} else {
|
} else {
|
||||||
Visibility::Hidden
|
Visibility::Hidden
|
||||||
|
|||||||
+7
-5
@@ -46,6 +46,7 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
)>,
|
)>,
|
||||||
mut cwss: ResMut<CurrentWorldSpriteState>,
|
mut cwss: ResMut<CurrentWorldSpriteState>,
|
||||||
) {
|
) {
|
||||||
|
println!("updating tile occlusion");
|
||||||
query_set
|
query_set
|
||||||
.p0()
|
.p0()
|
||||||
.par_iter_mut()
|
.par_iter_mut()
|
||||||
@@ -91,7 +92,8 @@ pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
|||||||
|
|
||||||
let mut is_occluded = false;
|
let mut is_occluded = false;
|
||||||
|
|
||||||
'vertical_check: for z_offset in 1..15 {
|
let v_check_height: i32 = Z_TOTAL as i32 - (camera_z / ITILE_SIZE) + Z_BELOW as i32 + 1;
|
||||||
|
'vertical_check: for z_offset in 1..v_check_height {
|
||||||
let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * ITILE_SIZE));
|
let above_pos = IVec3::new(pos.x, pos.y, pos.z + (z_offset * ITILE_SIZE));
|
||||||
if above_pos.z <= camera_z {
|
if above_pos.z <= camera_z {
|
||||||
if let Some(&(_, opaque, _, _, _)) = tilemap.floor_tiles.get(&above_pos) {
|
if let Some(&(_, opaque, _, _, _)) = tilemap.floor_tiles.get(&above_pos) {
|
||||||
@@ -194,13 +196,13 @@ fn generate_chunks_from_algo(
|
|||||||
);
|
);
|
||||||
let pos_ivec = position.as_ivec3();
|
let pos_ivec = position.as_ivec3();
|
||||||
|
|
||||||
if z < -8 {
|
if z < -5 {
|
||||||
let noise_value = cave_noise.get([
|
let noise_value = cave_noise.get([
|
||||||
world_x as f64 * 0.05,
|
world_x as f64 * 0.05,
|
||||||
world_y as f64 * 0.05,
|
world_y as f64 * 0.05,
|
||||||
z as f64 * 0.05,
|
z as f64 * (0.15 * -z as f64),
|
||||||
]);
|
]);
|
||||||
if noise_value < -0.5 {
|
if noise_value < -0.65 {
|
||||||
FloorTilePrefab::air(position).spawn(&mut commands);
|
FloorTilePrefab::air(position).spawn(&mut commands);
|
||||||
tilemap
|
tilemap
|
||||||
.floor_tiles
|
.floor_tiles
|
||||||
@@ -275,7 +277,7 @@ fn generate_chunks_from_algo(
|
|||||||
|
|
||||||
fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
||||||
println!("setup_initial_chunks");
|
println!("setup_initial_chunks");
|
||||||
for x in -2..=2 {
|
for x in -3..=3 {
|
||||||
for y in -2..=2 {
|
for y in -2..=2 {
|
||||||
event_writer.write(LoadChunkEvent {
|
event_writer.write(LoadChunkEvent {
|
||||||
chunk_position: IVec2::new(x, y),
|
chunk_position: IVec2::new(x, y),
|
||||||
|
|||||||
+80
-73
@@ -74,7 +74,6 @@ pub fn initialize_textures(mut commands: Commands, asset_server: Res<AssetServer
|
|||||||
asset_server.load(BEDROCK_WALL_PATH),
|
asset_server.load(BEDROCK_WALL_PATH),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Insert the textures resource into the world
|
|
||||||
commands.insert_resource(Textures { handles: textures });
|
commands.insert_resource(Textures { handles: textures });
|
||||||
commands.insert_resource(TextureIDs { refs: texture_ids });
|
commands.insert_resource(TextureIDs { refs: texture_ids });
|
||||||
}
|
}
|
||||||
@@ -101,9 +100,7 @@ pub struct TerrainSprite {
|
|||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct QuiltCache {
|
pub struct QuiltCache {
|
||||||
// Tracks the dimensions of the quilted texture for each z-index
|
|
||||||
pub dimensions: HashMap<usize, (u32, u32)>,
|
pub dimensions: HashMap<usize, (u32, u32)>,
|
||||||
// Tracks if any z-index needs to be requilt
|
|
||||||
pub dirty_indices: Vec<usize>,
|
pub dirty_indices: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +113,6 @@ impl Default for QuiltCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This system generates a quilted sprite for each z-index
|
|
||||||
pub fn build_quilted_terrain_sprites(
|
pub fn build_quilted_terrain_sprites(
|
||||||
query: Query<(&FloorTile, &Transform)>,
|
query: Query<(&FloorTile, &Transform)>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -130,19 +126,15 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
if cwss.state != TerrainSpriteState::WaitingForRender {
|
if cwss.state != TerrainSpriteState::WaitingForRender {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
cwss.state = TerrainSpriteState::InProgress;
|
cwss.state = TerrainSpriteState::InProgress;
|
||||||
|
|
||||||
// despawn all existing quilted terrain sprites
|
|
||||||
for entity in query_sprites.iter() {
|
for entity in query_sprites.iter() {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map to collect all visible tiles per z-index
|
|
||||||
let mut tiles_by_z: HashMap<usize, Vec<(Vec2, &FloorTile)>> = HashMap::new();
|
let mut tiles_by_z: HashMap<usize, Vec<(Vec2, &FloorTile)>> = HashMap::new();
|
||||||
|
// Calculate bounds for all visible tiles
|
||||||
// First pass: Collect all visible tiles by z_index and compute bounds
|
|
||||||
for z_index in 0..=tilemap::Z_TOTAL as usize {
|
for z_index in 0..=tilemap::Z_TOTAL as usize {
|
||||||
for (floortile, transform) in query.iter() {
|
for (floortile, transform) in query.iter() {
|
||||||
let is_visible =
|
let is_visible =
|
||||||
@@ -157,75 +149,83 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each z-index, create a quilted texture
|
// For each z-index, create a new quilted texture, baked and composited.
|
||||||
for (z_index, tiles) in tiles_by_z.iter() {
|
for (z_index, tiles) in tiles_by_z.iter() {
|
||||||
if tiles.is_empty() {
|
if tiles.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find bounds for the quilted texture
|
// Snap min/max values to tile grid - accounting for half tile on each edge
|
||||||
let min_x = tiles.iter().map(|(pos, _)| pos.x).reduce(f32::min).unwrap();
|
// We need to extend the boundaries by half a tile in each direction to ensure full coverage
|
||||||
let max_x = tiles.iter().map(|(pos, _)| pos.x).reduce(f32::max).unwrap();
|
// Don't ask, dragons.
|
||||||
let min_y = tiles.iter().map(|(pos, _)| pos.y).reduce(f32::min).unwrap();
|
let min_x_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.x).reduce(f32::min).unwrap()
|
||||||
let max_y = tiles.iter().map(|(pos, _)| pos.y).reduce(f32::max).unwrap();
|
- TILE_SIZE / 2.0)
|
||||||
|
/ TILE_SIZE)
|
||||||
|
.floor()
|
||||||
|
* TILE_SIZE;
|
||||||
|
let min_y_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.y).reduce(f32::min).unwrap()
|
||||||
|
- TILE_SIZE / 2.0)
|
||||||
|
/ TILE_SIZE)
|
||||||
|
.floor()
|
||||||
|
* TILE_SIZE;
|
||||||
|
let max_x_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.x).reduce(f32::max).unwrap()
|
||||||
|
+ TILE_SIZE / 2.0)
|
||||||
|
/ TILE_SIZE)
|
||||||
|
.ceil()
|
||||||
|
* TILE_SIZE;
|
||||||
|
let max_y_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.y).reduce(f32::max).unwrap()
|
||||||
|
+ TILE_SIZE / 2.0)
|
||||||
|
/ TILE_SIZE)
|
||||||
|
.ceil()
|
||||||
|
* TILE_SIZE;
|
||||||
|
|
||||||
// Snap min/max values to tile grid - ensure we're centered on tile centers
|
// Calculate terrain texture dimensions in pixels
|
||||||
// Our tiles are positioned at their centers (not corners)
|
|
||||||
let min_x_aligned = (min_x / TILE_SIZE).floor() * TILE_SIZE;
|
|
||||||
let min_y_aligned = (min_y / TILE_SIZE).floor() * TILE_SIZE;
|
|
||||||
let max_x_aligned = (max_x / TILE_SIZE).ceil() * TILE_SIZE;
|
|
||||||
let max_y_aligned = (max_y / TILE_SIZE).ceil() * TILE_SIZE;
|
|
||||||
|
|
||||||
// Calculate texture dimensions in pixels
|
|
||||||
// We use TILE_PIXELS (16.0) as the base unit for the texture size
|
|
||||||
let width_tiles = ((max_x_aligned - min_x_aligned) / TILE_SIZE) as u32;
|
let width_tiles = ((max_x_aligned - min_x_aligned) / TILE_SIZE) as u32;
|
||||||
let height_tiles = ((max_y_aligned - min_y_aligned) / TILE_SIZE) as u32;
|
let height_tiles = ((max_y_aligned - min_y_aligned) / TILE_SIZE) as u32;
|
||||||
let width_px = width_tiles * TILE_PIXELS as u32;
|
let width_px = width_tiles * TILE_PIXELS;
|
||||||
let height_px = height_tiles * TILE_PIXELS as u32;
|
let height_px = height_tiles * TILE_PIXELS;
|
||||||
|
|
||||||
// Store the dimensions for later use (especially for adjusting the transform)
|
|
||||||
quilt_cache
|
quilt_cache
|
||||||
.dimensions
|
.dimensions
|
||||||
.insert(*z_index, (width_px, height_px));
|
.insert(*z_index, (width_px, height_px));
|
||||||
|
|
||||||
// Create a new texture
|
|
||||||
let mut texture_data = vec![0u8; (width_px * height_px * 4) as usize];
|
let mut texture_data = vec![0u8; (width_px * height_px * 4) as usize];
|
||||||
|
|
||||||
// Draw each tile into the texture
|
|
||||||
for (pos, floortile) in tiles {
|
for (pos, floortile) in tiles {
|
||||||
let id = floortile.id;
|
let texture = textures
|
||||||
let texture_id = texture_ids.refs.get(&id).unwrap();
|
.handles
|
||||||
let texture = textures.handles.get(texture_id).unwrap();
|
.get(texture_ids.refs.get(&floortile.id).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rel_x = pos.x - min_x_aligned;
|
||||||
|
let rel_y = pos.y - min_y_aligned;
|
||||||
|
|
||||||
|
let tile_x = (rel_x / TILE_SIZE).round() as u32;
|
||||||
|
let tile_y = (height_tiles as f32 - 1.0 - (rel_y / TILE_SIZE).round()) as u32;
|
||||||
|
|
||||||
|
let target_x = tile_x * TILE_PIXELS;
|
||||||
|
let target_y = tile_y * TILE_PIXELS;
|
||||||
|
let mut data: Vec<&[u8]> = vec![];
|
||||||
|
|
||||||
// Fetch the source texture data
|
|
||||||
if let Some(source_texture) = images.get(texture) {
|
if let Some(source_texture) = images.get(texture) {
|
||||||
// Calculate position within the quilted texture
|
if let Some(_data) = &source_texture.data {
|
||||||
// We need to be precise with the mapping from world coordinates to texture pixels
|
// replace this one texture push with loop
|
||||||
|
// if the texture contains any transparent or semi-transparent pixels we should also add the tile below it (z-1)
|
||||||
// Calculate tile position relative to the quilted texture origin
|
data.push(_data);
|
||||||
// This gives us the tile index (whole number of tiles from origin)
|
|
||||||
let tile_x = ((pos.x - min_x_aligned) / TILE_SIZE).round() as u32;
|
|
||||||
let tile_y =
|
|
||||||
(height_tiles as f32 - 1.0 - ((pos.y - min_y_aligned) / TILE_SIZE).round())
|
|
||||||
as u32;
|
|
||||||
// Copy the tile texture into the quilted texture
|
|
||||||
// Convert from tile indices to pixel coordinates in the output texture
|
|
||||||
if let Some(data) = &source_texture.data {
|
|
||||||
blit_texture(
|
|
||||||
data,
|
|
||||||
&mut texture_data,
|
|
||||||
source_texture.size().x as u32,
|
|
||||||
source_texture.size().y as u32,
|
|
||||||
width_px,
|
|
||||||
height_px,
|
|
||||||
(tile_x * TILE_PIXELS as u32) + (TILE_PIXELS / 2.0) as u32,
|
|
||||||
(tile_y * TILE_PIXELS as u32) + (TILE_PIXELS / 2.0) as u32,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
blit_texture(
|
||||||
|
data, // tile
|
||||||
|
&mut texture_data, // terrain
|
||||||
|
source_texture.size().x as u32,
|
||||||
|
source_texture.size().y as u32,
|
||||||
|
width_px,
|
||||||
|
height_px,
|
||||||
|
target_x,
|
||||||
|
target_y,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new image asset
|
|
||||||
let quilted_texture = Image::new_fill(
|
let quilted_texture = Image::new_fill(
|
||||||
render_resource::Extent3d {
|
render_resource::Extent3d {
|
||||||
width: width_px,
|
width: width_px,
|
||||||
@@ -237,30 +237,28 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
render_resource::TextureFormat::Rgba8UnormSrgb,
|
render_resource::TextureFormat::Rgba8UnormSrgb,
|
||||||
RenderAssetUsages::RENDER_WORLD,
|
RenderAssetUsages::RENDER_WORLD,
|
||||||
);
|
);
|
||||||
|
|
||||||
let texture_handle = images.add(quilted_texture);
|
let texture_handle = images.add(quilted_texture);
|
||||||
|
|
||||||
// Calculate the center position of the quilted sprite
|
|
||||||
// Using the aligned coordinates to ensure proper centering
|
|
||||||
let center_x = min_x_aligned + (max_x_aligned - min_x_aligned) / 2.0;
|
let center_x = min_x_aligned + (max_x_aligned - min_x_aligned) / 2.0;
|
||||||
let center_y = min_y_aligned + (max_y_aligned - min_y_aligned) / 2.0;
|
let center_y = min_y_aligned + (max_y_aligned - min_y_aligned) / 2.0;
|
||||||
|
|
||||||
// Spawn the quilted sprite
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Sprite {
|
Sprite {
|
||||||
image: texture_handle,
|
image: texture_handle,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Transform::from_xyz(center_x, center_y, (*z_index as f32 - Z_BELOW) * TILE_SIZE)
|
Transform::from_xyz(
|
||||||
.with_scale(Vec3::splat(PIXEL_RATIO)),
|
center_x + TILE_SIZE / 2.0,
|
||||||
|
center_y + TILE_SIZE / 2.0,
|
||||||
|
(*z_index as f32 - Z_BELOW) * TILE_SIZE,
|
||||||
|
)
|
||||||
|
.with_scale(Vec3::splat(PIXEL_RATIO)),
|
||||||
Visibility::Hidden,
|
Visibility::Hidden,
|
||||||
TerrainSprite { z_index: *z_index },
|
TerrainSprite { z_index: *z_index },
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear any dirty flags
|
|
||||||
quilt_cache.dirty_indices.clear();
|
quilt_cache.dirty_indices.clear();
|
||||||
|
|
||||||
cwss.state = TerrainSpriteState::RenderReady;
|
cwss.state = TerrainSpriteState::RenderReady;
|
||||||
println!(
|
println!(
|
||||||
"Quilted world sprites built. Elapsed: {:.2?}",
|
"Quilted world sprites built. Elapsed: {:.2?}",
|
||||||
@@ -270,7 +268,7 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
|
|
||||||
// Helper function to blit a texture onto another texture
|
// Helper function to blit a texture onto another texture
|
||||||
fn blit_texture(
|
fn blit_texture(
|
||||||
source: &[u8],
|
sources: Vec<&[u8]>,
|
||||||
target: &mut [u8],
|
target: &mut [u8],
|
||||||
source_width: u32,
|
source_width: u32,
|
||||||
source_height: u32,
|
source_height: u32,
|
||||||
@@ -283,22 +281,31 @@ fn blit_texture(
|
|||||||
if y + offset_y >= target_height {
|
if y + offset_y >= target_height {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for x in 0..source_width {
|
for x in 0..source_width {
|
||||||
if x + offset_x >= target_width {
|
if x + offset_x >= target_width {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let source_idx = ((y * source_width) + x) as usize * 4;
|
let source_idx = ((y * source_width) + x) as usize * 4;
|
||||||
let target_idx = (((y + offset_y) * target_width) + (x + offset_x)) as usize * 4;
|
let target_idx = (((y + offset_y) * target_width) + (x + offset_x)) as usize * 4;
|
||||||
|
|
||||||
// Only copy non-transparent pixels
|
// New colour
|
||||||
if source.len() > source_idx + 3 && source[source_idx + 3] > 0 {
|
let mut r: u64 = 0;
|
||||||
target[target_idx] = source[source_idx]; // R
|
let mut g: u64 = 0;
|
||||||
target[target_idx + 1] = source[source_idx + 1]; // G
|
let mut b: u64 = 0;
|
||||||
target[target_idx + 2] = source[source_idx + 2]; // B
|
|
||||||
target[target_idx + 3] = source[source_idx + 3]; // A
|
for source in sources.iter() {
|
||||||
|
r += source[source_idx] as u64;
|
||||||
|
g += source[source_idx + 1] as u64;
|
||||||
|
b += source[source_idx + 2] as u64;
|
||||||
}
|
}
|
||||||
|
r /= sources.len() as u64;
|
||||||
|
g /= sources.len() as u64;
|
||||||
|
b /= sources.len() as u64;
|
||||||
|
|
||||||
|
target[target_idx] = r as u8;
|
||||||
|
target[target_idx + 1] = g as u8;
|
||||||
|
target[target_idx + 2] = b as u8;
|
||||||
|
target[target_idx + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user