revamp asset system with a global singleton cache

Former-commit-id: edfc83397ed897fcec37589261c2cfae42d6ec32
This commit is contained in:
Imbris 2019-04-25 23:30:46 -04:00
parent b83d45c464
commit 1d5020634d
14 changed files with 397 additions and 321 deletions

2
Cargo.lock generated
View File

@ -2285,6 +2285,8 @@ version = "0.2.0"
dependencies = [
"bincode 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -10,6 +10,7 @@ sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"]
specs = { version = "0.14", features = ["serde", "nightly"] }
vek = { version = "0.9", features = ["serde"] }
dot_vox = "4.0"
image = "0.21"
threadpool = "1.7"
mio = "0.6"
mio-extras = "2.0"
@ -19,3 +20,4 @@ bincode = "1.0"
log = "0.4"
rand = "0.5"
rayon = "1.0"
lazy_static = "1.3"

146
common/src/assets/mod.rs Normal file
View File

@ -0,0 +1,146 @@
use dot_vox::DotVoxData;
use image::DynamicImage;
use lazy_static::lazy_static;
use std::{
any::Any,
collections::HashMap,
fs::File,
io::Read,
sync::{Arc, PoisonError, RwLock},
};
use crate::figure::Segment;
#[derive(Debug, Clone)]
pub enum Error {
InvalidType,
NotFound,
Poison,
}
impl From<Arc<dyn Any + 'static + Sync + Send>> for Error {
fn from(_err: Arc<dyn Any + 'static + Sync + Send>) -> Self {
Error::InvalidType
}
}
impl From<std::io::Error> for Error {
fn from(_err: std::io::Error) -> Self {
Error::NotFound
}
}
impl<T> From<PoisonError<T>> for Error {
fn from(_err: PoisonError<T>) -> Self {
Error::Poison
}
}
lazy_static! {
static ref ASSETS: RwLock<HashMap<String, Arc<dyn Any + 'static + Sync + Send>>> =
RwLock::new(HashMap::new());
}
/// Function used to load assets
/// Example usage:
/// ```
/// use image::DynamicImage;
///
/// let my_image = common::asset::load::<DynamicImage>("core.ui.backgrounds.city").unwrap();
/// ```
// TODO: consider assets that we only need in one place or that don't need to be kept in memory?
pub fn load<A: Asset + 'static>(specifier: &str) -> Result<Arc<A>, Error> {
Ok(ASSETS
.write()?
.entry(specifier.to_string())
.or_insert(Arc::new(A::load(specifier)?))
.clone()
.downcast()?)
}
/// Asset Trait
pub trait Asset: Send + Sync + Sized {
fn load(specifier: &str) -> Result<Self, Error>;
}
impl Asset for DynamicImage {
fn load(specifier: &str) -> Result<Self, Error> {
Ok(image::load_from_memory(load_from_path(specifier)?.as_slice()).unwrap())
}
}
impl Asset for DotVoxData {
fn load(specifier: &str) -> Result<Self, Error> {
Ok(dot_vox::load_bytes(load_from_path(specifier)?.as_slice()).unwrap())
}
}
impl Asset for Segment {
fn load(specifier: &str) -> Result<Self, Error> {
Ok(Segment::from(dot_vox::load_bytes(load_from_path(specifier)?.as_slice()).unwrap()))
}
}
// TODO: System to load file from specifiers (eg "core.ui.backgrounds.city")
fn try_load_from_path(name: &str) -> Option<File> {
let basepaths = [
// if it's stupid and it works..,
"assets".to_string(),
"../../assets".to_string(),
"../assets".to_string(), /* optimizations */
[env!("CARGO_MANIFEST_DIR"), "/assets"].concat(),
[env!("CARGO_MANIFEST_DIR"), "/../../assets"].concat(),
[env!("CARGO_MANIFEST_DIR"), "/../assets"].concat(),
"../../../assets".to_string(),
[env!("CARGO_MANIFEST_DIR"), "/../../../assets"].concat(),
];
for bp in &basepaths {
let filename = [bp, name].concat();
match File::open(&filename) {
Ok(f) => {
debug!("loading {} succedeed", filename);
return Some(f);
},
Err(e) => {
debug!("loading {} did not work with error: {}", filename, e);
}
};
};
None
}
pub fn load_from_path(name: &str) -> Result<Vec<u8>, Error> {
match try_load_from_path(name) {
Some(mut f) => {
let mut content: Vec<u8> = vec!();
f.read_to_end(&mut content);
info!("loaded asset successful: {}", name);
Ok(content)
},
None => {
warn!("Loading asset failed, wanted to load {} but could not load it, check debug log!", name);
Err(Error::NotFound)
}
}
}
/*
/// Translation Asset
pub struct Translations {
pub translations: Value
}
impl Translations {
pub fn get_lang(&self, lang: &str) -> &str {
self.translations[lang].as_str().unwrap()
}
}
impl Asset for Translations {
type T=Self;
fn load(path: &str) -> Result<Self, ()>{
let file_out = read_from_path(path).unwrap();
let content = from_utf8(file_out.as_slice()).unwrap();
let value = content.parse::<Value>().unwrap();
Ok(Translations{translations: value})
}
}
*/

