Base of ui system
This commit is contained in:
parent
72e27968eb
commit
1ab2683a53
|
@ -7,6 +7,7 @@ dependencies = [
|
||||||
"glfw 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glfw 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"image 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"image 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -21,7 +22,7 @@ name = "advapi32-sys"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ name = "bzip2-sys"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -96,11 +97,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "gcc"
|
||||||
version = "0.3.13"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -137,12 +138,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"glfw-sys 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glfw-sys"
|
||||||
|
version = "3.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -200,7 +207,7 @@ name = "kernel32-sys"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -263,7 +270,7 @@ name = "miniz-sys"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -274,7 +281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -310,7 +317,7 @@ name = "openssl-sys"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -352,7 +359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -424,7 +431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -453,7 +460,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -14,6 +14,7 @@ flate2 = "0.2.9"
|
||||||
zip = "0.1.12"
|
zip = "0.1.12"
|
||||||
image = "0.3.12"
|
image = "0.3.12"
|
||||||
time = "0.1.32"
|
time = "0.1.32"
|
||||||
|
rand = "0.3.11"
|
||||||
|
|
||||||
[dependencies.steven_gl]
|
[dependencies.steven_gl]
|
||||||
path = "./gl"
|
path = "./gl"
|
||||||
|
|
|
@ -17,17 +17,15 @@ struct SHA_CTX {
|
||||||
num: libc::c_uint
|
num: libc::c_uint
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
enum RSA{}
|
||||||
struct RSA;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[allow(non_camel_case_types)]
|
||||||
struct EVP_CIPHER_CTX;
|
enum EVP_CIPHER_CTX{}
|
||||||
|
|
||||||
#[repr(C)]
|
#[allow(non_camel_case_types)]
|
||||||
struct EVP_CIPHER;
|
enum EVP_CIPHER{}
|
||||||
|
|
||||||
#[repr(C)]
|
enum ENGINE{}
|
||||||
struct ENGINE;
|
|
||||||
|
|
||||||
const RSA_PKCS1_PADDING : libc::c_int = 1;
|
const RSA_PKCS1_PADDING : libc::c_int = 1;
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,18 @@ pub fn active_texture(id: u32) {
|
||||||
unsafe { gl::ActiveTexture(gl::TEXTURE0 + id); }
|
unsafe { gl::ActiveTexture(gl::TEXTURE0 + id); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Factor is used in blending
|
||||||
|
pub type Factor = u32;
|
||||||
|
pub const SRC_ALPHA: Factor = gl::SRC_ALPHA;
|
||||||
|
pub const ONE_MINUS_SRC_ALPHA: Factor = gl::ONE_MINUS_SRC_ALPHA;
|
||||||
|
pub const ONE_FACTOR: Factor = gl::ONE;
|
||||||
|
pub const ZERO_FACTOR: Factor = gl::ZERO;
|
||||||
|
|
||||||
|
/// Sets the factors to be used when blending.
|
||||||
|
pub fn blend_func(s_factor: Factor, d_factor: Factor) {
|
||||||
|
unsafe { gl::BlendFunc(s_factor, d_factor); }
|
||||||
|
}
|
||||||
|
|
||||||
/// Type is a type of data used by various operations.
|
/// Type is a type of data used by various operations.
|
||||||
pub type Type = u32;
|
pub type Type = u32;
|
||||||
pub const UNSIGNED_BYTE: Type = gl::UNSIGNED_BYTE;
|
pub const UNSIGNED_BYTE: Type = gl::UNSIGNED_BYTE;
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub mod gl;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
extern crate glfw;
|
extern crate glfw;
|
||||||
extern crate image;
|
extern crate image;
|
||||||
|
@ -30,6 +31,7 @@ extern crate serde_json;
|
||||||
extern crate steven_openssl as openssl;
|
extern crate steven_openssl as openssl;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate flate2;
|
extern crate flate2;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use glfw::{Action, Context, Key};
|
use glfw::{Action, Context, Key};
|
||||||
|
@ -56,6 +58,7 @@ fn main() {
|
||||||
glfw.set_swap_interval(1);
|
glfw.set_swap_interval(1);
|
||||||
|
|
||||||
let mut renderer = render::Renderer::new(resource_manager.clone());
|
let mut renderer = render::Renderer::new(resource_manager.clone());
|
||||||
|
let mut ui_container = ui::Container::new();
|
||||||
|
|
||||||
let mut last_frame = time::now();
|
let mut last_frame = time::now();
|
||||||
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
|
||||||
|
@ -68,6 +71,7 @@ fn main() {
|
||||||
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
|
||||||
|
|
||||||
let (width, height) = window.get_framebuffer_size();
|
let (width, height) = window.get_framebuffer_size();
|
||||||
|
ui_container.tick(&mut renderer, delta, width as f64, height as f64);
|
||||||
renderer.tick(delta, width as u32, height as u32);
|
renderer.tick(delta, width as u32, height as u32);
|
||||||
|
|
||||||
window.swap_buffers();
|
window.swap_buffers();
|
||||||
|
|
|
@ -998,7 +998,11 @@ impl Serializable for MapIcon {
|
||||||
|
|
||||||
impl Default for MapIcon {
|
impl Default for MapIcon {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MapIcon { .. Default::default() }
|
MapIcon {
|
||||||
|
direction_type: 0,
|
||||||
|
x: 0,
|
||||||
|
z: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,15 +33,13 @@ pub struct Renderer {
|
||||||
resources: Arc<RwLock<resources::Manager>>,
|
resources: Arc<RwLock<resources::Manager>>,
|
||||||
textures: Arc<RwLock<TextureManager>>,
|
textures: Arc<RwLock<TextureManager>>,
|
||||||
glsl: glsl::Registry,
|
glsl: glsl::Registry,
|
||||||
ui: ui::UIState,
|
pub ui: ui::UIState,
|
||||||
|
|
||||||
gl_texture: gl::Texture,
|
gl_texture: gl::Texture,
|
||||||
texture_layers: usize,
|
texture_layers: usize,
|
||||||
|
|
||||||
last_width: u32,
|
last_width: u32,
|
||||||
last_height: u32,
|
last_height: u32,
|
||||||
|
|
||||||
temp_rot: f64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
|
@ -71,8 +69,6 @@ impl Renderer {
|
||||||
texture_layers: 1,
|
texture_layers: 1,
|
||||||
last_width: 0,
|
last_width: 0,
|
||||||
last_height: 0,
|
last_height: 0,
|
||||||
|
|
||||||
temp_rot: 0.0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,19 +96,6 @@ impl Renderer {
|
||||||
gl::clear_color(14.0/255.0, 48.0/255.0, 92.0/255.0, 1.0);
|
gl::clear_color(14.0/255.0, 48.0/255.0, 92.0/255.0, 1.0);
|
||||||
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
|
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
|
||||||
|
|
||||||
let test = self.ui.new_text("Hello world", 10.0, 10.0, 255, 255, 255);
|
|
||||||
let data = test.bytes(width as f64, height as f64);
|
|
||||||
self.ui.add_bytes(&data);
|
|
||||||
|
|
||||||
let test = self.ui.new_text("Font rendering is complete! (ish)", 10.0, 30.0, 0, 255, 0);
|
|
||||||
let data = test.bytes(width as f64, height as f64);
|
|
||||||
self.ui.add_bytes(&data);
|
|
||||||
|
|
||||||
self.temp_rot += delta * 0.05;
|
|
||||||
let test = self.ui.new_text_rotated("Yay! Progress!", 150.0, 150.0, 1.0, 1.0, self.temp_rot, 255, 0, 0);
|
|
||||||
let data = test.bytes(width as f64, height as f64);
|
|
||||||
self.ui.add_bytes(&data);
|
|
||||||
|
|
||||||
self.ui.tick(width, height);
|
self.ui.tick(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,7 @@ impl UIState {
|
||||||
gl::clear(gl::ClearFlags::Depth);
|
gl::clear(gl::ClearFlags::Depth);
|
||||||
gl::depth_func(gl::LESS_OR_EQUAL);
|
gl::depth_func(gl::LESS_OR_EQUAL);
|
||||||
gl::enable(gl::BLEND);
|
gl::enable(gl::BLEND);
|
||||||
|
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
self.shader.use_program();
|
self.shader.use_program();
|
||||||
self.s_texture.set_int(0);
|
self.s_texture.set_int(0);
|
||||||
|
|
370
src/ui/mod.rs
370
src/ui/mod.rs
|
@ -11,3 +11,373 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use rand;
|
||||||
|
use render;
|
||||||
|
|
||||||
|
const SCALED_WIDTH: f64 = 854.0;
|
||||||
|
const SCALED_HEIGHT: f64 = 480.0;
|
||||||
|
|
||||||
|
pub enum Element {
|
||||||
|
Image(Image),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element {
|
||||||
|
fn should_draw(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => img.should_draw,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_parent(&self) -> Option<ElementRefInner> {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => img.parent,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_attachment(&self) -> (VAttach, HAttach) {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => (img.v_attach, img.h_attach),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_offset(&self) -> (f64, f64) {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => (img.x, img.y),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_size(&self) -> (f64, f64) {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => (img.width, img.height),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Element::Image(ref img) => img.dirty,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dirty(&mut self, val: bool) {
|
||||||
|
match self {
|
||||||
|
&mut Element::Image(ref mut img) => img.dirty = val,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) {
|
||||||
|
match self {
|
||||||
|
&mut Element::Image(ref mut img) => img.draw(renderer, r, width, height, delta),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Mode {
|
||||||
|
Scaled,
|
||||||
|
Unscaled(f64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum VAttach {
|
||||||
|
Top,
|
||||||
|
Middle,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum HAttach {
|
||||||
|
Left,
|
||||||
|
Center,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Region {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
w: f64,
|
||||||
|
h: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Region {
|
||||||
|
fn intersects(&self, o: &Region) -> bool {
|
||||||
|
!(self.x+self.w < o.x ||
|
||||||
|
self.x > o.x+o.w ||
|
||||||
|
self.y+self.h < o.y ||
|
||||||
|
self.y > o.y+o.h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reference to an element currently attached to a
|
||||||
|
/// container.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct ElementRef<T> {
|
||||||
|
inner: ElementRefInner,
|
||||||
|
ty: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
|
struct ElementRefInner {
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT};
|
||||||
|
|
||||||
|
pub struct Container {
|
||||||
|
pub mode: Mode,
|
||||||
|
elements: HashMap<ElementRefInner, Element>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Container {
|
||||||
|
pub fn new() -> Container {
|
||||||
|
Container {
|
||||||
|
mode: Mode::Scaled,
|
||||||
|
elements: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add<T: UIElement>(&mut self, e: T) -> ElementRef<T> {
|
||||||
|
let mut r = ElementRefInner{index: rand::random()};
|
||||||
|
while self.elements.contains_key(&r) {
|
||||||
|
r = ElementRefInner{index: rand::random()};
|
||||||
|
}
|
||||||
|
self.elements.insert(r, e.wrap());
|
||||||
|
ElementRef{inner: r, ty: PhantomData}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<T: UIElement>(&self, r: &ElementRef<T>) -> &T {
|
||||||
|
T::unwrap_ref(self.elements.get(&r.inner).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut<T: UIElement>(&mut self, r: &ElementRef<T>) -> &mut T {
|
||||||
|
T::unwrap_ref_mut(self.elements.get_mut(&r.inner).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove<T: UIElement>(&mut self, r: &ElementRef<T>) {
|
||||||
|
self.elements.remove(&r.inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self, renderer: &mut render::Renderer, delta: f64, width: f64, height: f64) {
|
||||||
|
let (sw, sh) = match self.mode {
|
||||||
|
Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height),
|
||||||
|
Mode::Unscaled(scale) => (scale, scale),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Borrow rules seem to prevent us from doing this in the first pass
|
||||||
|
// so we split it.
|
||||||
|
let regions = self.collect_elements(sw, sh);
|
||||||
|
for (re, e) in &mut self.elements {
|
||||||
|
if !e.should_draw() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(&(ref r, ref dirty)) = regions.get(re) {
|
||||||
|
e.set_dirty(*dirty);
|
||||||
|
e.draw(renderer, r, width, height, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_elements(&self, sw: f64, sh: f64) -> HashMap<ElementRefInner, (Region, bool)> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
for (re, e) in &self.elements {
|
||||||
|
if !e.should_draw() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let r = self.get_draw_region(e, sw, sh);
|
||||||
|
if r.intersects(&SCREEN) {
|
||||||
|
// Mark this as dirty if any of its
|
||||||
|
// parents are dirty too.
|
||||||
|
let mut dirty = e.is_dirty();
|
||||||
|
let mut parent = e.get_parent();
|
||||||
|
while !dirty && parent.is_some() {
|
||||||
|
let p = self.elements.get(&parent.unwrap()).unwrap();
|
||||||
|
dirty = p.is_dirty();
|
||||||
|
parent = p.get_parent();
|
||||||
|
}
|
||||||
|
map.insert(*re, (r, dirty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_draw_region(&self, e: &Element, sw: f64, sh: f64) -> Region {
|
||||||
|
let super_region = match e.get_parent() {
|
||||||
|
Some(ref p) => self.get_draw_region(self.elements.get(p).unwrap(), sw, sh),
|
||||||
|
None => SCREEN,
|
||||||
|
};
|
||||||
|
let mut r = Region{x:0.0,y:0.0,w:0.0,h:0.0};
|
||||||
|
let (w, h) = e.get_size();
|
||||||
|
let (ox, oy) = e.get_offset();
|
||||||
|
r.w = w * sw;
|
||||||
|
r.h = h * sh;
|
||||||
|
let (v_attach, h_attach) = e.get_attachment();
|
||||||
|
match h_attach {
|
||||||
|
HAttach::Left => r.x = ox * sw,
|
||||||
|
HAttach::Center => r.x = (super_region.w / 2.0) - (r.w / 2.0) + ox * sw,
|
||||||
|
HAttach::Right => r.x = super_region.w - ox * sw - r.w,
|
||||||
|
}
|
||||||
|
match v_attach {
|
||||||
|
VAttach::Top => r.y = oy * sh,
|
||||||
|
VAttach::Middle => r.y = (super_region.h / 2.0) - (r.h / 2.0) + oy * sh,
|
||||||
|
VAttach::Bottom => r.y = super_region.h - oy * sh - r.h,
|
||||||
|
}
|
||||||
|
r.x += super_region.x;
|
||||||
|
r.y += super_region.y;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UIElement {
|
||||||
|
fn wrap(self) -> Element;
|
||||||
|
fn unwrap_ref<'a>(&'a Element) -> &'a Self;
|
||||||
|
fn unwrap_ref_mut<'a>(&'a mut Element) -> &'a mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! lazy_field {
|
||||||
|
($name:ident, $t:ty, $get:ident, $set:ident) => (
|
||||||
|
pub fn $get(&self) -> $t {
|
||||||
|
self.$name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn $set(&mut self, val: $t) {
|
||||||
|
if self.$name != val {
|
||||||
|
self.$name = val;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Image {
|
||||||
|
dirty: bool,
|
||||||
|
data: Vec<u8>,
|
||||||
|
|
||||||
|
parent: Option<ElementRefInner>,
|
||||||
|
should_draw: bool,
|
||||||
|
texture: render::Texture,
|
||||||
|
layer: isize,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
width: f64,
|
||||||
|
height: f64,
|
||||||
|
v_attach: VAttach,
|
||||||
|
h_attach: HAttach,
|
||||||
|
|
||||||
|
t_x: f64,
|
||||||
|
t_y: f64,
|
||||||
|
t_width: f64,
|
||||||
|
t_height: f64,
|
||||||
|
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn new(texture: render::Texture, x: f64, y: f64, w: f64, h: f64, t_x: f64, t_y: f64, t_width: f64, t_height: f64, r: u8, g: u8, b: u8) -> Image {
|
||||||
|
Image {
|
||||||
|
dirty: true,
|
||||||
|
data: Vec::new(),
|
||||||
|
|
||||||
|
parent: None,
|
||||||
|
should_draw: true,
|
||||||
|
texture: texture,
|
||||||
|
layer: 0,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: w,
|
||||||
|
height: h,
|
||||||
|
v_attach: VAttach::Top,
|
||||||
|
h_attach: HAttach::Left,
|
||||||
|
|
||||||
|
t_x: t_x,
|
||||||
|
t_y: t_y,
|
||||||
|
t_width: t_width,
|
||||||
|
t_height: t_height,
|
||||||
|
|
||||||
|
r: r,
|
||||||
|
g: g,
|
||||||
|
b: b,
|
||||||
|
a: 255,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) {
|
||||||
|
if self.dirty {
|
||||||
|
self.dirty = false;
|
||||||
|
self.texture = renderer.check_texture(self.texture.clone());
|
||||||
|
let mut e = render::ui::UIElement::new(&self.texture, r.x, r.y, r.w, r.h, self.t_x, self.t_y, self.t_width, self.t_height);
|
||||||
|
e.r = self.r;
|
||||||
|
e.g = self.g;
|
||||||
|
e.b = self.b;
|
||||||
|
e.a = self.a;
|
||||||
|
e.layer = self.layer;
|
||||||
|
self.data = e.bytes(width, height);
|
||||||
|
}
|
||||||
|
renderer.ui.add_bytes(&self.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_parent<T: UIElement>(&mut self, other: ElementRef<T>) {
|
||||||
|
self.parent = Some(other.inner);
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_texture(&self) -> render::Texture {
|
||||||
|
self.texture.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_texture(&mut self, val: render::Texture) {
|
||||||
|
self.texture = val;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_field!(layer, isize, get_layer, set_layer);
|
||||||
|
lazy_field!(x, f64, get_x, set_x);
|
||||||
|
lazy_field!(y, f64, get_y, set_y);
|
||||||
|
lazy_field!(width, f64, get_width, set_width);
|
||||||
|
lazy_field!(height, f64, get_height, set_height);
|
||||||
|
lazy_field!(v_attach, VAttach, get_v_attach, set_v_attach);
|
||||||
|
lazy_field!(h_attach, HAttach, get_h_attach, set_h_attach);
|
||||||
|
|
||||||
|
lazy_field!(t_x, f64, get_t_x, set_t_x);
|
||||||
|
lazy_field!(t_y, f64, get_t_y, set_t_y);
|
||||||
|
lazy_field!(t_width, f64, get_t_width, set_t_width);
|
||||||
|
lazy_field!(t_height, f64, get_t_height, set_t_height);
|
||||||
|
|
||||||
|
lazy_field!(r, u8, get_r, set_r);
|
||||||
|
lazy_field!(g, u8, get_g, set_g);
|
||||||
|
lazy_field!(b, u8, get_b, set_b);
|
||||||
|
lazy_field!(a, u8, get_a, set_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UIElement for Image {
|
||||||
|
fn wrap(self) -> Element {
|
||||||
|
Element::Image(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_ref<'a>(e: &'a Element) -> &'a Image {
|
||||||
|
match e {
|
||||||
|
&Element::Image(ref val) => val,
|
||||||
|
_ => panic!("Incorrect type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Image {
|
||||||
|
match e {
|
||||||
|
&mut Element::Image(ref mut val) => val,
|
||||||
|
_ => panic!("Incorrect type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue