diff --git a/Cargo.lock b/Cargo.lock index 1a1ab9e19a..d087b366d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -414,13 +414,13 @@ dependencies = [ [[package]] name = "dot_vox" -version = "1.0.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -461,6 +461,33 @@ dependencies = [ "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "euc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "vek 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "euclid" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "euclid_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.5" @@ -668,6 +695,14 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "guillotiere" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hibitset" version = "0.5.4" @@ -862,14 +897,6 @@ dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.2.0" @@ -970,14 +997,6 @@ dependencies = [ "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nom" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nom" version = "4.2.3" @@ -1898,7 +1917,7 @@ name = "veloren-common" version = "0.2.0" dependencies = [ "bincode 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dot_vox 4.0.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)", @@ -1942,13 +1961,16 @@ dependencies = [ "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", - "dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_device_gl 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "glsl-include 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "guillotiere 0.4.1 (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)", @@ -2209,12 +2231,15 @@ dependencies = [ "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" -"checksum dot_vox 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa4d1fc391ef151fff024e8427d206af1adbef4281fcd875090f74697000441" +"checksum dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11afd3251e588f2770226659b2a1d55ec2f8aaf2ca42bdcdbd01ff53b4a81e70" "checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f" "checksum draw_state 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33cf9537e2d06891448799b96d5a8c8083e0e90522a7fdabe6ebf4f41d79d651" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" +"checksum euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0151594c4feeeb99ff35ac1b467383a46fcb2705275615bed0a47f25ffe2ccf8" +"checksum euclid 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7a4719a544a67ed3fc33784c2bd2c6581663dfe83b719a6ae05c6dabc3b51c73" +"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" @@ -2238,6 +2263,7 @@ dependencies = [ "checksum gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "39bb69499005e11b7b7cc0af38404a1bc0f53d954bffa8adcdb6e8d5b14f75d5" "checksum glsl-include 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "31c109a006ad24fd612da10d185b51000ef502155578f3634416f102f0d63b6c" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" +"checksum guillotiere 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e965c66630b3a0369feafb06d945f15a4f59aaecc209eb1c4a2b57bb48ee06" "checksum hibitset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6527bc88f32e0d3926c7572874b2bf17a19b36978aacd0aacf75f7d27a5992d0" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "545f000e8aa4e569e93f49c446987133452e0091c2494ac3efd3606aa3d309f2" @@ -2263,7 +2289,6 @@ dependencies = [ "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" @@ -2275,7 +2300,6 @@ dependencies = [ "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum noise 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a3a34d4f8a31f95919b7ead9f5b60afb9bda0cae98b9219432ffaa6f00b0141" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum nonzero_signed 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "02783a0482333b0d3f5f5411b8fb60454a596696da041da0470ac9ef3e6e37d8" "checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" diff --git a/common/Cargo.toml b/common/Cargo.toml index e12e94bbab..da924061fd 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,7 +10,7 @@ sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"] specs = { version = "0.14", features = ["serde"] } shred = { version = "0.7", features = ["nightly"] } vek = { version = "0.9", features = ["serde"] } -dot_vox = "1.0" +dot_vox = "4.0" threadpool = "1.7" mio = "0.6" mio-extras = "2.0" diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 4b9c11fa2b..40eda49ee8 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -22,6 +22,7 @@ glutin = "0.19" winit = {version = "0.18", features = ["serde"]} conrod_core = { git = "https://gitlab.com/veloren/conrod.git" } conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" } +euc = "0.2" # ECS specs = "0.14" @@ -35,9 +36,11 @@ failure = "0.1" lazy_static = "1.1" log = "0.4" pretty_env_logger = "0.3" -dot_vox = "1.0" +dot_vox = "4.0" image = "0.21" config = "0.9" serde = "1.0" serde_derive = "1.0" toml = "0.4" +guillotiere = "0.4" +fnv = "1.0" diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 589b283f85..83ab013899 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -2,7 +2,7 @@ mod chat; use crate::{ render::Renderer, - ui::{ScaleMode, ToggleButton, Ui}, + ui::{self, ScaleMode, ToggleButton, Ui}, window::{Event as WinEvent, Key, Window}, }; use common::assets; @@ -144,7 +144,7 @@ widget_ids! { pub(self) struct Imgs { //Missing: ActionBar, Health/Mana/Energy Bar & Char Window BG/Frame //Logo - v_logo: ImgId, + //v_logo: ImgId, // Bag bag: ImgId, bag_hover: ImgId, @@ -249,7 +249,7 @@ pub(self) struct Imgs { } impl Imgs { fn new(ui: &mut Ui, renderer: &mut Renderer) -> Imgs { - let mut load = |filename| { + let mut load = |filename, ui: &mut Ui| { let fullpath: String = ["/voxygen/", filename].concat(); let image = image::load_from_memory( assets::load(fullpath.as_str()) @@ -257,117 +257,116 @@ impl Imgs { .as_slice(), ) .unwrap(); - ui.new_image(renderer, &image).unwrap() + ui.new_graphic(ui::Graphic::Image(image)) }; Imgs { // Bag - bag: load("element/buttons/bag/closed.png"), - bag_hover: load("element/buttons/bag/closed_hover.png"), - bag_press: load("element/buttons/bag/closed_press.png"), - bag_open: load("element/buttons/bag/open.png"), - bag_open_hover: load("element/buttons/bag/open_hover.png"), - bag_open_press: load("element/buttons/bag/open_press.png"), - bag_contents: load("element/frames/bag.png"), - inv_grid: load("element/frames/inv_grid.png"), - inv_slot: load("element/buttons/inv_slot.png"), + bag: load("element/buttons/bag/closed.png", ui), + bag_hover: load("element/buttons/bag/closed_hover.png", ui), + bag_press: load("element/buttons/bag/closed_press.png", ui), + bag_open: load("element/buttons/bag/open.png", ui), + bag_open_hover: load("element/buttons/bag/open_hover.png", ui), + bag_open_press: load("element/buttons/bag/open_press.png", ui), + bag_contents: load("element/frames/bag.png", ui), + inv_grid: load("element/frames/inv_grid.png", ui), + inv_slot: load("element/buttons/inv_slot.png", ui), // Close button - close_button: load("element/buttons/x.png"), - close_button_hover: load("element/buttons/x_hover.png"), - close_button_press: load("element/buttons/x_press.png"), + close_button: load("element/buttons/x.png", ui), + close_button_hover: load("element/buttons/x_hover.png", ui), + close_button_press: load("element/buttons/x_press.png", ui), // Esc-Menu - esc_bg: load("element/frames/menu.png"), - fireplace: load("element/misc_backgrounds/fireplace.png"), - button_dark: load("element/buttons/button_dark.png"), - button_dark_hover: load("element/buttons/button_dark_hover.png"), - button_dark_press: load("element/buttons/button_dark_press.png"), + esc_bg: load("element/frames/menu.png", ui), + fireplace: load("element/misc_backgrounds/fireplace.png", ui), + button_dark: load("element/buttons/button_dark.png", ui), + button_dark_hover: load("element/buttons/button_dark_hover.png", ui), + button_dark_press: load("element/buttons/button_dark_press.png", ui), // MiniMap - mmap_frame: load("element/frames/mmap.png"), - mmap_frame_bg: load("element/misc_backgrounds/mmap_bg.png"), - mmap_icons: load("element/buttons/mmap_icons.png"), + mmap_frame: load("element/frames/mmap.png", ui), + mmap_frame_bg: load("element/misc_backgrounds/mmap_bg.png", ui), + mmap_icons: load("element/buttons/mmap_icons.png", ui), // Settings at Mini-Map - mmap_button: load("element/buttons/border.png"), - mmap_button_hover: load("element/buttons/border_mo.png"), - mmap_button_press: load("element/buttons/border_press.png"), - mmap_button_open: load("element/buttons/border_pressed.png"), + mmap_button: load("element/buttons/border.png", ui), + mmap_button_hover: load("element/buttons/border_mo.png", ui), + mmap_button_press: load("element/buttons/border_press.png", ui), + mmap_button_open: load("element/buttons/border_pressed.png", ui), // Skillbar Module - sb_grid: load("element/skill_bar/sbar_grid.png"), - sb_grid_bg: load("element/skill_bar/sbar_grid_bg.png"), - l_click: load("element/skill_bar/l.png"), - r_click: load("element/skill_bar/r.png"), - mana_bar: load("element/skill_bar/mana_bar.png"), - health_bar: load("element/skill_bar/health_bar.png"), - xp_bar: load("element/skill_bar/xp_bar.png"), + sb_grid: load("element/skill_bar/sbar_grid.png", ui), + sb_grid_bg: load("element/skill_bar/sbar_grid_bg.png", ui), + l_click: load("element/skill_bar/l.png", ui), + r_click: load("element/skill_bar/r.png", ui), + mana_bar: load("element/skill_bar/mana_bar.png", ui), + health_bar: load("element/skill_bar/health_bar.png", ui), + xp_bar: load("element/skill_bar/xp_bar.png", ui), //Buff Frame(s) - //buff_frame: load("element/skill_bar/buff_frame.png"), - //buff_frame_bg: load("element/skill_bar/buff_frame_bg.png"), - //buff_frame_red: load("element/skill_bar/buff_frame_red.png"), - //buff_frame_green: load("element/skill_bar/buff_frame_green.png"), + //buff_frame: load("element/skill_bar/buff_frame.png", ui), + //buff_frame_bg: load("element/skill_bar/buff_frame_bg.png", ui), + //buff_frame_red: load("element/skill_bar/buff_frame_red.png", ui), + //buff_frame_green: load("element/skill_bar/buff_frame_green.png", ui), //Missing: Buff Frame Animation (.gif ?!) (we could do animation in ui.maintain(), or in shader?) - window_frame: load("element/frames/window.png"), - window_frame_2: load("element/frames/window_2.png"), + window_frame: load("element/frames/window.png", ui), + window_frame_2: load("element/frames/window_2.png", ui), //Settings Window - settings_bg: load("element/frames/settings.png"), - settings_icon: load("element/icons/settings.png"), - settings_button_mo: load("element/buttons/blue_mo.png"), - check: load("element/buttons/check/no.png"), - check_mo: load("element/buttons/check/no_mo.png"), - check_press: load("element/buttons/check/press.png"), - check_checked: load("element/buttons/check/yes.png"), - check_checked_mo: load("element/buttons/check/yes_mo.png"), - slider: load("element/slider/track.png"), - slider_indicator: load("element/slider/indicator.png"), - button_blank: load("element/nothing.png"), - button_blue_mo: load("element/buttons/blue_mo.png"), - button_blue_press: load("element/buttons/blue_press.png"), + settings_bg: load("element/frames/settings.png", ui), + settings_icon: load("element/icons/settings.png", ui), + settings_button_mo: load("element/buttons/blue_mo.png", ui), + check: load("element/buttons/check/no.png", ui), + check_mo: load("element/buttons/check/no_mo.png", ui), + check_press: load("element/buttons/check/press.png", ui), + check_checked: load("element/buttons/check/yes.png", ui), + check_checked_mo: load("element/buttons/check/yes_mo.png", ui), + slider: load("element/slider/track.png", ui), + slider_indicator: load("element/slider/indicator.png", ui), + button_blank: ui.new_graphic(ui::Graphic::Blank), + button_blue_mo: load("element/buttons/blue_mo.png", ui), + button_blue_press: load("element/buttons/blue_press.png", ui), // Window BG - window_bg: load("element/misc_backgrounds/window_bg.png"), - v_logo: load("element/v_logo.png"), + window_bg: load("element/misc_backgrounds/window_bg.png", ui), //Social Window - social_bg: load("element/misc_backgrounds/small_bg.png"), - social_icon: load("element/icons/social.png"), + social_bg: load("element/misc_backgrounds/small_bg.png", ui), + social_icon: load("element/icons/social.png", ui), //Map Window - map_bg: load("element/misc_backgrounds/small_bg.png"), - map_icon: load("element/icons/map.png"), - map_frame: load("element/frames/window_map.png"), + map_bg: load("element/misc_backgrounds/small_bg.png", ui), + map_icon: load("element/icons/map.png", ui), + map_frame: load("element/frames/window_map.png", ui), // Spell Book Window - spellbook_bg: load("element/misc_backgrounds/small_bg.png"), - spellbook_icon: load("element/icons/spellbook.png"), + spellbook_bg: load("element/misc_backgrounds/small_bg.png", ui), + spellbook_icon: load("element/icons/spellbook.png", ui), //Char Window - charwindow: load("element/misc_backgrounds/charwindow.png"), - charwindow_icon: load("element/icons/charwindow.png"), - charwindow_tab_bg: load("element/frames/tab.png"), - charwindow_tab: load("element/buttons/tab.png"), - charwindow_expbar: load("element/misc_backgrounds/small_bg.png"), - progress_frame: load("element/frames/progress_bar.png"), - progress: load("element/misc_backgrounds/progress.png"), + charwindow: load("element/misc_backgrounds/charwindow.png", ui), + charwindow_icon: load("element/icons/charwindow.png", ui), + charwindow_tab_bg: load("element/frames/tab.png", ui), + charwindow_tab: load("element/buttons/tab.png", ui), + charwindow_expbar: load("element/misc_backgrounds/small_bg.png", ui), + progress_frame: load("element/frames/progress_bar.png", ui), + progress: load("element/misc_backgrounds/progress.png", ui), //Quest-Log Window - questlog_bg: load("element/misc_backgrounds/small_bg.png"), - questlog_icon: load("element/icons/questlog.png"), + questlog_bg: load("element/misc_backgrounds/small_bg.png", ui), + questlog_icon: load("element/icons/questlog.png", ui), // Chat-Arrows - chat_arrow: load("element/buttons/arrow/chat_arrow.png"), - chat_arrow_mo: load("element/buttons/arrow/chat_arrow_mo.png"), - chat_arrow_press: load("element/buttons/arrow/chat_arrow_press.png"), - chat_arrow_up: load("element/buttons/arrow/chat_arrow_up.png"), - chat_arrow_up_mo: load("element/buttons/arrow/chat_arrow_up_mo.png"), - chat_arrow_up_press: load("element/buttons/arrow/chat_arrow_up_press.png"), - chat_arrow_down: load("element/buttons/arrow/chat_arrow_down.png"), - chat_arrow_down_mo: load("element/buttons/arrow/chat_arrow_down_mo.png"), - chat_arrow_down_press: load("element/buttons/arrow/chat_arrow_down_press.png"), + chat_arrow: load("element/buttons/arrow/chat_arrow.png", ui), + chat_arrow_mo: load("element/buttons/arrow/chat_arrow_mo.png", ui), + chat_arrow_press: load("element/buttons/arrow/chat_arrow_press.png", ui), + chat_arrow_up: load("element/buttons/arrow/chat_arrow_up.png", ui), + chat_arrow_up_mo: load("element/buttons/arrow/chat_arrow_up_mo.png", ui), + chat_arrow_up_press: load("element/buttons/arrow/chat_arrow_up_press.png", ui), + chat_arrow_down: load("element/buttons/arrow/chat_arrow_down.png", ui), + chat_arrow_down_mo: load("element/buttons/arrow/chat_arrow_down_mo.png", ui), + chat_arrow_down_press: load("element/buttons/arrow/chat_arrow_down_press.png", ui), } } } diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index 34ebd08c70..1a2be0245e 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -235,7 +235,7 @@ impl Imgs { .as_slice(), ) .unwrap(); - ui.new_image(renderer, &image).unwrap() + ui.new_graphic(ui::Graphic::Image(image)) }; Imgs { v_logo: load("element/v_logo.png"), diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index 1a10e3ad14..1ab24d8c63 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -4,7 +4,10 @@ use crate::{ window::Window, DEFAULT_PUBLIC_SERVER, }; -use common::assets; +use common::{ + assets, + figure::Segment, +}; use conrod_core::{ color, color::TRANSPARENT, @@ -65,8 +68,7 @@ struct Imgs { } impl Imgs { fn new(ui: &mut Ui, renderer: &mut Renderer) -> Imgs { - // TODO: update paths - let mut load = |filename| { + let mut load_img = |filename, ui: &mut Ui| { let fullpath: String = ["/voxygen/", filename].concat(); let image = image::load_from_memory( assets::load(fullpath.as_str()) @@ -74,30 +76,41 @@ impl Imgs { .as_slice(), ) .unwrap(); - ui.new_image(renderer, &image).unwrap() + ui.new_graphic(ui::Graphic::Image(image)) + }; + let mut 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))) }; Imgs { - bg: load("background/bg_main.png"), - v_logo: load("element/v_logo.png"), + bg: load_img("background/bg_main.png", ui), + v_logo: load_img("element/v_logo.png", ui), // Input fields - input_bg: load("element/misc_backgrounds/textbox.png"), + input_bg: load_img("element/misc_backgrounds/textbox.png", ui), // Login button - login_button: load("element/buttons/button_login.png"), - login_button_hover: load("element/buttons/button_login_hover.png"), - login_button_press: load("element/buttons/button_login_press.png"), + login_button: load_img("element/buttons/button_login.png", ui), + login_button_hover: load_img("element/buttons/button_login_hover.png", ui), + login_button_press: load_img("element/buttons/button_login_press.png", ui), // Servers, settings, and quit buttons - button: load("element/buttons/button.png"), - button_hover: load("element/buttons/button_hover.png"), - button_press: load("element/buttons/button_press.png"), + //button: load_vox("element/buttons/button.vox", ui), + button: load_img("element/buttons/button.png", ui), + button_hover: load_img("element/buttons/button_hover.png", ui), + button_press: load_img("element/buttons/button_press.png", ui), //Error - error_frame: load("element/frames/window_2.png"), - button_dark: load("element/buttons/button_dark.png"), - button_dark_hover: load("element/buttons/button_dark_hover.png"), - button_dark_press: load("element/buttons/button_dark_press.png"), + error_frame: load_img("element/frames/window_2.png", ui), + button_dark: load_img("element/buttons/button_dark.png", ui), + button_dark_hover: load_img("element/buttons/button_dark_hover.png", ui), + button_dark_press: load_img("element/buttons/button_dark_press.png", ui), } } } diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs index 0f3a3b4800..0c2147c667 100644 --- a/voxygen/src/render/pipelines/ui.rs +++ b/voxygen/src/render/pipelines/ui.rs @@ -65,13 +65,13 @@ impl Mode { } } -pub fn create_quad(rect: Aabr, uv_rect: Aabr, color: [f32; 4], mode: Mode) -> Quad { +pub fn create_quad(rect: Aabr, uv_rect: Aabr, color: Rgba, mode: Mode) -> Quad { let mode_val = mode.value(); let v = |pos, uv| { Vertex { pos, uv, - color, + color: color.into_array(), mode: mode_val, } }; @@ -90,13 +90,13 @@ pub fn create_quad(rect: Aabr, uv_rect: Aabr, color: [f32; 4], mode: M ) } -pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: [f32; 4], mode: Mode) -> Tri { +pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: Rgba, mode: Mode) -> Tri { let mode_val = mode.value(); let v = |pos, uv| { Vertex { pos, uv, - color, + color: color.into_array(), mode: mode_val, } }; diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index 59d574a698..d9d166dd4c 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -81,7 +81,7 @@ impl Texture

{ tex, srv, sampler: factory.create_sampler(gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, + gfx::texture::FilterMethod::Scale, gfx::texture::WrapMode::Clamp, )), _phantom: PhantomData, diff --git a/voxygen/src/ui/graphic/graphic.rs b/voxygen/src/ui/graphic/graphic.rs new file mode 100644 index 0000000000..b42216b36a --- /dev/null +++ b/voxygen/src/ui/graphic/graphic.rs @@ -0,0 +1,115 @@ +use common::figure::Segment; +use fnv::FnvHashMap; +use guillotiere::{size2, Allocation, AtlasAllocator}; +use image::DynamicImage; +use vek::*; + +pub enum Graphic { + Image(DynamicImage), + Voxel(Segment), + Blank, +} +#[derive(PartialEq, Eq, Hash, Copy, Clone)] +pub struct Id(u32); + +type Parameters = (Id, Vec2, Aabr); + +pub struct GraphicCache { + atlas: AtlasAllocator, + graphic_map: FnvHashMap, + rect_map: FnvHashMap>, + next_id: u32, +} +impl GraphicCache { + pub fn new(size: Vec2) -> Self { + Self { + atlas: AtlasAllocator::new(size2(i32::from(size.x), i32::from(size.y))), + graphic_map: FnvHashMap::default(), + rect_map: FnvHashMap::default(), + next_id: 0, + } + } + pub fn new_graphic(&mut self, graphic: Graphic) -> Id { + let id = self.next_id; + self.next_id = id.wrapping_add(1); + + let id = Id(id); + self.graphic_map.insert(id, graphic); + + id + } + pub fn get_graphic(&self, id: Id) -> Option<&Graphic> { + self.graphic_map.get(&id) + } + pub fn clear_cache(&mut self, new_size: Vec2) { + self.rect_map.clear(); + self.atlas = AtlasAllocator::new(size2(i32::from(new_size.x), i32::from(new_size.y))); + } + pub fn cache_res( + &mut self, + graphic_id: Id, + dims: Vec2, + source: Aabr, + mut cacher: F, + ) -> Option> + where + F: FnMut(Aabr, Vec<[u8; 4]>), + { + match self + .rect_map + .get(&(graphic_id, dims, source.map(|e| e.to_bits()))) //<-------- TODO: Replace this with rounded representation of source + { + Some(aabr) => Some(*aabr), + None => match self.graphic_map.get(&graphic_id) { + Some(graphic) => { + // Allocate rectangle + let aabr = match self + .atlas + .allocate(size2(i32::from(dims.x), i32::from(dims.y))) + { + Some(Allocation { id, rectangle }) => { + let (min, max) = (rectangle.min, rectangle.max); + Aabr { + min: Vec2::new(min.x as u16, min.y as u16), + max: Vec2::new(max.x as u16, max.y as u16), + } + } + // Out of room + // TODO: make more room by 1. expanding cache size, 2. removing unused allocations, 3. rearranging rectangles + None => return None, + }; + + // Render image + // TODO: use source + let data = match graphic { + Graphic::Image(ref image) => image + .resize_exact( + u32::from(aabr.size().w), + u32::from(aabr.size().h), + image::FilterType::Nearest, + ) + .to_rgba() + .pixels() + .map(|p| p.data) + .collect::>(), + Graphic::Voxel(segment) => { + super::renderer::draw_vox(&segment, aabr.size().into()) + } + Graphic::Blank => return None, + }; + + // Draw to allocated area + cacher(aabr, data); + + // Insert area into map for retrieval + self.rect_map + .insert((graphic_id, dims, source.map(|e| e.to_bits())), aabr); + + // Return area + Some(aabr) + } + None => None, + }, + } + } +} diff --git a/voxygen/src/ui/graphic/mod.rs b/voxygen/src/ui/graphic/mod.rs new file mode 100644 index 0000000000..a7b96f903f --- /dev/null +++ b/voxygen/src/ui/graphic/mod.rs @@ -0,0 +1,4 @@ +mod graphic; +mod renderer; + +pub use graphic::{Graphic, GraphicCache, Id}; diff --git a/voxygen/src/ui/graphic/renderer.rs b/voxygen/src/ui/graphic/renderer.rs new file mode 100644 index 0000000000..233681c28e --- /dev/null +++ b/voxygen/src/ui/graphic/renderer.rs @@ -0,0 +1,218 @@ +use super::super::{linear_to_srgb, srgb_to_linear}; +use common::{ + figure::Segment, + vol::{ReadVol, SizedVol, Vox}, +}; +use euc::{buffer::Buffer2d, rasterizer, Pipeline}; +use vek::*; + +struct Voxel { + mvp: Mat4, +} + +#[derive(Copy, Clone)] +struct Vert { + pos: Vec3, + col: Rgb, + norm: Vec3, + ao_level: u8, +} +impl Vert { + fn new(pos: Vec3, col: Rgb, norm: Vec3, ao_level: u8) -> Self { + Vert { + pos, + col, + norm, + ao_level, + } + } +} + +impl<'a> Pipeline for Voxel { + type Vertex = Vert; + type VsOut = Rgba; + type Pixel = [u8; 4]; + + #[inline(always)] + fn vert( + &self, + Vert { + pos, + col, + norm, + ao_level, + }: &Self::Vertex, + ) -> ([f32; 3], Self::VsOut) { + let light = Rgba::from_opaque(Rgb::from(*ao_level as f32 / 4.0 + 0.25)); + let color = light * srgb_to_linear(Rgba::from_opaque(*col)); + let position = Vec3::from(self.mvp * Vec4::from_point(*pos)).into_array(); + (position, color) + } + #[inline(always)] + fn frag(&self, color: &Self::VsOut) -> Self::Pixel { + linear_to_srgb(*color) + .map(|e| (e * 255.0) as u8) + .into_array() + } +} + +pub fn draw_vox(segment: &Segment, output_size: Vec2) -> Vec<[u8; 4]> { + let dims = output_size.map(|e| e as usize).into_array(); + let mut color = Buffer2d::new(dims, [0; 4]); + let mut depth = Buffer2d::new(dims, 1.0); + + let (w, h, d) = segment.get_size().map(|e| e as f32).into_tuple(); + + let mvp = Mat4::::orthographic_rh_no(FrustumPlanes { + left: -1.0, + right: 1.0, + bottom: -1.0, + top: 1.0, + near: 0.0, + far: 1.0, + }) * Mat4::rotation_x(-std::f32::consts::PI / 2.0) + * Mat4::scaling_3d([2.0 / w, 2.0 / h, 2.0 / d]) + * Mat4::translation_3d([-w / 2.0, -h / 2.0, -d / 2.0]); + Voxel { mvp }.draw::, _>( + &generate_mesh(segment, Vec3::from(0.0)), + &mut color, + &mut depth, + ); + + // TODO: remove this clone + color.as_ref().to_vec() +} + +fn ao_level(side1: bool, corner: bool, side2: bool) -> u8 { + if side1 && side2 { + 0 + } else { + 3 - [side1, corner, side2].iter().filter(|e| **e).count() as u8 + } +} +// TODO: generalize meshing code.... +fn create_quad( + origin: Vec3, + unit_x: Vec3, + unit_y: Vec3, + norm: Vec3, + col: Rgb, + occluders: [bool; 8], +) -> [Vert; 6] { + let a_ao = ao_level(occluders[0], occluders[1], occluders[2]); + let b_ao = ao_level(occluders[2], occluders[3], occluders[4]); + let c_ao = ao_level(occluders[4], occluders[5], occluders[6]); + let d_ao = ao_level(occluders[6], occluders[7], occluders[0]); + + let a = Vert::new(origin, col, norm, a_ao); + let b = Vert::new(origin + unit_x, col, norm, b_ao); + let c = Vert::new(origin + unit_x + unit_y, col, norm, c_ao); + let d = Vert::new(origin + unit_y, col, norm, d_ao); + + // Flip to fix anisotropy + let (a, b, c, d) = if a_ao + c_ao > b_ao + d_ao { + (d, a, b, c) + } else { + (a, b, c, d) + }; + + [ + a, b, c, // Tri 1 + c, d, a, // Tri 2 + ] +} + +fn generate_mesh(segment: &Segment, offs: Vec3) -> Vec { + let mut vertices = Vec::new(); + + for pos in segment.iter_positions() { + if let Some(col) = segment.get(pos).ok().and_then(|vox| vox.get_color()) { + let col = col.map(|e| e as f32 / 255.0); + + let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true); + + let occluders = |unit_x, unit_y, dir| { + // would be nice to generate unit_x and unit_y from a given direction + [ + !is_empty(pos + dir - unit_x), + !is_empty(pos + dir - unit_x - unit_y), + !is_empty(pos + dir - unit_y), + !is_empty(pos + dir + unit_x - unit_y), + !is_empty(pos + dir + unit_x), + !is_empty(pos + dir + unit_x + unit_y), + !is_empty(pos + dir + unit_y), + !is_empty(pos + dir - unit_x + unit_y), + ] + }; + + // -x + if is_empty(pos - Vec3::unit_x()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32) + Vec3::unit_y(), + -Vec3::unit_y(), + Vec3::unit_z(), + -Vec3::unit_x(), + col, + occluders(-Vec3::unit_y(), Vec3::unit_z(), -Vec3::unit_x()), + )); + } + // +x + if is_empty(pos + Vec3::unit_x()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32) + Vec3::unit_x(), + Vec3::unit_y(), + Vec3::unit_z(), + Vec3::unit_x(), + col, + occluders(Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x()), + )); + } + // -y + if is_empty(pos - Vec3::unit_y()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32), + Vec3::unit_x(), + Vec3::unit_z(), + -Vec3::unit_y(), + col, + occluders(Vec3::unit_x(), Vec3::unit_z(), -Vec3::unit_y()), + )); + } + // +y + if is_empty(pos + Vec3::unit_y()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32) + Vec3::unit_y(), + Vec3::unit_z(), + Vec3::unit_x(), + Vec3::unit_y(), + col, + occluders(Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y()), + )); + } + // -z + if is_empty(pos - Vec3::unit_z()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32), + Vec3::unit_y(), + Vec3::unit_x(), + -Vec3::unit_z(), + col, + occluders(Vec3::unit_y(), Vec3::unit_x(), -Vec3::unit_z()), + )); + } + // +z + if is_empty(pos + Vec3::unit_z()) { + vertices.extend_from_slice(&create_quad( + offs + pos.map(|e| e as f32) + Vec3::unit_z(), + Vec3::unit_x(), + Vec3::unit_y(), + Vec3::unit_z(), + col, + occluders(Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z()), + )); + } + } + } + + vertices +} diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index 4cd1b89da4..f5cf7c4a07 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -1,8 +1,15 @@ mod widgets; +mod graphic; +mod util; pub use widgets::toggle_button::ToggleButton; +pub use graphic::Graphic; +pub(self) use util::{srgb_to_linear, linear_to_srgb}; -use image::DynamicImage; +use graphic::{ + GraphicCache, + Id as GraphicId, +}; use conrod_core::{ Ui as CrUi, UiBuilder, @@ -16,7 +23,7 @@ use conrod_core::{ widget::{Id as WidgId, id::Generator}, render::Primitive, event::Input, - input::{touch::Touch, Widget, Motion, Button, MouseButton}, + input::{touch::Touch, Widget, Motion, Button}, }; use vek::*; use crate::{ @@ -81,9 +88,10 @@ impl Event { } pub struct Cache { - blank_texture: Texture, glyph_cache: GlyphCache<'static>, glyph_cache_tex: Texture, + graphic_cache: graphic::GraphicCache, + graphic_cache_tex: Texture, } // TODO: Should functions be returning UiError instead of Error? @@ -93,23 +101,31 @@ impl Cache { const SCALE_TOLERANCE: f32 = 0.1; const POSITION_TOLERANCE: f32 = 0.1; + let graphic_cache_dims = Vec2::new(w * 4, h * 4); Ok(Self { - blank_texture: renderer.create_texture(&DynamicImage::new_rgba8(1, 1))?, glyph_cache: GlyphCache::builder() .dimensions(w as u32, h as u32) .scale_tolerance(SCALE_TOLERANCE) .position_tolerance(POSITION_TOLERANCE) .build(), glyph_cache_tex: renderer.create_dynamic_texture((w, h).into())?, + graphic_cache: GraphicCache::new(graphic_cache_dims), + graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?, }) } - pub fn blank_texture(&self) -> &Texture { &self.blank_texture } pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex } pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture) { (&mut self.glyph_cache, &self.glyph_cache_tex) } + pub fn graphic_cache_tex(&self) -> &Texture { &self.graphic_cache_tex } + pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture) { (&mut self.graphic_cache, &self.graphic_cache_tex) } + pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId { self.graphic_cache.new_graphic(graphic) } + pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2) { + self.graphic_cache.clear_cache(new_size); + self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap(); + } } enum DrawKind { - Image(ImgId), + Image, // Text and non-textured geometry Plain, } @@ -121,9 +137,9 @@ enum DrawCommand { Scissor(Aabr), } impl DrawCommand { - fn image(model: Model, img_id: ImgId) -> DrawCommand { + fn image(model: Model) -> DrawCommand { DrawCommand::Draw { - kind: DrawKind::Image(img_id), + kind: DrawKind::Image, model, } } @@ -198,7 +214,7 @@ impl Scale { pub struct Ui { ui: CrUi, - image_map: Map>, + image_map: Map, cache: Cache, // Draw commands for the next render draw_commands: Vec, @@ -230,8 +246,8 @@ impl Ui { self.ui.handle_event(Input::Resize(w, h)); } - pub fn new_image(&mut self, renderer: &mut Renderer, image: &DynamicImage) -> Result { - Ok(self.image_map.insert(renderer.create_texture(image)?)) + pub fn new_graphic(&mut self, graphic: Graphic) -> ImgId { + self.image_map.insert(self.cache.new_graphic(graphic)) } pub fn new_font(&mut self, font: Font) -> FontId { @@ -246,7 +262,7 @@ impl Ui { self.ui.set_widgets() } - // Accepts option so widget can be unfocused + // Accepts Option so widget can be unfocused pub fn focus_widget(&mut self, id: Option) { self.ui.keyboard_capture(match id { Some(id) => id, @@ -259,7 +275,7 @@ impl Ui { self.ui.global_input().current.widget_capturing_keyboard } - // Get whether the a widget besides the window is capturing the mouse + // Get whether a widget besides the window is capturing the mouse pub fn no_widget_capturing_mouse(&self) -> bool { self.ui.global_input().current.widget_capturing_mouse.filter(|id| id != &self.ui.window ).is_none() } @@ -305,7 +321,14 @@ impl Ui { self.draw_commands.clear(); let mut mesh = Mesh::new(); - let mut current_img = None; + // TODO: this could be removed entirely if the draw call just used both textures + // however this allows for flexibility if we want to interleave other draw calls later + enum State { + Image, + Plain, + }; + + let mut current_state = State::Plain; let window_scizzor = default_scissor(renderer); let mut current_scizzor = window_scizzor; @@ -314,9 +337,10 @@ impl Ui { // `Plain` state. macro_rules! switch_to_plain_state { () => { - if let Some(image_id) = current_img.take() { - self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)); + if let State::Image = current_state { + self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap())); mesh.clear(); + current_state = State::Plain; } }; } @@ -324,7 +348,7 @@ impl Ui { let p_scale_factor = self.scale.scale_factor_physical(); while let Some(prim) = primitives.next() { - let Primitive {kind, scizzor, id, rect} = prim; + let Primitive {kind, scizzor, id: _id, rect} = prim; // Check for a change in the scizzor let new_scizzor = { @@ -348,12 +372,12 @@ impl Ui { }; if new_scizzor != current_scizzor { // Finish the current command - match current_img.take() { - None => - self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())), - Some(image_id) => - self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)), - } + self.draw_commands.push(match current_state { + State::Plain => + DrawCommand::plain(renderer.create_model(&mesh).unwrap()), + State::Image => + DrawCommand::image(renderer.create_model(&mesh).unwrap()), + }); mesh.clear(); // Update the scizzor and produce a command. @@ -375,52 +399,64 @@ impl Ui { use conrod_core::render::PrimitiveKind; match kind { PrimitiveKind::Image { image_id, color, source_rect } => { + let graphic_id = self.image_map.get(&image_id).expect("Image does not exist in image map"); + let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex(); - // Switch to the `Image` state for this image if we're not in it already. - let new_image_id = image_id; - match current_img { - // If we're already in the drawing mode for this image, we're done. - Some(image_id) if image_id == new_image_id => (), - // If we were in the `Plain` drawing state, switch to Image drawing state. - None => { - self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())); - mesh.clear(); - current_img = Some(new_image_id); - } - // If we were drawing a different image, switch state to draw *this* image. - Some(image_id) => { - self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)); - mesh.clear(); - current_img = Some(new_image_id); - } + match graphic_cache.get_graphic(*graphic_id) { + Some(Graphic::Blank) | None => continue, + _ => {} } - let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa()); + // Switch to the `Image` state for this image if we're not in it already. + if let State::Plain = current_state { + self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())); + mesh.clear(); + current_state = State::Image; + } - // Transform the source rectangle into uv coordinates - let (image_w, image_h) = self.image_map - .get(&image_id) - .expect("Image does not exist in image map") - .get_dimensions() - .map(|e| e as f64) - .into_tuple(); - let (uv_l, uv_r, uv_t, uv_b) = match source_rect { - Some(src_rect) => { - let (l, r, b, t) = src_rect.l_r_b_t(); - ((l / image_w) as f32, - (r / image_w) as f32, - (b / image_h) as f32, - (t / image_h) as f32) + let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into()); + + + let resolution = Vec2::new( + (rect.w() * p_scale_factor) as u16, + (rect.h() * p_scale_factor) as u16, + ); + // Transform the source rectangle into uv coordinate + // TODO: make sure this is right + let source_aabr = { + let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0);/*match source_rect { + Some(src_rect) => { + let (l, r, b, t) = src_rect.l_r_b_t(); + ((l / image_w) as f32, + (r / image_w) as f32, + (b / image_h) as f32, + (t / image_h) as f32) + } + None => (0.0, 1.0, 0.0, 1.0), + };*/ + Aabr { + min: Vec2::new(uv_l, uv_b), + max: Vec2::new(uv_r, uv_t), } - None => (0.0, 1.0, 0.0, 1.0), }; - let uv = Aabr { - min: Vec2::new(uv_l, uv_b), - max: Vec2::new(uv_r, uv_t), + let (cache_w, cache_h) = cache_tex.get_dimensions().map(|e| e as f32).into_tuple(); + + // Cache graphic at particular resolution + let uv_aabr = match graphic_cache.cache_res(*graphic_id, resolution, source_aabr, |aabr, data| { + let offset = aabr.min.into_array(); + let size = aabr.size().into_array(); + renderer.update_texture(cache_tex, offset, size, &data); + }) { + Some(aabr) => Aabr { + min: Vec2::new(aabr.min.x as f32 / cache_w, aabr.max.y as f32 / cache_h), + max: Vec2::new(aabr.max.x as f32 / cache_w, aabr.min.y as f32 / cache_h), + }, + None => continue, }; + mesh.push_quad(create_ui_quad( gl_aabr(rect), - uv, + uv_aabr, color, UiMode::Image, )); @@ -449,7 +485,7 @@ impl Ui { renderer.update_texture(cache_tex, offset, size, &new_data); }).unwrap(); - let color = srgb_to_linear(color.to_fsa()); + let color = srgb_to_linear(color.to_fsa().into()); for g in positioned_glyphs { if let Ok(Some((uv_rect, screen_rect))) = glyph_cache.rect_for(font_id.index(), g) { @@ -477,7 +513,7 @@ impl Ui { } } PrimitiveKind::Rectangle { color } => { - let color = srgb_to_linear(color.to_fsa()); + let color = srgb_to_linear(color.to_fsa().into()); // Don't draw a transparent rectangle if color[3] == 0.0 { continue; @@ -497,7 +533,7 @@ impl Ui { } PrimitiveKind::TrianglesSingleColor { color, triangles } => { // Don't draw transparent triangle or switch state if there are actually no triangles - let color: [f32; 4] = srgb_to_linear(color.into()); + let color = srgb_to_linear(Rgba::from(Into::<[f32; 4]>::into(color))); if triangles.is_empty() || color[3] == 0.0 { continue; } @@ -529,24 +565,27 @@ impl Ui { } _ => {} - // TODO: Add these - //PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);} + // TODO: Add this //PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);} + // Other uneeded for now + //PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);} } } // Enter the final command - match current_img { - None => - self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap())), - Some(image_id) => - self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap(), image_id)), - } + self.draw_commands.push(match current_state { + State::Plain => + DrawCommand::plain(renderer.create_model(&mesh).unwrap()), + State::Image => + DrawCommand::image(renderer.create_model(&mesh).unwrap()), + }); // Handle window resizing if let Some(new_dims) = self.window_resized.take() { self.scale.window_resized(new_dims, renderer); let (w, h) = self.scale.scaled_window_size().into_tuple(); self.ui.handle_event(Input::Resize(w, h)); + self.cache.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4)); + // TODO: probably need to resize glyph cache, see conrod's gfx backend for reference } } } @@ -560,8 +599,8 @@ impl Ui { } DrawCommand::Draw { kind, model } => { let tex = match kind { - DrawKind::Image(image_id) => { - self.image_map.get(&image_id).expect("Image does not exist in image map") + DrawKind::Image => { + self.cache.graphic_cache_tex() } DrawKind::Plain => { self.cache.glyph_cache_tex() @@ -580,16 +619,4 @@ fn default_scissor(renderer: &mut Renderer) -> Aabr { min: Vec2 { x: 0, y: 0 }, max: Vec2 { x: screen_w, y: screen_h } } -} - -fn srgb_to_linear(color: [f32; 4]) -> [f32; 4] { - fn linearize(comp: f32) -> f32 { - if comp <= 0.04045 { - comp / 12.92 - } else { - ((comp + 0.055) / 1.055).powf(2.4) - } - } - - [linearize(color[0]), linearize(color[1]), linearize(color[2]), color[3]] -} +} \ No newline at end of file diff --git a/voxygen/src/ui/util.rs b/voxygen/src/ui/util.rs new file mode 100644 index 0000000000..6359ddd8dd --- /dev/null +++ b/voxygen/src/ui/util.rs @@ -0,0 +1,36 @@ +use vek::*; + +#[inline(always)] +pub fn srgb_to_linear(c: Rgba) -> Rgba { + #[inline(always)] + fn to_linear(x: f32) -> f32 { + if x <= 0.04045 { + x / 12.92 + } else { + ((x + 0.055) / 1.055).powf(2.4) + } + } + Rgba { + r: to_linear(c.r), + g: to_linear(c.g), + b: to_linear(c.b), + a: c.a, + } +} +#[inline(always)] +pub fn linear_to_srgb(c: Rgba) -> Rgba { + #[inline(always)] + fn to_srgb(x: f32) -> f32 { + if x <= 0.0031308 { + x * 12.92 + } else { + x.powf(1.0 / 2.4) * 1.055 - 0.055 + } + } + Rgba { + r: to_srgb(c.r), + g: to_srgb(c.g), + b: to_srgb(c.b), + a: c.a, + } +}