veloren/voxygen/src/hud/item_imgs.rs

178 lines
5.9 KiB
Rust
Raw Normal View History

use crate::ui::{Graphic, SampleStrat, Transform, Ui};
2019-10-09 19:28:05 +00:00
use common::{
2021-12-12 19:01:52 +00:00
assets::{self, AssetExt, AssetHandle, DotVoxAsset, ReloadWatcher},
comp::item::item_key::ItemKey,
2020-04-06 02:50:27 +00:00
figure::Segment,
2019-10-09 19:28:05 +00:00
};
use conrod_core::image::Id;
use hashbrown::HashMap;
use image::DynamicImage;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tracing::{error, warn};
2019-10-09 19:28:05 +00:00
use vek::*;
pub fn animate_by_pulse(ids: &[Id], pulse: f32) -> Id {
let animation_frame = (pulse * 3.0) as usize;
ids[animation_frame % ids.len()]
}
2019-10-09 19:28:05 +00:00
#[derive(Serialize, Deserialize)]
enum ImageSpec {
Png(String),
Vox(String),
// (specifier, offset, (axis, 2 * angle / pi), zoom)
VoxTrans(String, [f32; 3], [f32; 3], f32),
}
impl ImageSpec {
fn create_graphic(&self) -> Graphic {
match self {
2021-07-11 18:41:52 +00:00
ImageSpec::Png(specifier) => Graphic::Image(graceful_load_img(specifier), None),
2019-10-09 19:28:05 +00:00
ImageSpec::Vox(specifier) => Graphic::Voxel(
2021-07-11 18:41:52 +00:00
graceful_load_segment_no_skin(specifier),
2019-10-09 19:28:05 +00:00
Transform {
stretch: false,
..Default::default()
},
SampleStrat::None,
2019-10-09 19:28:05 +00:00
),
ImageSpec::VoxTrans(specifier, offset, [rot_x, rot_y, rot_z], zoom) => Graphic::Voxel(
2021-07-11 18:41:52 +00:00
graceful_load_segment_no_skin(specifier),
2019-10-09 19:28:05 +00:00
Transform {
ori: Quaternion::rotation_x(rot_x * std::f32::consts::PI / 180.0)
.rotated_y(rot_y * std::f32::consts::PI / 180.0)
.rotated_z(rot_z * std::f32::consts::PI / 180.0),
2019-10-09 19:28:05 +00:00
offset: Vec3::from(*offset),
zoom: *zoom,
orth: true, // TODO: Is this what we want here? @Pfau
stretch: false,
},
SampleStrat::None,
2019-10-09 19:28:05 +00:00
),
}
}
}
2019-10-09 19:28:05 +00:00
#[derive(Serialize, Deserialize)]
struct ItemImagesSpec(HashMap<ItemKey, ImageSpec>);
2020-12-12 22:14:24 +00:00
impl assets::Asset for ItemImagesSpec {
type Loader = assets::RonLoader;
2020-12-13 01:09:57 +00:00
const EXTENSION: &'static str = "ron";
2019-10-09 19:28:05 +00:00
}
// TODO: when there are more images don't load them all into memory
2019-10-09 19:28:05 +00:00
pub struct ItemImgs {
map: HashMap<ItemKey, Id>,
2020-12-12 22:14:24 +00:00
manifest: AssetHandle<ItemImagesSpec>,
2021-12-12 19:01:52 +00:00
watcher: ReloadWatcher,
not_found: Id,
2019-10-09 19:28:05 +00:00
}
2020-12-12 22:14:24 +00:00
2019-10-09 19:28:05 +00:00
impl ItemImgs {
pub fn new(ui: &mut Ui, not_found: Id) -> Self {
2020-12-13 01:09:57 +00:00
let manifest = ItemImagesSpec::load_expect("voxygen.item_image_manifest");
2020-12-12 22:14:24 +00:00
let map = manifest
.read()
2019-10-09 19:28:05 +00:00
.0
.iter()
// TODO: what if multiple kinds map to the same image, it would be nice to use the same
// image id for both, although this does interfere with the current hot-reloading
// strategy
2019-10-09 19:28:05 +00:00
.map(|(kind, spec)| (kind.clone(), ui.add_graphic(spec.create_graphic())))
2020-12-12 22:14:24 +00:00
.collect();
Self {
map,
manifest,
2021-12-12 19:01:52 +00:00
watcher: manifest.reload_watcher(),
not_found,
2019-10-09 19:28:05 +00:00
}
}
2019-10-09 19:28:05 +00:00
/// Checks if the manifest has been changed and reloads the images if so
/// Reuses img ids
pub fn reload_if_changed(&mut self, ui: &mut Ui) {
2021-12-12 19:01:52 +00:00
if self.watcher.reloaded() {
2020-12-12 22:14:24 +00:00
for (kind, spec) in self.manifest.read().0.iter() {
2019-10-09 19:28:05 +00:00
// Load new graphic
let graphic = spec.create_graphic();
// See if we already have an id we can use
2021-07-11 18:41:52 +00:00
match self.map.get(kind) {
2019-10-09 19:28:05 +00:00
Some(id) => ui.replace_graphic(*id, graphic),
// Otherwise, generate new id and insert it into our Id -> ItemKey map
2019-10-09 19:28:05 +00:00
None => {
self.map.insert(kind.clone(), ui.add_graphic(graphic));
},
2019-10-09 19:28:05 +00:00
}
}
}
}
pub fn img_ids(&self, item_key: ItemKey) -> Vec<Id> {
if let ItemKey::TagExamples(keys) = item_key {
return keys
.iter()
.filter_map(|k| self.map.get(k))
.cloned()
.collect();
};
match self.map.get(&item_key) {
Some(id) => vec![*id],
2019-10-09 19:28:05 +00:00
// There was no specification in the ron
None => {
warn!(
?item_key,
"missing specified image file (note: hot-reloading won't work here)",
2019-10-09 19:28:05 +00:00
);
Vec::new()
},
2019-10-09 19:28:05 +00:00
}
}
pub fn img_ids_or_not_found_img(&self, item_key: ItemKey) -> Vec<Id> {
let mut ids = self.img_ids(item_key);
if ids.is_empty() {
ids.push(self.not_found)
}
ids
}
2019-10-09 19:28:05 +00:00
}
// Copied from figure/load.rs
// TODO: remove code dup?
2020-12-12 22:14:24 +00:00
fn graceful_load_vox(specifier: &str) -> AssetHandle<DotVoxAsset> {
2019-10-09 19:28:05 +00:00
let full_specifier: String = ["voxygen.", specifier].concat();
2020-12-12 22:14:24 +00:00
match DotVoxAsset::load(full_specifier.as_str()) {
2019-10-09 19:28:05 +00:00
Ok(dot_vox) => dot_vox,
Err(_) => {
error!(?full_specifier, "Could not load vox file for item images",);
2020-12-12 22:14:24 +00:00
DotVoxAsset::load_expect("voxygen.voxel.not_found")
},
2019-10-09 19:28:05 +00:00
}
}
fn graceful_load_img(specifier: &str) -> Arc<DynamicImage> {
let full_specifier: String = ["voxygen.", specifier].concat();
2020-12-12 22:14:24 +00:00
let handle = match assets::Image::load(&full_specifier) {
2019-10-09 19:28:05 +00:00
Ok(img) => img,
Err(_) => {
error!(?full_specifier, "Could not load image file for item images");
2020-12-12 22:14:24 +00:00
assets::Image::load_expect("voxygen.element.not_found")
},
2020-12-12 22:14:24 +00:00
};
handle.read().to_image()
2019-10-09 19:28:05 +00:00
}
2020-04-06 02:50:27 +00:00
fn graceful_load_segment_no_skin(specifier: &str) -> Arc<Segment> {
use common::figure::{mat_cell::MatCell, MatSegment};
2020-12-12 22:14:24 +00:00
let mat_seg = MatSegment::from(&graceful_load_vox(specifier).read().0);
2020-04-06 02:50:27 +00:00
let seg = mat_seg
.map(|mat_cell| match mat_cell {
MatCell::None => None,
MatCell::Mat(_) => Some(MatCell::None),
2021-10-26 03:29:16 +00:00
MatCell::Normal(data) => data.is_hollow().then(|| MatCell::None),
2020-04-06 02:50:27 +00:00
})
.to_segment(|_| Default::default());
2020-04-06 02:50:27 +00:00
Arc::new(seg)
}