mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Address many of Imbris's comments on MR 2301.
This commit is contained in:
parent
5aa98d18e3
commit
9c4453508e
@ -34,11 +34,11 @@ struct MinimapColumn {
|
|||||||
/// Coordinate of lowest z-slice
|
/// Coordinate of lowest z-slice
|
||||||
zlo: i32,
|
zlo: i32,
|
||||||
/// Z-slices of colors and filled-ness
|
/// Z-slices of colors and filled-ness
|
||||||
layers: Vec<Grid<(Vec4<u8>, bool)>>,
|
layers: Vec<Grid<(Rgba<u8>, bool)>>,
|
||||||
/// Color and filledness above the highest layer
|
/// Color and filledness above the highest layer
|
||||||
above: (Vec4<u8>, bool),
|
above: (Rgba<u8>, bool),
|
||||||
/// Color and filledness below the lowest layer
|
/// Color and filledness below the lowest layer
|
||||||
below: (Vec4<u8>, bool),
|
below: (Rgba<u8>, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VoxelMinimap {
|
pub struct VoxelMinimap {
|
||||||
@ -53,14 +53,14 @@ pub struct VoxelMinimap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VOXEL_MINIMAP_SIDELENGTH: u32 = 256;
|
const VOXEL_MINIMAP_SIDELENGTH: u32 = 256;
|
||||||
|
|
||||||
impl VoxelMinimap {
|
impl VoxelMinimap {
|
||||||
pub fn new(ui: &mut Ui) -> Self {
|
pub fn new(ui: &mut Ui) -> Self {
|
||||||
let mut composited = RgbaImage::new(VOXEL_MINIMAP_SIDELENGTH, VOXEL_MINIMAP_SIDELENGTH);
|
let composited = RgbaImage::from_pixel(
|
||||||
for x in 0..VOXEL_MINIMAP_SIDELENGTH {
|
VOXEL_MINIMAP_SIDELENGTH,
|
||||||
for y in 0..VOXEL_MINIMAP_SIDELENGTH {
|
VOXEL_MINIMAP_SIDELENGTH,
|
||||||
composited.put_pixel(x, y, image::Rgba([0, 0, 0, 64]));
|
image::Rgba([0, 0, 0, 64]),
|
||||||
}
|
);
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
chunk_minimaps: HashMap::new(),
|
chunk_minimaps: HashMap::new(),
|
||||||
image_id: ui.add_graphic_with_rotations(Graphic::Image(
|
image_id: ui.add_graphic_with_rotations(Graphic::Image(
|
||||||
@ -75,34 +75,30 @@ impl VoxelMinimap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_color(block: &Block) -> Option<Vec4<u8>> {
|
fn block_color(block: &Block) -> Option<Rgba<u8>> {
|
||||||
block
|
block
|
||||||
.get_color()
|
.get_color()
|
||||||
.map(|rgb| Vec4::new(rgb.r, rgb.g, rgb.b, 255))
|
.map(|rgb| Rgba::new(rgb.r, rgb.g, rgb.b, 255))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if matches!(block.kind(), BlockKind::Water) {
|
matches!(block.kind(), BlockKind::Water).then(|| Rgba::new(119, 149, 197, 255))
|
||||||
Some(Vec4::new(119, 149, 197, 255))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Each layer is a slice of the terrain near that z-level
|
/// Each layer is a slice of the terrain near that z-level
|
||||||
fn composite_layer_slice(chunk: &TerrainChunk, layers: &mut Vec<Grid<(Vec4<u8>, bool)>>) {
|
fn composite_layer_slice(chunk: &TerrainChunk, layers: &mut Vec<Grid<(Rgba<u8>, bool)>>) {
|
||||||
for z in chunk.get_min_z()..chunk.get_max_z() {
|
for z in chunk.get_min_z()..chunk.get_max_z() {
|
||||||
let grid = Grid::populate_from(Vec2::new(32, 32), |v| {
|
let grid = Grid::populate_from(Vec2::new(32, 32), |v| {
|
||||||
let mut rgba = Vec4::<f32>::zero();
|
let mut rgba = Rgba::<f32>::zero();
|
||||||
let (weights, zoff) = (&[1, 2, 4, 1, 1, 1][..], -2);
|
let (weights, zoff) = (&[1, 2, 4, 1, 1, 1][..], -2);
|
||||||
for dz in 0..weights.len() {
|
for dz in 0..weights.len() {
|
||||||
let color = chunk
|
let color = chunk
|
||||||
.get(Vec3::new(v.x, v.y, dz as i32 + z + zoff))
|
.get(Vec3::new(v.x, v.y, dz as i32 + z + zoff))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(Self::block_color)
|
.and_then(Self::block_color)
|
||||||
.unwrap_or_else(Vec4::zero);
|
.unwrap_or_else(Rgba::zero);
|
||||||
rgba += color.as_() * weights[dz as usize] as f32;
|
rgba += color.as_() * weights[dz as usize] as f32;
|
||||||
}
|
}
|
||||||
let rgba: Vec4<u8> = (rgba / weights.iter().map(|x| *x as f32).sum::<f32>()).as_();
|
let rgba: Rgba<u8> = (rgba / weights.iter().map(|x| *x as f32).sum::<f32>()).as_();
|
||||||
(rgba, true)
|
(rgba, true)
|
||||||
});
|
});
|
||||||
layers.push(grid);
|
layers.push(grid);
|
||||||
@ -110,7 +106,7 @@ impl VoxelMinimap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Each layer is the overhead as if its z-level were the ceiling
|
/// Each layer is the overhead as if its z-level were the ceiling
|
||||||
fn composite_layer_overhead(chunk: &TerrainChunk, layers: &mut Vec<Grid<(Vec4<u8>, bool)>>) {
|
fn composite_layer_overhead(chunk: &TerrainChunk, layers: &mut Vec<Grid<(Rgba<u8>, bool)>>) {
|
||||||
for z in chunk.get_min_z()..chunk.get_max_z() {
|
for z in chunk.get_min_z()..chunk.get_max_z() {
|
||||||
let grid = Grid::populate_from(Vec2::new(32, 32), |v| {
|
let grid = Grid::populate_from(Vec2::new(32, 32), |v| {
|
||||||
let mut rgba = None;
|
let mut rgba = None;
|
||||||
@ -124,9 +120,6 @@ impl VoxelMinimap {
|
|||||||
.and_then(Self::block_color)
|
.and_then(Self::block_color)
|
||||||
{
|
{
|
||||||
if seen_air > 0 {
|
if seen_air > 0 {
|
||||||
/*rgba = Some(color.map(|j| {
|
|
||||||
(j as u32).saturating_sub(if seen_air > 2 { 4 } else { 0 }) as u8
|
|
||||||
}));*/
|
|
||||||
rgba = Some(color);
|
rgba = Some(color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -147,7 +140,7 @@ impl VoxelMinimap {
|
|||||||
let is_filled = block.map_or(true, |b| {
|
let is_filled = block.map_or(true, |b| {
|
||||||
b.is_filled() && !matches!(b.kind(), BlockKind::Leaves | BlockKind::Wood)
|
b.is_filled() && !matches!(b.kind(), BlockKind::Leaves | BlockKind::Wood)
|
||||||
});
|
});
|
||||||
let rgba = rgba.unwrap_or_else(|| Vec3::zero().with_w(255));
|
let rgba = rgba.unwrap_or_else(|| Rgba::new(0, 0, 0, 255));
|
||||||
(rgba, is_filled)
|
(rgba, is_filled)
|
||||||
});
|
});
|
||||||
layers.push(grid);
|
layers.push(grid);
|
||||||
@ -164,40 +157,42 @@ impl VoxelMinimap {
|
|||||||
|
|
||||||
for (key, chunk) in terrain.iter() {
|
for (key, chunk) in terrain.iter() {
|
||||||
let delta: Vec2<u32> = (key - cpos).map(i32::abs).as_();
|
let delta: Vec2<u32> = (key - cpos).map(i32::abs).as_();
|
||||||
if !self.chunk_minimaps.contains_key(&key)
|
if delta.x < VOXEL_MINIMAP_SIDELENGTH / TerrainChunkSize::RECT_SIZE.x
|
||||||
&& delta.x < VOXEL_MINIMAP_SIDELENGTH / TerrainChunkSize::RECT_SIZE.x
|
|
||||||
&& delta.y < VOXEL_MINIMAP_SIDELENGTH / TerrainChunkSize::RECT_SIZE.y
|
&& delta.y < VOXEL_MINIMAP_SIDELENGTH / TerrainChunkSize::RECT_SIZE.y
|
||||||
|
&& !self.chunk_minimaps.contains_key(&key)
|
||||||
{
|
{
|
||||||
let arc_chunk = Arc::clone(chunk);
|
if let Some((_, column)) = self.keyed_jobs.spawn(Some(&pool), key, || {
|
||||||
if let Some((_, column)) = self.keyed_jobs.spawn(Some(&pool), key, move |_| {
|
let arc_chunk = Arc::clone(chunk);
|
||||||
let mut layers = Vec::new();
|
move |_| {
|
||||||
const MODE_OVERHEAD: bool = true;
|
let mut layers = Vec::new();
|
||||||
if MODE_OVERHEAD {
|
const MODE_OVERHEAD: bool = true;
|
||||||
Self::composite_layer_overhead(&arc_chunk, &mut layers);
|
if MODE_OVERHEAD {
|
||||||
} else {
|
Self::composite_layer_overhead(&arc_chunk, &mut layers);
|
||||||
Self::composite_layer_slice(&arc_chunk, &mut layers);
|
} else {
|
||||||
}
|
Self::composite_layer_slice(&arc_chunk, &mut layers);
|
||||||
let above = arc_chunk
|
}
|
||||||
.get(Vec3::new(0, 0, arc_chunk.get_max_z() + 1))
|
let above = arc_chunk
|
||||||
.ok()
|
.get(Vec3::new(0, 0, arc_chunk.get_max_z() + 1))
|
||||||
.cloned()
|
.ok()
|
||||||
.unwrap_or_else(Block::empty);
|
.copied()
|
||||||
let below = arc_chunk
|
.unwrap_or_else(Block::empty);
|
||||||
.get(Vec3::new(0, 0, arc_chunk.get_min_z() - 1))
|
let below = arc_chunk
|
||||||
.ok()
|
.get(Vec3::new(0, 0, arc_chunk.get_min_z() - 1))
|
||||||
.cloned()
|
.ok()
|
||||||
.unwrap_or_else(Block::empty);
|
.copied()
|
||||||
MinimapColumn {
|
.unwrap_or_else(Block::empty);
|
||||||
zlo: arc_chunk.get_min_z(),
|
MinimapColumn {
|
||||||
layers,
|
zlo: arc_chunk.get_min_z(),
|
||||||
above: (
|
layers,
|
||||||
Self::block_color(&above).unwrap_or_else(Vec4::zero),
|
above: (
|
||||||
above.is_filled(),
|
Self::block_color(&above).unwrap_or_else(Rgba::zero),
|
||||||
),
|
above.is_filled(),
|
||||||
below: (
|
),
|
||||||
Self::block_color(&below).unwrap_or_else(Vec4::zero),
|
below: (
|
||||||
below.is_filled(),
|
Self::block_color(&below).unwrap_or_else(Rgba::zero),
|
||||||
),
|
below.is_filled(),
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
self.chunk_minimaps.insert(key, column);
|
self.chunk_minimaps.insert(key, column);
|
||||||
@ -216,120 +211,127 @@ impl VoxelMinimap {
|
|||||||
|
|
||||||
pub fn maintain(&mut self, client: &Client, ui: &mut Ui) {
|
pub fn maintain(&mut self, client: &Client, ui: &mut Ui) {
|
||||||
let player = client.entity();
|
let player = client.entity();
|
||||||
if let Some(pos) = client.state().ecs().read_storage::<comp::Pos>().get(player) {
|
let pos = if let Some(pos) = client.state().ecs().read_storage::<comp::Pos>().get(player) {
|
||||||
let pos = pos.0;
|
pos.0
|
||||||
let vpos = pos.xy() - VOXEL_MINIMAP_SIDELENGTH as f32 / 2.0;
|
} else {
|
||||||
let cpos: Vec2<i32> = vpos
|
return;
|
||||||
|
};
|
||||||
|
let vpos = pos.xy() - VOXEL_MINIMAP_SIDELENGTH as f32 / 2.0;
|
||||||
|
let cpos: Vec2<i32> = vpos
|
||||||
|
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
||||||
|
.as_();
|
||||||
|
|
||||||
|
let pool = client.state().ecs().read_resource::<SlowJobPool>();
|
||||||
|
let terrain = client.state().terrain();
|
||||||
|
let new_chunks = self.add_chunks_near(&pool, &terrain, cpos);
|
||||||
|
self.remove_unloaded_chunks(&terrain);
|
||||||
|
|
||||||
|
// ceiling_offset is the distance from the player to a block heuristically
|
||||||
|
// detected as the ceiling height (a non-tree solid block above them, or
|
||||||
|
// the sky if no such block exists). This is used for determining which
|
||||||
|
// z-slice of the minimap to show, such that house roofs and caves and
|
||||||
|
// dungeons are all handled uniformly.
|
||||||
|
let ceiling_offset = {
|
||||||
|
let voff = Vec2::new(
|
||||||
|
VOXEL_MINIMAP_SIDELENGTH as f32,
|
||||||
|
VOXEL_MINIMAP_SIDELENGTH as f32,
|
||||||
|
) / 2.0;
|
||||||
|
let coff: Vec2<i32> = voff
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
||||||
.as_();
|
.as_();
|
||||||
|
let cmod: Vec2<i32> = vpos
|
||||||
let pool = client.state().ecs().read_resource::<SlowJobPool>();
|
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).rem_euclid(j))
|
||||||
let terrain = client.state().terrain();
|
.as_();
|
||||||
let new_chunks = self.add_chunks_near(&pool, &terrain, cpos);
|
let column = self.chunk_minimaps.get(&(cpos + coff));
|
||||||
self.remove_unloaded_chunks(&terrain);
|
column
|
||||||
|
.map(
|
||||||
let ceiling_offset = {
|
|MinimapColumn {
|
||||||
let voff = Vec2::new(
|
zlo, layers, above, ..
|
||||||
VOXEL_MINIMAP_SIDELENGTH as f32,
|
}| {
|
||||||
VOXEL_MINIMAP_SIDELENGTH as f32,
|
(0..layers.len() as i32)
|
||||||
) / 2.0;
|
.find(|dz| {
|
||||||
let coff: Vec2<i32> = voff
|
layers
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
.get((pos.z as i32 - zlo + dz) as usize)
|
||||||
.as_();
|
.and_then(|grid| grid.get(cmod))
|
||||||
let cmod: Vec2<i32> = vpos
|
.map_or(false, |(_, b)| *b)
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).rem_euclid(j))
|
})
|
||||||
.as_();
|
.unwrap_or_else(|| {
|
||||||
let column = self.chunk_minimaps.get(&(cpos + coff));
|
if above.1 {
|
||||||
column
|
1
|
||||||
.map(
|
} else {
|
||||||
|MinimapColumn {
|
self.max_chunk_z - pos.z as i32
|
||||||
zlo, layers, above, ..
|
}
|
||||||
}| {
|
})
|
||||||
(0..layers.len() as i32)
|
},
|
||||||
.filter_map(|dz| {
|
)
|
||||||
layers.get((pos.z as i32 - zlo + dz) as usize).and_then(
|
.unwrap_or(0)
|
||||||
|grid| {
|
};
|
||||||
if grid.get(cmod).map_or(false, |(_, b)| *b) {
|
if cpos.distance_squared(self.last_pos.xy()) >= 1
|
||||||
Some(dz)
|
|| self.last_pos.z != pos.z as i32
|
||||||
} else {
|
|| self.last_ceiling != ceiling_offset
|
||||||
None
|
|| new_chunks
|
||||||
}
|
{
|
||||||
},
|
self.last_pos = cpos.with_z(pos.z as i32);
|
||||||
|
self.last_ceiling = ceiling_offset;
|
||||||
|
for y in 0..VOXEL_MINIMAP_SIDELENGTH {
|
||||||
|
for x in 0..VOXEL_MINIMAP_SIDELENGTH {
|
||||||
|
let voff = Vec2::new(x as f32, y as f32);
|
||||||
|
let coff: Vec2<i32> = voff
|
||||||
|
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
||||||
|
.as_();
|
||||||
|
let cmod: Vec2<i32> = voff
|
||||||
|
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).rem_euclid(j))
|
||||||
|
.as_();
|
||||||
|
let column = self.chunk_minimaps.get(&(cpos + coff));
|
||||||
|
let color: Rgba<u8> = column
|
||||||
|
.and_then(|column| {
|
||||||
|
let MinimapColumn {
|
||||||
|
zlo,
|
||||||
|
layers,
|
||||||
|
above,
|
||||||
|
below,
|
||||||
|
} = column;
|
||||||
|
if pos.z as i32 + ceiling_offset < *zlo {
|
||||||
|
// If the ceiling is below the bottom of a chunk, color it black,
|
||||||
|
// so that the middles of caves/dungeons don't show the forests
|
||||||
|
// around them.
|
||||||
|
Some(Rgba::new(0, 0, 0, 255))
|
||||||
|
} else {
|
||||||
|
// Otherwise, take the pixel from the precomputed z-level view at
|
||||||
|
// the ceiling's height (using the top slice of the chunk if the
|
||||||
|
// ceiling is above the chunk, (e.g. so that forests with
|
||||||
|
// differently-tall trees are handled properly)
|
||||||
|
layers
|
||||||
|
.get(
|
||||||
|
((pos.z as i32 - zlo + ceiling_offset) as usize)
|
||||||
|
.min(layers.len().saturating_sub(1)),
|
||||||
)
|
)
|
||||||
})
|
.and_then(|grid| grid.get(cmod).map(|c| c.0.as_()))
|
||||||
.next()
|
.or_else(|| {
|
||||||
.unwrap_or_else(|| {
|
Some(if pos.z as i32 > *zlo {
|
||||||
if above.1 {
|
above.0
|
||||||
1
|
} else {
|
||||||
} else {
|
below.0
|
||||||
self.max_chunk_z - pos.z as i32
|
})
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
},
|
})
|
||||||
)
|
.unwrap_or_else(Rgba::zero);
|
||||||
.unwrap_or(0)
|
self.composited.put_pixel(
|
||||||
};
|
x,
|
||||||
if cpos.distance_squared(self.last_pos.xy()) >= 1
|
VOXEL_MINIMAP_SIDELENGTH - y - 1,
|
||||||
|| self.last_pos.z != pos.z as i32
|
image::Rgba([color.r, color.g, color.b, color.a]),
|
||||||
|| self.last_ceiling != ceiling_offset
|
);
|
||||||
|| new_chunks
|
|
||||||
{
|
|
||||||
self.last_pos = cpos.with_z(pos.z as i32);
|
|
||||||
self.last_ceiling = ceiling_offset;
|
|
||||||
for y in 0..VOXEL_MINIMAP_SIDELENGTH {
|
|
||||||
for x in 0..VOXEL_MINIMAP_SIDELENGTH {
|
|
||||||
let voff = Vec2::new(x as f32, y as f32);
|
|
||||||
let coff: Vec2<i32> = voff
|
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).div_euclid(j))
|
|
||||||
.as_();
|
|
||||||
let cmod: Vec2<i32> = voff
|
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |i, j| (i as u32).rem_euclid(j))
|
|
||||||
.as_();
|
|
||||||
let column = self.chunk_minimaps.get(&(cpos + coff));
|
|
||||||
let color: Vec4<u8> = column
|
|
||||||
.and_then(
|
|
||||||
|MinimapColumn {
|
|
||||||
zlo,
|
|
||||||
layers,
|
|
||||||
above,
|
|
||||||
below,
|
|
||||||
}| {
|
|
||||||
if pos.z as i32 + ceiling_offset < *zlo {
|
|
||||||
Some(Vec3::zero().with_w(255))
|
|
||||||
} else {
|
|
||||||
layers
|
|
||||||
.get(
|
|
||||||
((pos.z as i32 - zlo + ceiling_offset) as usize)
|
|
||||||
.min(layers.len().saturating_sub(1)),
|
|
||||||
)
|
|
||||||
.and_then(|grid| grid.get(cmod).map(|c| c.0.as_()))
|
|
||||||
.or_else(|| {
|
|
||||||
Some(if pos.z as i32 > *zlo {
|
|
||||||
above.0
|
|
||||||
} else {
|
|
||||||
below.0
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap_or_else(Vec4::zero);
|
|
||||||
self.composited.put_pixel(
|
|
||||||
x,
|
|
||||||
VOXEL_MINIMAP_SIDELENGTH - y - 1,
|
|
||||||
image::Rgba([color.x, color.y, color.z, color.w]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.replace_graphic(
|
|
||||||
self.image_id.none,
|
|
||||||
Graphic::Image(
|
|
||||||
Arc::new(DynamicImage::ImageRgba8(self.composited.clone())),
|
|
||||||
Some(Rgba::from([0.0, 0.0, 0.0, 0.0])),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.replace_graphic(
|
||||||
|
self.image_id.none,
|
||||||
|
Graphic::Image(
|
||||||
|
Arc::new(DynamicImage::ImageRgba8(self.composited.clone())),
|
||||||
|
Some(Rgba::from([0.0, 0.0, 0.0, 0.0])),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,27 +402,30 @@ fn draw_graphic(
|
|||||||
pool: Option<&SlowJobPool>,
|
pool: Option<&SlowJobPool>,
|
||||||
) -> Option<(RgbaImage, Option<Rgba<f32>>)> {
|
) -> Option<(RgbaImage, Option<Rgba<f32>>)> {
|
||||||
match graphic_map.get(&graphic_id) {
|
match graphic_map.get(&graphic_id) {
|
||||||
|
// Short-circuit spawning a threadpool for blank graphics
|
||||||
Some(Graphic::Blank) => None,
|
Some(Graphic::Blank) => None,
|
||||||
Some(inner) => {
|
Some(inner) => {
|
||||||
let inner = inner.clone();
|
|
||||||
keyed_jobs
|
keyed_jobs
|
||||||
.spawn(pool, (graphic_id, dims), move |_| {
|
.spawn(pool, (graphic_id, dims), || {
|
||||||
match inner {
|
let inner = inner.clone();
|
||||||
// Render image at requested resolution
|
move |_| {
|
||||||
// TODO: Use source aabr.
|
match inner {
|
||||||
Graphic::Image(ref image, border_color) => Some((
|
// Render image at requested resolution
|
||||||
resize_pixel_art(
|
// TODO: Use source aabr.
|
||||||
&image.to_rgba8(),
|
Graphic::Image(ref image, border_color) => Some((
|
||||||
u32::from(dims.x),
|
resize_pixel_art(
|
||||||
u32::from(dims.y),
|
&image.to_rgba8(),
|
||||||
),
|
u32::from(dims.x),
|
||||||
border_color,
|
u32::from(dims.y),
|
||||||
)),
|
),
|
||||||
Graphic::Voxel(ref segment, trans, sample_strat) => Some((
|
border_color,
|
||||||
renderer::draw_vox(&segment, dims, trans, sample_strat),
|
)),
|
||||||
None,
|
Graphic::Voxel(ref segment, trans, sample_strat) => Some((
|
||||||
)),
|
renderer::draw_vox(&segment, dims, trans, sample_strat),
|
||||||
_ => None,
|
None,
|
||||||
|
)),
|
||||||
|
Graphic::Blank => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|(_, v)| v)
|
.and_then(|(_, v)| v)
|
||||||
|
@ -1077,11 +1077,14 @@ impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> Key
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(
|
/// Spawn a task on a specified threadpool. The function is given as a thunk
|
||||||
|
/// so that if work is needed to create captured variables (e.g.
|
||||||
|
/// `Arc::clone`), that only occurs if the task hasn't yet been scheduled.
|
||||||
|
pub fn spawn<F: FnOnce(&K) -> V + Send + Sync + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
pool: Option<&SlowJobPool>,
|
pool: Option<&SlowJobPool>,
|
||||||
k: K,
|
k: K,
|
||||||
f: impl FnOnce(&K) -> V + Send + Sync + 'static,
|
f: impl FnOnce() -> F,
|
||||||
) -> Option<(K, V)> {
|
) -> Option<(K, V)> {
|
||||||
if let Some(pool) = pool {
|
if let Some(pool) = pool {
|
||||||
while let Ok((k2, v)) = self.rx.try_recv() {
|
while let Ok((k2, v)) = self.rx.try_recv() {
|
||||||
@ -1106,6 +1109,7 @@ impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> Key
|
|||||||
},
|
},
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
let tx = self.tx.clone();
|
let tx = self.tx.clone();
|
||||||
|
let f = f();
|
||||||
pool.spawn("IMAGE_PROCESSING", move || {
|
pool.spawn("IMAGE_PROCESSING", move || {
|
||||||
let v = f(&k);
|
let v = f(&k);
|
||||||
let _ = tx.send((k, v));
|
let _ = tx.send((k, v));
|
||||||
@ -1115,7 +1119,7 @@ impl<K: Hash + Eq + Send + Sync + 'static + Clone, V: Send + Sync + 'static> Key
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let v = f(&k);
|
let v = f()(&k);
|
||||||
Some((k, v))
|
Some((k, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user