View File

@ -10,6 +10,7 @@ extern crate serde_derive;
#[macro_use]
extern crate log;
pub mod assets;
pub mod clock;
pub mod comp;
pub mod figure;

View File

@ -1,189 +0,0 @@
use super::Asset;
use crate::ui::{Ui, Graphic};
use common::figure::Segment;
use dot_vox::DotVoxData;
use image::DynamicImage;
use conrod_core::image::Id as ImgId;
pub trait UiId where Self: std::marker::Sized {
fn to_ui_asset(self, ui: &mut Ui) -> ImgId;
}
impl UiId for DynamicImage {
fn to_ui_asset(self, ui: &mut Ui) -> ImgId {
ui.new_graphic(Graphic::Image(self))
}
}
impl UiId for DotVoxData {
fn to_ui_asset(self, ui: &mut Ui) -> ImgId {
ui.new_graphic(Graphic::Voxel(Segment::from(self)))
}
}
/// This macro will automatically load all specified assets, get the corresponding ImgIds and
/// create a struct with all of them
///
/// Example usage:
/// ```
/// image_ids! {
/// pub struct Ids {
/// <DotVoxData>
/// button1: "filename1.vox",
/// button2: "filename2.vox",
///
/// <DynamicImage>
/// background: "background.png",
/// }
/// }
/// ```
macro_rules! image_ids {
(pub struct $Ids:ident { $( <$T:ty> $( $name:ident: $file:expr ),* $(,)? )* }) => {
pub struct $Ids {
$($( $name: ImgId, )*)*
}
impl $Ids {
pub fn load(ui: &mut Ui) -> Result<Self, std::io::Error> {
Ok(Self {
$($( $name: UiId::to_ui_asset(<$T>::load($file)?, ui), )*)*
})
}
}
};
}
image_ids! {
pub struct Ids {
<DotVoxData>
// Bag
bag_contents: "element/frames/bag.vox",
inv_grid: "element/frames/inv_grid.vox",
inv_slot: "element/buttons/inv_slot.vox",
// Buttons
settings: "element/buttons/settings.vox",
settings_hover: "element/buttons/settings_hover.vox",
settings_press: "element/buttons/settings_press.vox",
social_button: "element/buttons/social.vox",
social_hover: "element/buttons/social_hover.vox",
social_press: "element/buttons/social_press.vox",
map_button: "element/buttons/map.vox",
map_hover: "element/buttons/map_hover.vox",
map_press: "element/buttons/map_press.vox",
spellbook_button: "element/buttons/spellbook.vox",
spellbook_hover: "element/buttons/spellbook_hover.vox",
spellbook_press: "element/buttons/spellbook_press.vox",
character_button: "element/buttons/character.vox",
character_hover: "element/buttons/character_hover.vox",
character_press: "element/buttons/character_press.vox",
qlog_button: "element/buttons/qlog.vox",
qlog_hover: "element/buttons/qlog_hover.vox",
qlog_press: "element/buttons/qlog_press.vox",
close_button: "element/buttons/x.vox",
close_button_hover: "element/buttons/x_hover.vox",
close_button_press: "element/buttons/x_press.vox",
// Esc menu
fireplace: "element/misc_bg/fireplace.vox",
button_dark: "element/buttons/button_dark.vox",
// Minimap
mmap_frame: "element/frames/mmap.vox",
window_frame: "element/frames/window2.vox",
map_frame_l: "element/frames/map_l.vox",
map_frame_r: "element/frames/map_r.vox",
<DynamicImage>
// Bag
bag: "element/buttons/bag/closed.png",
bag_hover: "element/buttons/bag/closed_hover.png",
bag_press: "element/buttons/bag/closed_press.png",
bag_open: "element/buttons/bag/open.png",
bag_open_hover: "element/buttons/bag/open_hover.png",
bag_open_press: "element/buttons/bag/open_press.png",
// Buttons
mmap_button: "element/buttons/border.png",
mmap_button_hover: "element/buttons/border_mo.png",
mmap_button_press: "element/buttons/border_press.png",
mmap_button_open: "element/buttons/border_pressed.png",
// Esc-Menu
esc_bg: "element/frames/menu.png",
button_dark_hover: "element/buttons/button_dark_hover.png",
button_dark_press: "element/buttons/button_dark_press.png",
// MiniMap
mmap_frame_bg: "element/misc_bg/mmap_bg.png",
// Skillbar Module
sb_grid: "element/skill_bar/sbar_grid.png",
sb_grid_bg: "element/skill_bar/sbar_grid_bg.png",
l_click: "element/skill_bar/l.png",
r_click: "element/skill_bar/r.png",
mana_bar: "element/skill_bar/mana_bar.png",
health_bar: "element/skill_bar/health_bar.png",
xp_bar: "element/skill_bar/xp_bar.png",
// Missing: Buff Frame Animation (.gif ?!) (we could do animation in ui.maintain(), or in shader?)
window_frame_2: "element/frames/window_2.png",
// Settings Window
settings_bg: "element/frames/settings.png",
settings_icon: "element/icons/settings.png",
settings_button_mo: "element/buttons/blue_mo.png",
check: "element/buttons/check/no.png",
check_mo: "element/buttons/check/no_mo.png",
check_press: "element/buttons/check/press.png",
check_checked: "element/buttons/check/yes.png",
check_checked_mo: "element/buttons/check/yes_mo.png",
slider: "element/slider/track.png",
slider_indicator: "element/slider/indicator.png",
//button_blank: ui.new_graphic(ui::Graphic::Blank),
button_blue_mo: "element/buttons/blue_mo.png",
button_blue_press: "element/buttons/blue_press.png",
// Window BG
window_bg: "element/misc_bg/window_bg.png",
// Social Window
social_bg: "element/misc_bg/small_bg.png",
social_icon: "element/icons/social.png",
// Map Window
map_bg: "element/misc_bg/small_bg.png",
map_icon: "element/icons/map.png",
// Spell Book Window
spellbook_bg: "element/misc_bg/small_bg.png",
spellbook_icon: "element/icons/spellbook.png",
// Char Window
charwindow: "element/misc_bg/charwindow.png",
charwindow_icon: "element/icons/charwindow.png",
charwindow_tab_bg: "element/frames/tab.png",
charwindow_tab: "element/buttons/tab.png",
charwindow_expbar: "element/misc_bg/small_bg.png",
progress_frame: "element/frames/progress_bar.png",
progress: "element/misc_bg/progress.png",
// Quest-Log Window
questlog_bg: "element/misc_bg/small_bg.png",
questlog_icon: "element/icons/questlog.png",
// Chat-Arrows
chat_arrow: "element/buttons/arrow/chat_arrow.png",
chat_arrow_mo: "element/buttons/arrow/chat_arrow_mo.png",
chat_arrow_press: "element/buttons/arrow/chat_arrow_press.png",
}
}

