1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Uploads data to the GPU which is needed for rendering.
use crate::{
    context::MapContext,
    coords::ViewRegion,
    raster::{
        resource::RasterResources, AvailableRasterLayerData, RasterLayerData,
        RasterLayersDataComponent,
    },
    render::{
        eventually::{Eventually, Eventually::Initialized},
        tile_view_pattern::DEFAULT_TILE_SIZE,
        Renderer,
    },
    style::Style,
    tcs::tiles::Tiles,
};

pub fn upload_system(
    MapContext {
        world,
        style,
        view_state,
        renderer: Renderer { device, queue, .. },
        ..
    }: &mut MapContext,
) {
    let Some(Initialized(raster_resources)) = world
        .resources
        .query_mut::<&mut Eventually<RasterResources>>()
    else {
        return;
    };
    let view_region =
        view_state.create_view_region(view_state.zoom().zoom_level(DEFAULT_TILE_SIZE));

    if let Some(view_region) = &view_region {
        upload_raster_layer(
            raster_resources,
            device,
            queue,
            &world.tiles,
            style,
            view_region,
        );
    }
}

#[tracing::instrument(skip_all)]
fn upload_raster_layer(
    raster_resources: &mut RasterResources,
    device: &wgpu::Device,
    queue: &wgpu::Queue,
    tiles: &Tiles,
    style: &Style,
    view_region: &ViewRegion,
) {
    for coords in view_region.iter() {
        if raster_resources.get_bound_texture(&coords).is_some() {
            continue;
        }

        let Some(raster_layers) = tiles.query::<&RasterLayersDataComponent>(coords) else {
            continue;
        };

        for style_layer in &style.layers {
            let style_source_layer = style_layer.source_layer.as_ref().unwrap(); // FIXME: Remove unwrap

            let Some(AvailableRasterLayerData { coords, image, .. }) = raster_layers
                .layers
                .iter()
                .flat_map(|data| match data {
                    RasterLayerData::Available(data) => Some(data),
                    RasterLayerData::Missing(_) => None,
                })
                .find(|layer| style_source_layer.as_str() == layer.source_layer)
            else {
                continue;
            };

            let (width, height) = image.dimensions();

            let texture = raster_resources.create_texture(
                None,
                device,
                wgpu::TextureFormat::Rgba8UnormSrgb,
                width,
                height,
                wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
            );

            queue.write_texture(
                wgpu::ImageCopyTexture {
                    aspect: wgpu::TextureAspect::All,
                    texture: &texture.texture,
                    mip_level: 0,
                    origin: wgpu::Origin3d::ZERO,
                },
                image,
                wgpu::ImageDataLayout {
                    offset: 0,
                    bytes_per_row: Some(4 * width),
                    rows_per_image: Some(height),
                },
                texture.size,
            );

            raster_resources.bind_texture(device, coords, texture);
        }
    }
}