use crate::{
buffer::{GpuBuffer, GpuDeviceExt},
Camera,
};
use twmap::{Group, Layer};
use vek::Vec2;
use wgpu::{BufferUsages, Device, Queue};
use super::{GpuEnvelopesData, GpuQuadsData, GpuTilemapData, TilemapCorner};
const LABEL: Option<&str> = Some("Group");
pub type GroupInfoBuffer = GpuBuffer<GroupInfo>;
#[derive(Debug, Copy, Clone, bytemuck::Zeroable, bytemuck::Pod)]
#[repr(C)]
pub struct GroupInfo {
offset: Vec2<f32>,
parallax: Vec2<f32>,
}
pub enum GpuLayerData {
Tilemap(GpuTilemapData),
Quads(GpuQuadsData),
}
pub struct GpuGroupData {
pub info_buffer: GroupInfoBuffer,
pub info: GroupInfo,
pub layers: Vec<GpuLayerData>,
}
impl GpuGroupData {
pub fn upload(
group: &Group,
envelopes: &GpuEnvelopesData,
images: &[twmap::Image],
device: &Device,
queue: &Queue,
) -> Self {
let info = GroupInfo {
offset: group.offset.az(),
parallax: group.parallax.az::<f32>() / 100.,
};
let info_buffer = device.buffer(&info, LABEL, BufferUsages::UNIFORM);
let mut layers = Vec::new();
for layer in &group.layers {
if let Some(gpu_layer) = match layer {
Layer::Tiles(layer) => Some(GpuLayerData::Tilemap(GpuTilemapData::upload(
layer, images, device, queue,
))),
Layer::Quads(layer) => Some(GpuLayerData::Quads(GpuQuadsData::upload(
layer, envelopes, device,
))),
_ => None,
} {
layers.push(gpu_layer);
}
}
Self {
info,
info_buffer,
layers,
}
}
pub fn update(
&self,
vertices: &[Option<GpuBuffer<[TilemapCorner; 4]>>],
camera: &Camera,
render_target_size: Vec2<u32>,
envelopes: &[twmap::Envelope],
client_time: i64,
server_time: i64,
queue: &Queue,
) {
let tiles_on_screen = camera.world_perspective_size(self.info.parallax);
let mut projection = camera.world_perspective(self.info.parallax);
projection.min += self.info.offset;
projection.max += self.info.offset;
for (layer, vertices) in self.layers.iter().zip(vertices.iter()) {
if let GpuLayerData::Tilemap(tilemap) = layer {
tilemap.update(
vertices.as_ref().unwrap(),
&projection,
tiles_on_screen,
render_target_size,
envelopes,
client_time,
server_time,
queue,
);
}
}
}
}