Skip to content

Commit

Permalink
Added batch saving
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescarterbell committed Jan 7, 2024
1 parent 5ba7785 commit f5ab3e2
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 30 deletions.
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ aery = "0.5.1"
bevy = {version = "0.12.1", default-features = false}
rstest = "0.18.2"
bimap = "0.6.3"
rand = "0.8.5"

[workspace.lints.clippy]
type_complexity = "allow"
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_tiles_render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ bevy_tiles = {path = "../bevy_tiles"}
[dev-dependencies]
rstest = {workspace = true}
bevy = {workspace = true, default-features = true}
rand = {workspace = true}

[lints]
workspace = true
12 changes: 10 additions & 2 deletions crates/bevy_tiles_render/examples/hello_tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use bevy::{
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
ecs::system::Commands,
math::{Quat, Vec3},
render::camera::OrthographicProjection,
transform::{
components::{GlobalTransform, Transform},
TransformBundle,
Expand Down Expand Up @@ -33,20 +34,27 @@ fn main() {
struct GameLayer;

impl TileMapLabel for GameLayer {
const CHUNK_SIZE: usize = 8;
const CHUNK_SIZE: usize = 32;
}

fn spawn(mut commands: Commands) {
let mut tile_commands = commands.tiles::<GameLayer, 2>();
tile_commands.spawn_map(TileMapRenderingBundle {
tile_size: TileSize(16.0),
grid_size: TileGridSize(18.0),
tile_map_renderer: TileMapRenderer { batch_size: 512 },
..Default::default()
});

tile_commands.spawn_tile_batch(CoordIterator::new([-100, -100], [100, 100]), move |_| ());
tile_commands.spawn_tile_batch(CoordIterator::new([-200, -200], [200, 200]), move |_| ());

commands.spawn(Camera2dBundle {
projection: OrthographicProjection {
scale: 5.0,
far: 1000.0,
near: -1000.0,
..Default::default()
},
..Default::default()
});
}
10 changes: 8 additions & 2 deletions crates/bevy_tiles_render/src/chunk/internal.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use bevy::{
ecs::{component::Component, entity::Entity},
prelude::Deref,
ecs::{component::Component, entity::Entity, system::Resource},
prelude::{Deref, DerefMut},
utils::HashMap,
};
use bevy_tiles::chunks::ChunkCoord;

use crate::bindings::ChunkBuffer;

#[derive(Default, Resource, Deref, DerefMut)]
pub struct SavedChunks(HashMap<Entity, ChunkBuffer>);

#[derive(Component, Deref)]
pub struct BatchSize(pub u32);

Expand Down
38 changes: 38 additions & 0 deletions crates/bevy_tiles_render/src/cleanup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use bevy::ecs::{entity::Entity, query::With, system::ResMut, world::World};

use crate::{
bindings::ChunkBuffer,
chunk::internal::SavedChunks,
maps::internal::{MapInfo, SavedMaps},
};

pub fn save_chunks(mut world: &mut World) {
// Get the map id's we need
let map_ids: Vec<Entity> = world
.query_filtered::<Entity, With<MapInfo>>()
.iter(world)
.collect();

// Get the chunk id's we need
let chunk_ids: Vec<Entity> = world
.query_filtered::<Entity, With<ChunkBuffer>>()
.iter(world)
.collect();

// Remove the map entities and put them into our hashmap
let mut saved_maps = SavedMaps::default();
for map_id in map_ids.into_iter() {
let mut map = world.entity_mut(map_id);
saved_maps.insert(map_id, map.take::<MapInfo>().unwrap());
}

// Remove the chunk entities and put them into our hashmap
let mut saved_chunks = SavedChunks::default();
for chunk_id in chunk_ids.into_iter() {
let mut chunk = world.entity_mut(chunk_id);
saved_chunks.insert(chunk_id, chunk.take::<ChunkBuffer>().unwrap());
}

world.insert_resource(saved_maps);
world.insert_resource(saved_chunks);
}
28 changes: 23 additions & 5 deletions crates/bevy_tiles_render/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bevy::{
ecs::{
entity::Entity,
query::With,
system::{Commands, Query},
system::{Commands, Query, Res, ResMut},
},
log::debug,
render::Extract,
Expand All @@ -16,12 +16,17 @@ use bevy_tiles::{
};

use crate::{
chunk::internal::ChunkUniforms,
maps::{internal::MapInfo, TileGridSize, TileMapRenderer, TileSize},
chunk::internal::{ChunkUniforms, SavedChunks},
maps::{
internal::{MapInfo, SavedMaps},
TileGridSize, TileMapRenderer, TileSize,
},
};

pub fn extract_chunks(
mut commands: Commands,
mut saved_maps: ResMut<SavedMaps>,
mut saved_chunks: ResMut<SavedChunks>,
maps: Extract<
Query<(
Entity,
Expand All @@ -37,6 +42,11 @@ pub fn extract_chunks(
) {
let mut extracted_maps = Vec::with_capacity(maps.iter().len());
for (map_id, map, renderer, transform, tile_size, grid_size) in maps.iter() {
// TODO: Check if it's changed
if let Some(map_info) = saved_maps.remove(&map_id) {
extracted_maps.push((map_id, map_info));
continue;
}
let transform = transform.cloned().unwrap_or_default();
let tile_size = tile_size.cloned().unwrap_or_default();
let grid_size = grid_size.cloned().unwrap_or_default();
Expand All @@ -54,13 +64,22 @@ pub fn extract_chunks(
commands.insert_or_spawn_batch(extracted_maps);

let mut extracted_chunks = Vec::with_capacity(chunks.iter().len());
let mut extracted_saved_chunks = Vec::new();
let mut chunk_edges = Vec::with_capacity(chunks.iter().len());

for (chunk_id, edges, chunk, chunk_coord) in chunks.iter() {
let [map_id] = edges.targets() else {
panic!("Missing map reference on chunk!");
};

chunk_edges.push((chunk_id, *map_id));

// TODO: Check if it's changed
if let Some(chunk_info) = saved_chunks.remove(&chunk_id) {
extracted_saved_chunks.push((chunk_id, chunk_info));
continue;
}

let mut extracted_tile_instances = Vec::with_capacity(chunk.total_size());

for tile in chunk.get_tiles() {
Expand All @@ -71,8 +90,6 @@ pub fn extract_chunks(
}
}

chunk_edges.push((chunk_id, *map_id));

extracted_chunks.push((
chunk_id,
ChunkUniforms {
Expand All @@ -82,6 +99,7 @@ pub fn extract_chunks(
));
}

commands.insert_or_spawn_batch(extracted_saved_chunks);
commands.insert_or_spawn_batch(extracted_chunks);

for (chunk_id, map_id) in chunk_edges.into_iter() {
Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_tiles_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use bevy::{
},
};

use chunk::internal::SavedChunks;
use cleanup::save_chunks;
use extract::extract_chunks;
use maps::internal::SavedMaps;
use prepare::{create_bind_groups, prepare_chunk_batch, prepare_chunks};
use queue::{create_chunk_batches, queue_chunks};

Expand All @@ -20,14 +23,14 @@ use crate::{draw::DrawChunks, pipeline::TilesChunkPipeline};
mod bindings;
mod buffer_helpers;
pub mod chunk;
mod cleanup;
mod draw;
mod extract;
pub mod maps;
mod pipeline;
mod prepare;
mod queue;
pub mod tiles;
mod tiles_render;

const TILES_VERT: Handle<Shader> = Handle::weak_from_u128(163058266501073814892310220797241232500);
const TILES_FRAG: Handle<Shader> = Handle::weak_from_u128(163058266501073814892310220797241232501);
Expand All @@ -37,7 +40,10 @@ pub struct TilesRenderPlugin;
impl Plugin for TilesRenderPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
let render_app = app.get_sub_app_mut(RenderApp).expect("No RenderApp found!");

render_app.add_plugins(Aery);
render_app.init_resource::<SavedMaps>();
render_app.init_resource::<SavedChunks>();

// Respawn chunks that we saved from the last frame
// Copy over tile data
Expand All @@ -60,7 +66,8 @@ impl Plugin for TilesRenderPlugin {
)
.chain()
.in_set(RenderSet::Prepare),
);
)
.add_systems(Render, (save_chunks).in_set(RenderSet::Cleanup));
}

fn finish(&self, app: &mut bevy::prelude::App) {
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_tiles_render/src/maps/internal.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use bevy::{ecs::component::Component, prelude::Deref, transform::components::GlobalTransform};
use bevy::{
ecs::{component::Component, entity::Entity, system::Resource},
prelude::{Deref, DerefMut},
transform::components::GlobalTransform,
utils::HashMap,
};

use super::{TileGridSize, TileMapRenderer, TileSize};

#[derive(Default, Resource, Deref, DerefMut)]
pub struct SavedMaps(HashMap<Entity, MapInfo>);

#[derive(Clone, Component)]
pub struct MapInfo {
pub chunk_size: u32,
Expand Down
24 changes: 12 additions & 12 deletions crates/bevy_tiles_render/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bevy::{
core_pipeline::core_2d::Transparent2d,
ecs::{
entity::Entity,
query::{Or, With},
system::{Commands, Query, Res, ResMut},
},
log::debug,
Expand All @@ -21,6 +22,7 @@ use bevy::{
use bevy_tiles::chunks::InMap;

use crate::{
bindings::ChunkBuffer,
chunk::internal::{BatchSize, ChunkBatch, ChunkUniforms},
draw::DrawChunks,
maps::internal::MapInfo,
Expand All @@ -30,7 +32,7 @@ use crate::{
pub fn create_chunk_batches(
mut commands: Commands,
maps: Query<((Entity, &MapInfo), Relations<InMap>)>,
chunks: Query<(Entity, &ChunkUniforms)>,
chunks: Query<Entity, Or<(With<ChunkUniforms>, With<ChunkBuffer>)>>,
) {
for ((map_id, map_info), edges) in maps.iter() {
let max_batch_size = map_info.tile_map_renderer.batch_size;
Expand All @@ -52,17 +54,15 @@ pub fn create_chunk_batches(
let mut batch_size = 0;
let mut current_batch = ChunkBatch(commands.spawn_empty().id());

edges
.join::<InMap>(&chunks)
.for_each(|(chunk_id, extracted_tiles)| {
if batch_size == max_batch_size {
batches.push((*current_batch, (BatchSize(batch_size), map_info.clone())));
batch_size = 0;
current_batch = ChunkBatch(commands.spawn_empty().id());
}
batched_chunks.push((chunk_id, current_batch.clone()));
batch_size += 1;
});
edges.join::<InMap>(&chunks).for_each(|chunk_id| {
if batch_size == max_batch_size {
batches.push((*current_batch, (BatchSize(batch_size), map_info.clone())));
batch_size = 0;
current_batch = ChunkBatch(commands.spawn_empty().id());
}
batched_chunks.push((chunk_id, current_batch.clone()));
batch_size += 1;
});

if batch_size > 0 {
batches.push((*current_batch, (BatchSize(batch_size), map_info.clone())));
Expand Down
6 changes: 0 additions & 6 deletions crates/bevy_tiles_render/src/tiles_render.rs

This file was deleted.

0 comments on commit f5ab3e2

Please sign in to comment.