From 1ab2683a5322e21e9d8143470da43d5766205a81 Mon Sep 17 00:00:00 2001 From: Thinkofdeath Date: Fri, 18 Sep 2015 22:02:08 +0100 Subject: [PATCH] Base of ui system --- Cargo.lock | 29 ++-- Cargo.toml | 1 + openssl/src/lib.rs | 14 +- src/gl/mod.rs | 12 ++ src/main.rs | 4 + src/protocol/packet.rs | 6 +- src/render/mod.rs | 19 +-- src/render/ui.rs | 1 + src/ui/mod.rs | 372 ++++++++++++++++++++++++++++++++++++++++- 9 files changed, 419 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7938d1f..795aa5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ dependencies = [ "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)", "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)", "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)", @@ -21,7 +22,7 @@ name = "advapi32-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", ] @@ -49,7 +50,7 @@ name = "bzip2-sys" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", ] @@ -96,11 +97,11 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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]] @@ -137,12 +138,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", + "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)", "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)", "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]] name = "glob" version = "0.2.10" @@ -200,7 +207,7 @@ name = "kernel32-sys" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", ] @@ -263,7 +270,7 @@ name = "miniz-sys" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", ] @@ -274,7 +281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", - "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]] @@ -310,7 +317,7 @@ name = "openssl-sys" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", "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)", @@ -352,7 +359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", - "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]] @@ -424,7 +431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", - "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]] @@ -453,7 +460,7 @@ dependencies = [ [[package]] name = "winapi" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] diff --git a/Cargo.toml b/Cargo.toml index 471bbda..51d5a8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ flate2 = "0.2.9" zip = "0.1.12" image = "0.3.12" time = "0.1.32" +rand = "0.3.11" [dependencies.steven_gl] path = "./gl" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index ee46955..8b30da4 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -17,17 +17,15 @@ struct SHA_CTX { num: libc::c_uint } -#[repr(C)] -struct RSA; +enum RSA{} -#[repr(C)] -struct EVP_CIPHER_CTX; +#[allow(non_camel_case_types)] +enum EVP_CIPHER_CTX{} -#[repr(C)] -struct EVP_CIPHER; +#[allow(non_camel_case_types)] +enum EVP_CIPHER{} -#[repr(C)] -struct ENGINE; +enum ENGINE{} const RSA_PKCS1_PADDING : libc::c_int = 1; diff --git a/src/gl/mod.rs b/src/gl/mod.rs index e8c5161..08d23f2 100644 --- a/src/gl/mod.rs +++ b/src/gl/mod.rs @@ -129,6 +129,18 @@ pub fn active_texture(id: u32) { 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. pub type Type = u32; pub const UNSIGNED_BYTE: Type = gl::UNSIGNED_BYTE; diff --git a/src/main.rs b/src/main.rs index 8bee55a..90359b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ pub mod gl; pub mod types; pub mod resources; pub mod render; +pub mod ui; extern crate glfw; extern crate image; @@ -30,6 +31,7 @@ extern crate serde_json; extern crate steven_openssl as openssl; extern crate hyper; extern crate flate2; +extern crate rand; use std::sync::{Arc, RwLock}; use glfw::{Action, Context, Key}; @@ -56,6 +58,7 @@ fn main() { glfw.set_swap_interval(1); let mut renderer = render::Renderer::new(resource_manager.clone()); + let mut ui_container = ui::Container::new(); let mut last_frame = time::now(); 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 (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); window.swap_buffers(); diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index fad09f5..9db8a03 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -998,7 +998,11 @@ impl Serializable for MapIcon { impl Default for MapIcon { fn default() -> Self { - MapIcon { .. Default::default() } + MapIcon { + direction_type: 0, + x: 0, + z: 0, + } } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 337e3d3..ebde8c6 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -33,15 +33,13 @@ pub struct Renderer { resources: Arc>, textures: Arc>, glsl: glsl::Registry, - ui: ui::UIState, + pub ui: ui::UIState, gl_texture: gl::Texture, texture_layers: usize, last_width: u32, last_height: u32, - - temp_rot: f64, } impl Renderer { @@ -71,8 +69,6 @@ impl Renderer { texture_layers: 1, last_width: 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(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); } diff --git a/src/render/ui.rs b/src/render/ui.rs index 7de95f1..5737e12 100644 --- a/src/render/ui.rs +++ b/src/render/ui.rs @@ -141,6 +141,7 @@ impl UIState { gl::clear(gl::ClearFlags::Depth); gl::depth_func(gl::LESS_OR_EQUAL); gl::enable(gl::BLEND); + gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); self.shader.use_program(); self.s_texture.set_int(0); diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 241c8f9..cb0e19c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -10,4 +10,374 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -// limitations under the License. \ No newline at end of file +// 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 { + 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 { + inner: ElementRefInner, + ty: PhantomData, +} + +#[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, +} + +impl Container { + pub fn new() -> Container { + Container { + mode: Mode::Scaled, + elements: HashMap::new(), + } + } + + pub fn add(&mut self, e: T) -> ElementRef { + 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(&self, r: &ElementRef) -> &T { + T::unwrap_ref(self.elements.get(&r.inner).unwrap()) + } + + pub fn get_mut(&mut self, r: &ElementRef) -> &mut T { + T::unwrap_ref_mut(self.elements.get_mut(&r.inner).unwrap()) + } + + pub fn remove(&mut self, r: &ElementRef) { + 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 { + 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, + + parent: Option, + 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(&mut self, other: ElementRef) { + 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"), + } + } +}