View File

@ -1,50 +0,0 @@
pub mod ids;
use conrod_core::widget::image::Image;
use crate::ui::Ui;
use crate::ui::Graphic;
use dot_vox::DotVoxData;
use image::DynamicImage;
use std::env;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::fs::File;
fn read_from_path(path: &str) -> Result<Vec<u8>, std::io::Error> {
let path_slash = path.replace(".", "/");
let path_slash_toml = [env!("CARGO_MANIFEST_DIR"), &path_slash, ".toml"].concat();
println!("{}", path_slash_toml);
let mut content = Vec::new();
File::open(path_slash_toml)?.read_to_end(&mut content);
Ok(content)
}
pub trait Asset where Self: std::marker::Sized {
fn load(path: &str) -> Result<Self, std::io::Error>;
}
impl Asset for DynamicImage {
fn load(path: &str) -> Result<Self, std::io::Error> {
let image = image::load_from_memory(
&read_from_path(path)?
).unwrap();
Ok(image)
}
}
impl Asset for DotVoxData {
fn load(path: &str) -> Result<Self, std::io::Error> {
let dot_vox = dot_vox::load_bytes(
&read_from_path(path)?
).unwrap();
Ok(dot_vox)
}
}

View File

@ -6,21 +6,17 @@ use self::character_window::CharacterWindow;
use crate::{
render::Renderer,
settings::{ControlSettings, Settings},
ui::{self, ScaleMode, ToggleButton, Ui},
ui::{ScaleMode, ToggleButton, Ui, Graphic},
window::{Event as WinEvent, Key, Window},
GlobalState,
};
use common::{
assets,
figure::Segment};
use conrod_core::{
color,
image::Id as ImgId,
text::font::Id as FontId,
widget::{self,Style, Button, Image, Rectangle, Scrollbar, Text},
WidgetStyle, widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
};
use common::assets;
// TODO: Use styles?
const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
@ -210,6 +206,138 @@ widget_ids! {
}
}
image_ids! {
pub(self) struct<common::figure::Segment> Voxs {
// Bag
bag_contents: "/voxygen/element/frames/bag.vox",
inv_grid: "/voxygen/element/frames/inv_grid.vox",
inv_slot: "/voxygen/element/buttons/inv_slot.vox",
// Buttons
settings: "/voxygen/element/buttons/settings.vox",
settings_hover: "/voxygen/element/buttons/settings_hover.vox",
settings_press: "/voxygen/element/buttons/settings_press.vox",
social_button: "/voxygen/element/buttons/social.vox",
social_hover: "/voxygen/element/buttons/social_hover.vox",
social_press: "/voxygen/element/buttons/social_press.vox",
map_button: "/voxygen/element/buttons/map.vox",
map_hover: "/voxygen/element/buttons/map_hover.vox",
map_press: "/voxygen/element/buttons/map_press.vox",
spellbook_button: "/voxygen/element/buttons/spellbook.vox",
spellbook_hover: "/voxygen/element/buttons/spellbook_hover.vox",
spellbook_press: "/voxygen/element/buttons/spellbook_press.vox",
character_button: "/voxygen/element/buttons/character.vox",
character_hover: "/voxygen/element/buttons/character_hover.vox",
character_press: "/voxygen/element/buttons/character_press.vox",
qlog_button: "/voxygen/element/buttons/qlog.vox",
qlog_hover: "/voxygen/element/buttons/qlog_hover.vox",
qlog_press: "/voxygen/element/buttons/qlog_press.vox",
close_button: "/voxygen/element/buttons/x.vox",
close_button_hover: "/voxygen/element/buttons/x_hover.vox",
close_button_press: "/voxygen/element/buttons/x_press.vox",
// Esc menu
fireplace: "/voxygen/element/misc_bg/fireplace.vox",
button_dark: "/voxygen/element/buttons/button_dark.vox",
// Minimap
mmap_frame: "/voxygen/element/frames/mmap.vox",
window_frame: "/voxygen/element/frames/window2.vox",
map_frame_l: "/voxygen/element/frames/map_l.vox",
map_frame_r: "/voxygen/element/frames/map_r.vox",
}
pub(self) struct<image::DynamicImage> Imgs {
// Bag
bag: "/voxygen/element/buttons/bag/closed.png",
bag_hover: "/voxygen/element/buttons/bag/closed_hover.png",
bag_press: "/voxygen/element/buttons/bag/closed_press.png",
bag_open: "/voxygen/element/buttons/bag/open.png",
bag_open_hover: "/voxygen/element/buttons/bag/open_hover.png",
bag_open_press: "/voxygen/element/buttons/bag/open_press.png",
// Buttons
mmap_button: "/voxygen/element/buttons/border.png",
mmap_button_hover: "/voxygen/element/buttons/border_mo.png",
mmap_button_press: "/voxygen/element/buttons/border_press.png",
mmap_button_open: "/voxygen/element/buttons/border_pressed.png",
// Esc-Menu
esc_bg: "/voxygen/element/frames/menu.png",
button_dark_hover: "/voxygen/element/buttons/button_dark_hover.png",
button_dark_press: "/voxygen/element/buttons/button_dark_press.png",
// MiniMap
mmap_frame_bg: "/voxygen/element/misc_bg/mmap_bg.png",
// Skillbar Module
sb_grid: "/voxygen/element/skill_bar/sbar_grid.png",
sb_grid_bg: "/voxygen/element/skill_bar/sbar_grid_bg.png",
l_click: "/voxygen/element/skill_bar/l.png",
r_click: "/voxygen/element/skill_bar/r.png",
mana_bar: "/voxygen/element/skill_bar/mana_bar.png",
health_bar: "/voxygen/element/skill_bar/health_bar.png",
xp_bar: "/voxygen/element/skill_bar/xp_bar.png",
// Missing: Buff Frame Animation (.gif ?!) (we could do animation in ui.maintain(), or in shader?)
window_frame_2: "/voxygen/element/frames/window_2.png",
// Settings Window
settings_bg: "/voxygen/element/frames/settings.png",
settings_icon: "/voxygen/element/icons/settings.png",
settings_button_mo: "/voxygen/element/buttons/blue_mo.png",
check: "/voxygen/element/buttons/check/no.png",
check_mo: "/voxygen/element/buttons/check/no_mo.png",
check_press: "/voxygen/element/buttons/check/press.png",
check_checked: "/voxygen/element/buttons/check/yes.png",
check_checked_mo: "/voxygen/element/buttons/check/yes_mo.png",
slider: "/voxygen/element/slider/track.png",
slider_indicator: "/voxygen/element/slider/indicator.png",
//button_blank: ui.new_graphic(ui::Graphic::Blank),
button_blue_mo: "/voxygen/element/buttons/blue_mo.png",
button_blue_press: "/voxygen/element/buttons/blue_press.png",
// Window BG
window_bg: "/voxygen/element/misc_bg/window_bg.png",
// Social Window
social_bg: "/voxygen/element/misc_bg/small_bg.png",
social_icon: "/voxygen/element/icons/social.png",
// Map Window
map_bg: "/voxygen/element/misc_bg/small_bg.png",
map_icon: "/voxygen/element/icons/map.png",
// Spell Book Window
spellbook_bg: "/voxygen/element/misc_bg/small_bg.png",
spellbook_icon: "/voxygen/element/icons/spellbook.png",
// Char Window
charwindow: "/voxygen/element/misc_bg/charwindow.png",
charwindow_icon: "/voxygen/element/icons/charwindow.png",
charwindow_tab_bg: "/voxygen/element/frames/tab.png",
charwindow_tab: "/voxygen/element/buttons/tab.png",
charwindow_expbar: "/voxygen/element/misc_bg/small_bg.png",
progress_frame: "/voxygen/element/frames/progress_bar.png",
progress: "/voxygen/element/misc_bg/progress.png",
// Quest-Log Window
questlog_bg: "/voxygen/element/misc_bg/small_bg.png",
questlog_icon: "/voxygen/element/icons/questlog.png",
// Chat-Arrows
chat_arrow: "/voxygen/element/buttons/arrow/chat_arrow.png",
chat_arrow_mo: "/voxygen/element/buttons/arrow/chat_arrow_mo.png",
chat_arrow_press: "/voxygen/element/buttons/arrow/chat_arrow_press.png",
}
}
enum SettingsTab {
Interface,
Video,
@ -244,6 +372,8 @@ pub struct Hud {
ui: Ui,
ids: Ids,
imgs: Imgs,
voxs: Voxs,
blank_img: conrod_core::image::Id,
chat: chat::Chat,
font_metamorph: FontId,
font_opensans: FontId,
@ -277,13 +407,18 @@ impl Hud {
// Generate ids
let ids = Ids::new(ui.id_generator());
// Load images
let imgs = Imgs::new(&mut ui, window.renderer_mut());
let imgs = Imgs::load(&mut ui).unwrap();
// Load vox files
let voxs = Voxs::load(&mut ui).unwrap();
// Blank graphic
let blank_img = ui.new_graphic(Graphic::Blank);
// Load fonts
let load_font = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/font", filename].concat();
// TODO: use Asset trait to load font
ui.new_font(
conrod_core::text::Font::from_bytes(
assets::load(fullpath.as_str()).expect("Error loading file"),
assets::load_from_path(fullpath.as_str()).expect("Error loading file")
)
.unwrap(),
)
@ -296,6 +431,8 @@ impl Hud {
Self {
ui,
imgs,
voxs,
blank_img,
ids,
chat,
settings_tab: SettingsTab::Interface,
@ -387,10 +524,10 @@ impl Hud {
.font_size(18)
.set(self.ids.help, ui_widgets);
// X-button
if Button::image(self.imgs.close_button)
if Button::image(self.voxs.close_button)
.w_h(100.0 * 0.2, 100.0 * 0.2)
.hover_image(self.imgs.close_button_hover)
.press_image(self.imgs.close_button_press)
.hover_image(self.voxs.close_button_hover)
.press_image(self.voxs.close_button_press)
.top_right_with_margins_on(self.ids.help_bg, 8.0, 3.0)
.set(self.ids.button_help2, ui_widgets)
.was_clicked()
@ -451,7 +588,7 @@ impl Hud {
// Buttons at Bag
// 0 Settings
if Button::image(self.imgs.settings)
if Button::image(self.voxs.settings)
.w_h(29.0, 25.0)
.bottom_right_with_margins_on(ui_widgets.window, 5.0, 57.0)
.hover_image(self.imgs.settings_hover)
@ -474,7 +611,7 @@ impl Hud {
};
// 2 Map
if Button::image(self.imgs.map_button)
if Button::image(self.voxs.map_button)
.w_h(22.0, 25.0)
.left_from(self.ids.social_button, 10.0)
.hover_image(self.imgs.map_hover)
@ -495,19 +632,19 @@ impl Hud {
// Other Windows can only be accessed, when Settings are closed.
// Opening Settings will close all other Windows including the Bag.
// Opening the Map won't close the windows displayed before.
Image::new(self.imgs.social_button)
Image::new(self.voxs.social_button)
.w_h(25.0, 25.0)
.left_from(self.ids.settings_button, 10.0)
.set(self.ids.social_button_bg, ui_widgets);
Image::new(self.imgs.spellbook_button)
Image::new(self.voxs.spellbook_button)
.w_h(28.0, 25.0)
.left_from(self.ids.map_button, 10.0)
.set(self.ids.spellbook_button_bg, ui_widgets);
Image::new(self.imgs.character_button)
Image::new(self.voxs.character_button)
.w_h(27.0, 25.0)
.left_from(self.ids.spellbook_button, 10.0)
.set(self.ids.character_button_bg, ui_widgets);
Image::new(self.imgs.qlog_button)
Image::new(self.voxs.qlog_button)
.w_h(23.0, 25.0)
.left_from(self.ids.character_button, 10.0)
.set(self.ids.qlog_button_bg, ui_widgets);
@ -518,7 +655,7 @@ impl Hud {
} && self.map_open == false
{
// 1 Social
if Button::image(self.imgs.social_button)
if Button::image(self.voxs.social_button)
.w_h(25.0, 25.0)
.left_from(self.ids.settings_button, 10.0)
.hover_image(self.imgs.social_hover)
@ -544,7 +681,7 @@ impl Hud {
}
// 3 Spellbook
if Button::image(self.imgs.spellbook_button)
if Button::image(self.voxs.spellbook_button)
.w_h(28.0, 25.0)
.left_from(self.ids.map_button, 10.0)
.hover_image(self.imgs.spellbook_hover)
@ -570,7 +707,7 @@ impl Hud {
}
// 4 Char-Window
if Button::image(self.imgs.character_button)
if Button::image(self.voxs.character_button)
.w_h(27.0, 25.0)
.left_from(self.ids.spellbook_button, 10.0)
.hover_image(self.imgs.character_hover)
@ -1182,12 +1319,12 @@ impl Hud {
Small::Social => {
//Frame
if char_window_open {
Image::new(self.imgs.window_frame)
Image::new(self.voxs.window_frame)
.right_from(self.ids.charwindow_frame, 20.0)
.w_h(107.0 * 4.0, 125.0 * 4.0)
.set(self.ids.social_frame, ui_widgets);
} else {
Image::new(self.imgs.window_frame)
Image::new(self.voxs.window_frame)
.top_left_with_margins_on(ui_widgets.window, 200.0, 10.0)
.w_h(107.0 * 4.0, 125.0 * 4.0)
.set(self.ids.social_frame, ui_widgets);
@ -1232,7 +1369,7 @@ impl Hud {
Small::Spellbook => {
// Frame
if char_window_open {
Image::new(self.imgs.window_frame)
Image::new(self.voxs.window_frame)
.right_from(self.ids.charwindow_frame, 20.0)
.w_h(107.0 * 4.0, 125.0 * 4.0)
.set(self.ids.spellbook_frame, ui_widgets);
@ -1281,7 +1418,7 @@ impl Hud {
Small::Questlog => {
// Frame
if char_window_open {
Image::new(self.imgs.window_frame)
Image::new(self.voxs.window_frame)
.right_from(self.ids.charwindow_frame, 20.0)
.w_h(107.0 * 4.0, 125.0 * 4.0)
.set(self.ids.questlog_frame, ui_widgets);
@ -1342,7 +1479,7 @@ impl Hud {
.scroll_kids_vertically()
.set(self.ids.map_bg, ui_widgets);
// Frame
Image::new(self.imgs.map_frame_l)
Image::new(self.voxs.map_frame_l)
.top_left_with_margins_on(self.ids.map_bg, 0.0, 0.0)
.w_h(412.0, 488.0)
.set(self.ids.map_frame_l, ui_widgets);
@ -1392,7 +1529,7 @@ impl Hud {
.middle_of(ui_widgets.window)
.set(self.ids.esc_bg, ui_widgets);
Image::new(self.imgs.fireplace)
Image::new(self.voxs.fireplace)
.w_h(180.0, 60.0)
.mid_top_with_margin_on(self.ids.esc_bg, 50.0)
.set(self.ids.fireplace, ui_widgets);

View File

@ -1,7 +1,8 @@
#![feature(drain_filter)]
#![recursion_limit = "2048"]
pub mod assets;
#[macro_use]
pub mod ui;
pub mod anim;
pub mod error;
pub mod hud;

View File

@ -1,5 +1,4 @@
use crate::{
assets,
render::Renderer,
ui::{self, ScaleMode, Ui},
window::Window,
@ -232,26 +231,18 @@ struct Imgs {
icon_border_pressed: ImgId,
}
impl Imgs {
fn new(ui: &mut Ui, renderer: &mut Renderer) -> Imgs {
fn new(ui: &mut Ui) -> Imgs {
let load_img = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let image = image::load_from_memory(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap();
ui.new_graphic(ui::Graphic::Image(image))
let image = assets::load::<image::DynamicImage>(fullpath.as_str())
.expect("Error loading file");
ui.new_graphic(image.into())
};
let load_vox = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let dot_vox = dot_vox::load_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap();
ui.new_graphic(ui::Graphic::Voxel(Segment::from(dot_vox)))
let segment = assets::load::<common::figure::Segment>(fullpath.as_str())
.expect("Error loading file");
ui.new_graphic(segment.into())
};
Imgs {
v_logo: load_vox("element/v_logo.vox", ui),
@ -368,16 +359,14 @@ impl CharSelectionUi {
// Generate ids
let ids = Ids::new(ui.id_generator());
// Load images
let imgs = Imgs::new(&mut ui, window.renderer_mut());
let imgs = Imgs::new(&mut ui);
// Load fonts
let load_font = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/font", filename].concat();
ui.new_font(
conrod_core::text::Font::from_bytes(
assets::load(fullpath.as_str()).expect("Error loading file"),
)
.unwrap(),
)
ui.new_font(conrod_core::text::Font::from_bytes(
assets::load_from_path(fullpath.as_str())
.expect("Error loading file")
).unwrap())
};
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);

View File

@ -1,11 +1,13 @@
use crate::{
assets,
render::Renderer,
ui::{self, ScaleMode, Ui},
window::Window,
GlobalState, DEFAULT_PUBLIC_SERVER,
};
use common::figure::Segment;
use common::{
assets,
figure::Segment,
};
use conrod_core::{
color,
color::TRANSPARENT,
@ -64,26 +66,18 @@ struct Imgs {
button_press: ImgId,
}
impl Imgs {
fn new(ui: &mut Ui, renderer: &mut Renderer) -> Imgs {
fn new(ui: &mut Ui) -> Imgs {
let load_img = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let image = image::load_from_memory(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap();
ui.new_graphic(ui::Graphic::Image(image))
let image = assets::load::<image::DynamicImage>(fullpath.as_str())
.expect("Error loading file");
ui.new_graphic(image.into())
};
let load_vox = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/", filename].concat();
let dot_vox = dot_vox::load_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap();
ui.new_graphic(ui::Graphic::Voxel(Segment::from(dot_vox)))
let segment = assets::load::<common::figure::Segment>(fullpath.as_str())
.expect("Error loading file");
ui.new_graphic(segment.into())
};
Imgs {
bg: load_img("background/bg_main.png", ui),
@ -132,13 +126,13 @@ impl MainMenuUi {
// Generate ids
let ids = Ids::new(ui.id_generator());
// Load images
let imgs = Imgs::new(&mut ui, window.renderer_mut());
let imgs = Imgs::new(&mut ui);
// Load fonts
let load_font = |filename, ui: &mut Ui| {
let fullpath: String = ["/voxygen/font", filename].concat();
ui.new_font(
conrod_core::text::Font::from_bytes(
assets::load(fullpath.as_str()).expect("Error loading file"),
assets::load_from_path(fullpath.as_str()).expect("Error loading file")
)
.unwrap(),
)

View File

@ -100,15 +100,9 @@ impl FigureCache {
fn load_mesh(filename: &'static str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
let fullpath: String = ["/voxygen/voxel/", filename].concat();
Segment::from(
dot_vox::load_bytes(
assets::load(fullpath.as_str())
.expect("Error loading file")
.as_slice(),
)
.unwrap(),
)
.generate_mesh(position)
assets::load::<Segment>(fullpath.as_str())
.expect("Error loading file")
.generate_mesh(position)
}
fn load_head(head: Head) -> Mesh<FigurePipeline> {

View File

@ -1,3 +1,4 @@
use std::sync::Arc;
use common::figure::Segment;
use fnv::FnvHashMap;
use guillotiere::{size2, Allocation, AtlasAllocator};
@ -5,10 +6,22 @@ use image::DynamicImage;
use vek::*;
pub enum Graphic {
Image(DynamicImage),
Voxel(Segment),
Image(Arc<DynamicImage>),
Voxel(Arc<Segment>),
Blank,
}
impl From<Arc<DynamicImage>> for Graphic {
fn from(image: Arc<DynamicImage>) -> Self {
Graphic::Image(image)
}
}
impl From<Arc<Segment>> for Graphic {
fn from(vox: Arc<Segment>) -> Self {
Graphic::Voxel(vox)
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct Id(u32);
@ -92,8 +105,8 @@ impl GraphicCache {
.pixels()
.map(|p| p.data)
.collect::<Vec<[u8; 4]>>(),
Graphic::Voxel(segment) => {
super::renderer::draw_vox(&segment, aabr.size().into())
Graphic::Voxel(vox) => {
super::renderer::draw_vox(&vox, aabr.size().into())
}
Graphic::Blank => return None,
};

34
voxygen/src/ui/img_ids.rs Normal file
View File

@ -0,0 +1,34 @@
/// This macro will automatically load all specified assets, get the corresponding ImgIds and
/// create a struct with all of them
///
/// Example usage:
/// ```
/// image_ids! {
/// struct<DotVoxData> Voxs {
/// button1: "filename1.vox",
/// button2: "filename2.vox",
/// }
/// struct<DynamicImage> Imgs {
/// background: "background.png",
/// }
/// }
/// ```
// TODO: will this work with shorter name paths? eg not rate::ui::Graphic::
#[macro_export]
macro_rules! image_ids {
($($v:vis struct<$T:ty> $Ids:ident { $( $name:ident: $specifier:expr ), *$(,)? } )*) => {
$(
$v struct $Ids {
$( $name: conrod_core::image::Id, )*
}
impl $Ids {
pub fn load(ui: &mut Ui) -> Result<Self, common::assets::Error> {
Ok(Self {
$( $name: ui.new_graphic(common::assets::load::<$T>($specifier)?.into()), )*
})
}
}
)*
};
}

View File

@ -1,6 +1,8 @@
mod graphic;
mod util;
mod widgets;
#[macro_use]
mod img_ids;
pub use graphic::Graphic;
pub(self) use util::{linear_to_srgb, srgb_to_linear};