Skip to content

Commit

Permalink
Tilemap optimizations (Astrabit-ST#132)
Browse files Browse the repository at this point in the history
* Use the layout from the old branch

* Remove support for push constants

* Use bytes_of and from_bytes

* Use vec2 instead of vec3

* Move grid.wgsl

* Don't use an instance buffer for the grid

* Move the tilepicker mostly into graphics

* Fix collision shader

* Remove vertex buffer from grid

* Remove tilemap vertex buffer

* Remove vertex buffer from collision

* Use shared placeholder png

* Update alox-48

* Massively refactor things (still broken)
- Splits viewport into a transform and screen size
- Fundamentally changes how things are drawn
- Ditches Arc everywhere, so now there are practically 0 multithreading primitives
- Breaks things

* Fix event position bug

* Actually render the grid

* Fix viewport translations

* Fix autotile animation

* Fix some grid issues

* Reimplement event preview

* Fix collision

* Fix align bug

* Fix event preview rendering

* Fix some webgl issues
  • Loading branch information
melody-rs authored and MolassesLover committed Jul 23, 2024
1 parent 6678df2 commit b422d47
Show file tree
Hide file tree
Showing 59 changed files with 2,697 additions and 3,264 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

File renamed without changes
389 changes: 150 additions & 239 deletions crates/components/src/map_view.rs

Large diffs are not rendered by default.

178 changes: 28 additions & 150 deletions crates/components/src/tilepicker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,71 +15,24 @@
// You should have received a copy of the GNU General Public License
// along with Luminol. If not, see <http://www.gnu.org/licenses/>.

use fragile::Fragile;
use itertools::Itertools;
use std::sync::Arc;
use std::time::Duration;
use luminol_graphics::Renderable;

pub struct Tilepicker {
pub selected_tiles_left: i16,
pub selected_tiles_top: i16,
pub selected_tiles_right: i16,
pub selected_tiles_bottom: i16,

pub coll_enabled: bool,
pub grid_enabled: bool,
pub view: luminol_graphics::Tilepicker,

drag_origin: Option<egui::Pos2>,

resources: Arc<Resources>,
viewport: Arc<luminol_graphics::viewport::Viewport>,
ani_time: Option<f64>,

/// When true, brush tile ID randomization is enabled.
pub brush_random: bool,
/// Seed for the PRNG used for the brush when brush tile ID randomization is enabled.
brush_seed: [u8; 16],
}

struct Resources {
tiles: luminol_graphics::tiles::Tiles,
collision: luminol_graphics::collision::Collision,
grid: luminol_graphics::grid::Grid,
}

// wgpu types are not Send + Sync on webassembly, so we use fragile to make sure we never access any wgpu resources across thread boundaries
struct Callback {
resources: Fragile<Arc<Resources>>,
graphics_state: Fragile<Arc<luminol_graphics::GraphicsState>>,

coll_enabled: bool,
grid_enabled: bool,
}

impl luminol_egui_wgpu::CallbackTrait for Callback {
fn paint<'a>(
&'a self,
info: egui::PaintCallbackInfo,
render_pass: &mut wgpu::RenderPass<'a>,
_callback_resources: &'a luminol_egui_wgpu::CallbackResources,
) {
let resources = self.resources.get();
let graphics_state = self.graphics_state.get();

resources
.tiles
.draw(graphics_state, &[true], None, render_pass);

if self.coll_enabled {
resources.collision.draw(graphics_state, render_pass);
}

if self.grid_enabled {
resources.grid.draw(graphics_state, &info, render_pass);
}
}
}

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum SelectedTile {
Autotile(i16),
Expand Down Expand Up @@ -120,65 +73,12 @@ impl Tilepicker {
let tilesets = update_state.data.tilesets();
let tileset = &tilesets.data[map.tileset_id];

let atlas = update_state.graphics.atlas_loader.load_atlas(
let view = luminol_graphics::Tilepicker::new(
&update_state.graphics,
update_state.filesystem,
tileset,
update_state.filesystem,
)?;

let tilepicker_data = (47..(384 + 47))
.step_by(48)
.chain(384..(atlas.tileset_height as i16 / 32 * 8 + 384))
.collect_vec();
let tilepicker_data = luminol_data::Table3::new_data(
8,
1 + (atlas.tileset_height / 32) as usize,
1,
tilepicker_data,
);

let viewport = Arc::new(luminol_graphics::viewport::Viewport::new(
&update_state.graphics,
256.,
atlas.tileset_height as f32 + 32.,
));

let tiles = luminol_graphics::tiles::Tiles::new(
&update_state.graphics,
viewport.clone(),
atlas,
&tilepicker_data,
);

let grid = luminol_graphics::grid::Grid::new(
&update_state.graphics,
viewport.clone(),
tilepicker_data.xsize(),
tilepicker_data.ysize(),
);

let mut passages =
luminol_data::Table2::new(tilepicker_data.xsize(), tilepicker_data.ysize());
for x in 0..8 {
passages[(x, 0)] = {
let tile_id = tilepicker_data[(x, 0, 0)].try_into().unwrap_or_default();
if tile_id >= tileset.passages.len() {
0
} else {
tileset.passages[tile_id]
}
};
}
let length =
(passages.len().saturating_sub(8)).min(tileset.passages.len().saturating_sub(384));
passages.as_mut_slice()[8..8 + length]
.copy_from_slice(&tileset.passages.as_slice()[384..384 + length]);
let collision = luminol_graphics::collision::Collision::new(
&update_state.graphics,
viewport.clone(),
&passages,
);

let mut brush_seed = [0u8; 16];
brush_seed[0..8].copy_from_slice(
&update_state
Expand All @@ -192,19 +92,13 @@ impl Tilepicker {
brush_seed[8..16].copy_from_slice(&(map_id as u64).to_le_bytes());

Ok(Self {
resources: Arc::new(Resources {
tiles,
collision,
grid,
}),
viewport,
ani_time: None,
view,

selected_tiles_left: 0,
selected_tiles_top: 0,
selected_tiles_right: 0,
selected_tiles_bottom: 0,
coll_enabled: false,
grid_enabled: true,

drag_origin: None,
brush_seed,
brush_random: false,
Expand Down Expand Up @@ -258,26 +152,8 @@ impl Tilepicker {
) -> egui::Response {
self.brush_random = update_state.toolbar.brush_random != ui.input(|i| i.modifiers.alt);

let time = ui.ctx().input(|i| i.time);
let graphics_state = update_state.graphics.clone();

if let Some(ani_time) = self.ani_time {
if time - ani_time >= 16. / 60. {
self.ani_time = Some(time);
self.resources
.tiles
.autotiles
.inc_ani_index(&graphics_state.render_state);
}
} else {
self.ani_time = Some(time);
}

ui.ctx()
.request_repaint_after(Duration::from_secs_f64(16. / 60.));

let (canvas_rect, response) = ui.allocate_exact_size(
egui::vec2(256., self.resources.tiles.atlas.tileset_height as f32 + 32.),
egui::vec2(256., self.view.atlas.tileset_height as f32 + 32.),
egui::Sense::click_and_drag(),
);

Expand All @@ -287,27 +163,29 @@ impl Tilepicker {
.intersect(scroll_rect.translate(canvas_rect.min.to_vec2()));
let scroll_rect = absolute_scroll_rect.translate(-canvas_rect.min.to_vec2());

self.viewport.set_proj(
&graphics_state.render_state,
glam::Mat4::orthographic_rh(
scroll_rect.left(),
scroll_rect.right(),
scroll_rect.bottom(),
scroll_rect.top(),
-1.,
1.,
),
self.view.grid.display.set_pixels_per_point(
&update_state.graphics.render_state,
ui.ctx().pixels_per_point(),
);

self.view.set_position(
&update_state.graphics.render_state,
glam::vec2(0.0, -scroll_rect.top()),
);
// FIXME: move this into graphics
self.view.viewport.set(
&update_state.graphics.render_state,
glam::vec2(scroll_rect.width(), scroll_rect.height()),
glam::Vec2::ZERO,
glam::Vec2::ONE,
);
self.view
.update_animation(&update_state.graphics.render_state, ui.input(|i| i.time));

let painter = luminol_graphics::Painter::new(self.view.prepare(&update_state.graphics));
ui.painter()
.add(luminol_egui_wgpu::Callback::new_paint_callback(
absolute_scroll_rect,
Callback {
resources: Fragile::new(self.resources.clone()),
graphics_state: Fragile::new(graphics_state.clone()),
coll_enabled: self.coll_enabled,
grid_enabled: self.grid_enabled,
},
painter,
));

let rect = egui::Rect::from_x_y_ranges(
Expand All @@ -333,7 +211,7 @@ impl Tilepicker {
pos
};
let rect = egui::Rect::from_two_pos(drag_origin, pos);
let bottom = self.resources.tiles.atlas.tileset_height as i16 / 32;
let bottom = self.view.atlas.tileset_height as i16 / 32;
self.selected_tiles_left = (rect.left() as i16).clamp(0, 7);
self.selected_tiles_right = (rect.right() as i16).clamp(0, 7);
self.selected_tiles_top = (rect.top() as i16).clamp(0, bottom);
Expand Down
8 changes: 4 additions & 4 deletions crates/data/src/rgss_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ pub struct Color {

impl From<alox_48::Userdata> for Color {
fn from(value: alox_48::Userdata) -> Self {
bytemuck::cast_slice(&value.data)[0]
*bytemuck::from_bytes(&value.data)
}
}

impl From<Color> for alox_48::Userdata {
fn from(value: Color) -> Self {
alox_48::Userdata {
class: "Color".into(),
data: bytemuck::cast_slice(&[value]).to_vec(),
data: bytemuck::bytes_of(&value).to_vec(),
}
}
}
Expand Down Expand Up @@ -67,15 +67,15 @@ pub struct Tone {

impl From<alox_48::Userdata> for Tone {
fn from(value: alox_48::Userdata) -> Self {
bytemuck::cast_slice(&value.data)[0]
*bytemuck::from_bytes(&value.data)
}
}

impl From<Tone> for alox_48::Userdata {
fn from(value: Tone) -> Self {
alox_48::Userdata {
class: "Tone".into(),
data: bytemuck::cast_slice(&[value]).to_vec(),
data: bytemuck::bytes_of(&value).to_vec(),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/graphics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ naga = "0.19.0"

crossbeam.workspace = true
dashmap.workspace = true
parking_lot.workspace = true

color-eyre.workspace = true

Expand All @@ -40,5 +41,6 @@ camino.workspace = true

luminol-data.workspace = true
luminol-filesystem.workspace = true
luminol-macros.workspace = true

fragile.workspace = true
50 changes: 0 additions & 50 deletions crates/graphics/src/collision/collision.wgsl

This file was deleted.

Loading

0 comments on commit b422d47

Please sign in to comment.