use std::sync::Arc;
use serde::{Deserialize, Serialize};
use crate::layers::composite_layer::{base_draw_composite_layer, base_draw_composite_layer_svg};
use crate::two::svg::SvgContext;
use crate::render_traits::{
ColorMode, DrawToRasterCpu, DrawToRasterGpu, DrawToSvg, PickableLayer, PreparedAndDraw, PreparedLayer, UnitsMode, ViewParams
};
use crate::layers::rect_layer::{RectLayer, RectLayerParams};
use crate::layers::multiscale_utils::{
self, ResolutionLevel, get_visible_tiles, select_resolution_level,
};
use crate::render_types::{CpuContext, CpuRenderPass, PrepareResult, RenderResult};
use crate::render_types::GpuContext;
use crate::wgpu;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MultiscaleLayerParams {
pub layer_id: String,
pub resolution_levels: Vec<ResolutionLevel>,
}
pub struct MultiscaleLayer {
view_params: ViewParams,
layer_params: MultiscaleLayerParams,
sub_layer_instances: Vec<Box<dyn PreparedAndDraw>>,
}
impl MultiscaleLayer {
pub fn new(view_params: ViewParams, layer_params: MultiscaleLayerParams) -> Self {
assert!(
!layer_params.resolution_levels.is_empty(),
"MultiscaleLayer requires at least one resolution level"
);
Self {
view_params,
layer_params,
sub_layer_instances: Vec::new(),
}
}
fn build_sublayers(&self) -> Vec<Box<dyn PreparedAndDraw>> {
let levels = &self.layer_params.resolution_levels;
let level_idx = select_resolution_level(&self.view_params, levels);
let level = &levels[level_idx];
let tiles = get_visible_tiles(&self.view_params, level);
let mut sublayers: Vec<Box<dyn PreparedAndDraw>> = Vec::new();
let mut x0_vec: Vec<f32> = Vec::new();
let mut y0_vec: Vec<f32> = Vec::new();
let mut x1_vec: Vec<f32> = Vec::new();
let mut y1_vec: Vec<f32> = Vec::new();
let mut labels_vec: Vec<i32> = Vec::new();
for tile in &tiles {
let tile_pixels_w = (tile.tile_x_end - tile.tile_x_start) as f64;
let tile_pixels_h = (tile.tile_y_end - tile.tile_y_start) as f64;
let phys_x1 = tile.phys_x0 + tile_pixels_w * level.scale[1];
let phys_y1 = tile.phys_y0 + tile_pixels_h * level.scale[0];
x0_vec.push(tile.phys_x0 as f32);
y0_vec.push(tile.phys_y0 as f32);
x1_vec.push(phys_x1 as f32);
y1_vec.push(phys_y1 as f32);
labels_vec.push(((tile.row + tile.col + level_idx as i32) % 2) as i32);
}
if !x0_vec.is_empty() {
let rect_params = RectLayerParams {
layer_id: format!(
"{}_tiles_level{}",
self.layer_params.layer_id, level_idx
),
bounds: self.view_params.margins.clone(),
data_unit_mode_x: UnitsMode::Data,
data_unit_mode_y: UnitsMode::Data,
stroke_width: Some(1.0),
stroke_width_unit_mode: UnitsMode::Pixels,
fill_color: None,
fill_color_mode: ColorMode::Categorical,
position_x0: Arc::new(x0_vec),
position_y0: Arc::new(y0_vec),
position_x1: Arc::new(x1_vec),
position_y1: Arc::new(y1_vec),
labels_vec: Arc::new(labels_vec),
};
sublayers.push(Box::new(RectLayer::new(
self.view_params.clone(),
rect_params,
)));
}
sublayers
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl PreparedLayer for MultiscaleLayer {
async fn prepare(&mut self, gpu_context: Option<&GpuContext<'_>>) -> PrepareResult {
self.sub_layer_instances = self.build_sublayers();
for sub_layer in self.sub_layer_instances.iter_mut() {
sub_layer.prepare(gpu_context).await;
}
PrepareResult {
bailed_early: false,
}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToRasterGpu for MultiscaleLayer {
async fn draw(&self, gpu_context: &GpuContext<'_>, pass: &mut wgpu::RenderPass) {
base_draw_composite_layer(&self.sub_layer_instances, gpu_context, pass).await;
}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToRasterCpu for MultiscaleLayer {
async fn draw(&self, _cpu_context: &CpuContext<'_>, _pass: &mut CpuRenderPass) {}
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl DrawToSvg for MultiscaleLayer {
async fn draw(&self, ctx: &mut SvgContext) {
base_draw_composite_layer_svg(&self.sub_layer_instances, ctx).await
}
}
inventory::submit! {
crate::registry::LayerRegistration {
layer_type_name: "MultiscaleLayer",
create_layer: |value, view_params| {
let params: MultiscaleLayerParams = serde_json::from_value(value).unwrap();
Box::new(MultiscaleLayer::new(view_params.clone(), params))
},
}
}
impl PickableLayer for MultiscaleLayer {}