diff --git a/src/console/mod.rs b/src/console/mod.rs index 9b36f95..f8efc01 100644 --- a/src/console/mod.rs +++ b/src/console/mod.rs @@ -25,191 +25,219 @@ use render; use format::{Component, TextComponent, Color}; pub struct CVar { - pub name: &'static str, - pub ty: PhantomData, - pub description: &'static str, - pub mutable: bool, - pub serializable: bool, - pub default: &'static Fn() -> T, + pub name: &'static str, + pub ty: PhantomData, + pub description: &'static str, + pub mutable: bool, + pub serializable: bool, + pub default: &'static Fn() -> T, } impl Var for CVar { - fn serialize(&self, val: &Box) -> String { - format!("\"{}\"", val.downcast_ref::().unwrap()) - } + fn serialize(&self, val: &Box) -> String { + format!("\"{}\"", val.downcast_ref::().unwrap()) + } - fn deserialize(&self, input: &String) -> Box { - Box::new((&input[1..input.len() - 1]).to_owned()) - } + fn deserialize(&self, input: &String) -> Box { + Box::new((&input[1..input.len() - 1]).to_owned()) + } - fn description(&self) -> &'static str { self.description } - fn can_serialize(&self) -> bool { self.serializable } + fn description(&self) -> &'static str { + self.description + } + fn can_serialize(&self) -> bool { + self.serializable + } } pub trait Var { - fn serialize(&self, val: &Box) -> String; - fn deserialize(&self, input: &String) -> Box; - fn description(&self) -> &'static str; - fn can_serialize(&self) -> bool; + fn serialize(&self, val: &Box) -> String; + fn deserialize(&self, input: &String) -> Box; + fn description(&self) -> &'static str; + fn can_serialize(&self) -> bool; } pub struct Console { - names: HashMap, - vars: HashMap<&'static str, Box>, - var_values: HashMap<&'static str, Box>, + names: HashMap, + vars: HashMap<&'static str, Box>, + var_values: HashMap<&'static str, Box>, - history: Vec, + history: Vec, - collection: ui::Collection, - active: bool, - position: f64, + collection: ui::Collection, + active: bool, + position: f64, } impl Console { - pub fn new() -> Console { - let mut con = Console { - names: HashMap::new(), - vars: HashMap::new(), - var_values: HashMap::new(), + pub fn new() -> Console { + Console { + names: HashMap::new(), + vars: HashMap::new(), + var_values: HashMap::new(), - history: Vec::with_capacity(200), + history: vec![Component::Text(TextComponent::new("")); 200], - collection: ui::Collection::new(), - active: false, - position: -220.0, - }; - for _ in 0 .. 200 { - con.history.push(Component::Text( - TextComponent::new("") - )); - } - con - } + collection: ui::Collection::new(), + active: false, + position: -220.0, + } + } - pub fn register(&mut self, var: CVar) where CVar : Var { - if self.vars.contains_key(var.name) { - panic!("Key registered twice {}", var.name); - } - self.names.insert(var.name.to_owned(), var.name); - self.var_values.insert(var.name, Box::new((var.default)())); - self.vars.insert(var.name, Box::new(var)); - } + pub fn register(&mut self, var: CVar) + where CVar: Var + { + if self.vars.contains_key(var.name) { + panic!("Key registered twice {}", var.name); + } + self.names.insert(var.name.to_owned(), var.name); + self.var_values.insert(var.name, Box::new((var.default)())); + self.vars.insert(var.name, Box::new(var)); + } - pub fn get(&self, var: CVar) -> &T where CVar : Var { + pub fn get(&self, var: CVar) -> &T + where CVar: Var + { // Should never fail - self.var_values.get(var.name).unwrap().downcast_ref::().unwrap() - } + self.var_values.get(var.name).unwrap().downcast_ref::().unwrap() + } - pub fn set(&mut self, var: CVar, val: T) where CVar : Var { - self.var_values.insert(var.name, Box::new(val)); - self.save_config(); - } + pub fn set(&mut self, var: CVar, val: T) + where CVar: Var + { + self.var_values.insert(var.name, Box::new(val)); + self.save_config(); + } - pub fn is_active(&self) -> bool { - self.active - } + pub fn is_active(&self) -> bool { + self.active + } - pub fn toggle(&mut self) { - self.active = !self.active; - } + pub fn toggle(&mut self) { + self.active = !self.active; + } - pub fn tick(&mut self, ui_container: &mut ui::Container, renderer: &mut render::Renderer, delta: f64, width: f64) { + pub fn tick(&mut self, + ui_container: &mut ui::Container, + renderer: &mut render::Renderer, + delta: f64, + width: f64) { // To make sure the console is always on top it constant removes and readds itself. // Its hacky but the console should never appear for normal users so its not really // a major issue. - self.collection.remove_all(ui_container); - if !self.active && self.position <= -220.0 { - return; - } - if self.active { - if self.position < 0.0 { - self.position += delta * 4.0; - } else { - self.position = 0.0; - } - } else { - if self.position > -220.0 { - self.position -= delta * 4.0; - } else { - self.position = -220.0; - } - } - let w = match ui_container.mode { - ui::Mode::Scaled => width, - ui::Mode::Unscaled(scale) => 854.0 / scale, - }; + self.collection.remove_all(ui_container); + if !self.active && self.position <= -220.0 { + return; + } + if self.active { + if self.position < 0.0 { + self.position += delta * 4.0; + } else { + self.position = 0.0; + } + } else { + if self.position > -220.0 { + self.position -= delta * 4.0; + } else { + self.position = -220.0; + } + } + let w = match ui_container.mode { + ui::Mode::Scaled => width, + ui::Mode::Unscaled(scale) => 854.0 / scale, + }; - let mut background = ui::Image::new( - render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"), - 0.0, self.position, w, 220.0, - 0.0, 0.0, 1.0, 1.0, - 0, 0, 0 - ); - background.set_a(180); - let background = self.collection.add(ui_container.add(background)); + let mut background = + ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), + "steven:solid"), + 0.0, + self.position, + w, + 220.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0, + 0, + 0); + background.set_a(180); + let background = self.collection.add(ui_container.add(background)); - let mut lines = Vec::new(); - let mut offset = 0.0; - for line in self.history.iter().rev() { - if offset >= 210.0 { - break; - } - let mut fmt = ui::Formatted::with_width_limit(renderer, line.clone(), 5.0, 5.0 + offset, w - 1.0); - fmt.set_parent(&background); - fmt.set_v_attach(ui::VAttach::Bottom); - offset += fmt.get_height(); - lines.push(ui_container.add(fmt)); - } - for fmt in lines { - self.collection.add(fmt); - } - } + let mut lines = Vec::new(); + let mut offset = 0.0; + for line in self.history.iter().rev() { + if offset >= 210.0 { + break; + } + let mut fmt = ui::Formatted::with_width_limit(renderer, + line.clone(), + 5.0, + 5.0 + offset, + w - 1.0); + fmt.set_parent(&background); + fmt.set_v_attach(ui::VAttach::Bottom); + offset += fmt.get_height(); + lines.push(ui_container.add(fmt)); + } + for fmt in lines { + self.collection.add(fmt); + } + } - pub fn load_config(&mut self) { - if let Ok(file) = fs::File::open("conf.cfg") { - let reader = BufReader::new(file); - for line in reader.lines() { - let line = line.unwrap(); - if line.starts_with("#") || line.is_empty() { - continue; - } - let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::>(); - let (name, arg) = (&parts[0], &parts[1]); - if let Some(var_name) = self.names.get(name) { - let var = self.vars.get(var_name).unwrap(); - let val = var.deserialize(&arg); - if var.can_serialize() { - self.var_values.insert(var_name, val); - } - } else { - println!("Missing prop"); - } - } - } - } + pub fn load_config(&mut self) { + if let Ok(file) = fs::File::open("conf.cfg") { + let reader = BufReader::new(file); + for line in reader.lines() { + let line = line.unwrap(); + if line.starts_with("#") || line.is_empty() { + continue; + } + let parts = line.splitn(2, ' ').map(|v| v.to_owned()).collect::>(); + let (name, arg) = (&parts[0], &parts[1]); + if let Some(var_name) = self.names.get(name) { + let var = self.vars.get(var_name).unwrap(); + let val = var.deserialize(&arg); + if var.can_serialize() { + self.var_values.insert(var_name, val); + } + } else { + println!("Missing prop"); + } + } + } + } - pub fn save_config(&self) { - let mut file = BufWriter::new(fs::File::create("conf.cfg").unwrap()); - for (name, var) in &self.vars { - if !var.can_serialize() { - continue; - } - for line in var.description().lines() { - write!(file, "# {}\n", line).unwrap(); - } - write!(file, "{} {}\n\n", name, var.serialize(self.var_values.get(name).unwrap())).unwrap(); - } - } + pub fn save_config(&self) { + let mut file = BufWriter::new(fs::File::create("conf.cfg").unwrap()); + for (name, var) in &self.vars { + if !var.can_serialize() { + continue; + } + for line in var.description().lines() { + write!(file, "# {}\n", line).unwrap(); + } + write!(file, + "{} {}\n\n", + name, + var.serialize(self.var_values.get(name).unwrap())) + .unwrap(); + } + } - fn log(&mut self, record: &log::LogRecord) { - let mut file = &record.location().file().replace("\\", "/")[..]; - if let Some(pos) = file.rfind("src/") { - file = &file[pos + 4..]; - } - println!("[{}:{}][{}] {}", file, record.location().line(), record.level(), record.args()); - self.history.remove(0); - let mut msg = TextComponent::new(""); - msg.modifier.extra = Some(vec![ + fn log(&mut self, record: &log::LogRecord) { + let mut file = &record.location().file().replace("\\", "/")[..]; + if let Some(pos) = file.rfind("src/") { + file = &file[pos + 4..]; + } + println!("[{}:{}][{}] {}", + file, + record.location().line(), + record.level(), + record.args()); + self.history.remove(0); + let mut msg = TextComponent::new(""); + msg.modifier.extra = Some(vec![ Component::Text(TextComponent::new("[")), { let mut msg = TextComponent::new(file); @@ -238,34 +266,30 @@ impl Console { Component::Text(TextComponent::new("] ")), Component::Text(TextComponent::new(&format!("{}", record.args()))) ]); - self.history.push(Component::Text( - msg - )); - } + self.history.push(Component::Text(msg)); + } } pub struct ConsoleProxy { - console: Arc>, + console: Arc>, } impl ConsoleProxy { - pub fn new(con: Arc>) -> ConsoleProxy { - ConsoleProxy { - console: con, - } - } + pub fn new(con: Arc>) -> ConsoleProxy { + ConsoleProxy { console: con } + } } impl log::Log for ConsoleProxy { - fn enabled(&self, metadata: &log::LogMetadata) -> bool { - metadata.level() <= log::LogLevel::Trace - } + fn enabled(&self, metadata: &log::LogMetadata) -> bool { + metadata.level() <= log::LogLevel::Trace + } - fn log(&self, record: &log::LogRecord) { - if self.enabled(record.metadata()) { - self.console.lock().unwrap().log(record); - } - } + fn log(&self, record: &log::LogRecord) { + if self.enabled(record.metadata()) { + self.console.lock().unwrap().log(record); + } + } } unsafe impl Send for ConsoleProxy {} diff --git a/src/format.rs b/src/format.rs index 50dc3f9..49c12ba 100644 --- a/src/format.rs +++ b/src/format.rs @@ -18,19 +18,25 @@ use std::mem; #[derive(Debug, Clone)] pub enum Component { - Text(TextComponent) + Text(TextComponent), } impl Component { pub fn from_value(v: &serde_json::Value) -> Self { let mut modifier = Modifier::from_value(v); if let Some(val) = v.as_string() { - Component::Text(TextComponent{text: val.to_owned(), modifier: modifier}) - } else if v.find("text").is_some(){ + Component::Text(TextComponent { + text: val.to_owned(), + modifier: modifier, + }) + } else if v.find("text").is_some() { Component::Text(TextComponent::from_value(v, modifier)) } else { modifier.color = Some(Color::RGB(255, 0, 0)); - Component::Text(TextComponent{text: "UNHANDLED".to_owned(), modifier: modifier}) + Component::Text(TextComponent { + text: "UNHANDLED".to_owned(), + modifier: modifier, + }) } } @@ -49,7 +55,10 @@ impl fmt::Display for Component { impl Default for Component { fn default() -> Self { - Component::Text(TextComponent{text: "".to_owned(), modifier: Default::default()}) + Component::Text(TextComponent { + text: "".to_owned(), + modifier: Default::default(), + }) } } @@ -62,12 +71,10 @@ pub struct Modifier { pub strikethrough: Option, pub obfuscated: Option, pub color: Option, - - // click_event - // hover_event - // insertion } +// TODO: Missing events click/hover/insert + impl Modifier { pub fn from_value(v: &serde_json::Value) -> Self { let mut m = Modifier { @@ -76,7 +83,9 @@ impl Modifier { underlined: v.find("underlined").map_or(Option::None, |v| v.as_boolean()), strikethrough: v.find("strikethrough").map_or(Option::None, |v| v.as_boolean()), obfuscated: v.find("obfuscated").map_or(Option::None, |v| v.as_boolean()), - color: v.find("color").map_or(Option::None, |v| v.as_string()).map(|v| Color::from_string(&v.to_owned())), + color: v.find("color") + .map_or(Option::None, |v| v.as_string()) + .map(|v| Color::from_string(&v.to_owned())), extra: Option::None, }; if let Some(extra) = v.find("extra") { @@ -106,9 +115,7 @@ impl TextComponent { pub fn new(val: &str) -> TextComponent { TextComponent { text: val.to_owned(), - modifier: Modifier { - .. Default::default() - } + modifier: Modifier { ..Default::default() }, } } @@ -154,7 +161,7 @@ pub enum Color { LightPurple, Yellow, White, - RGB(u8, u8, u8) + RGB(u8, u8, u8), } impl fmt::Display for Color { @@ -195,11 +202,7 @@ impl Color { Ok(b) => b, Err(_) => return Color::White, }; - Color::RGB( - r, - g, - b - ) + Color::RGB(r, g, b) } _ => Color::White, } @@ -229,22 +232,22 @@ impl Color { pub fn to_rgb(&self) -> (u8, u8, u8) { match *self { - Color::Black =>(0, 0, 0), - Color::DarkBlue =>(0, 0, 170), - Color::DarkGreen =>(0, 170, 0), - Color::DarkAqua =>(0, 170, 170), - Color::DarkRed =>(170, 0, 0), - Color::DarkPurple =>(170, 0, 170), - Color::Gold =>(255, 170, 0), - Color::Gray =>(170, 170, 170), - Color::DarkGray =>(85, 85, 85), - Color::Blue =>(85, 85, 255), - Color::Green =>(85, 255, 85), - Color::Aqua =>(85, 255, 255), - Color::Red =>(255, 85, 85), - Color::LightPurple =>(255, 85, 255), - Color::Yellow =>(255, 255, 85), - Color::White =>(255, 255, 255), + Color::Black => (0, 0, 0), + Color::DarkBlue => (0, 0, 170), + Color::DarkGreen => (0, 170, 0), + Color::DarkAqua => (0, 170, 170), + Color::DarkRed => (170, 0, 0), + Color::DarkPurple => (170, 0, 170), + Color::Gold => (255, 170, 0), + Color::Gray => (170, 170, 170), + Color::DarkGray => (85, 85, 85), + Color::Blue => (85, 85, 255), + Color::Green => (85, 255, 85), + Color::Aqua => (85, 255, 255), + Color::Red => (255, 85, 85), + Color::LightPurple => (255, 85, 255), + Color::Yellow => (255, 255, 85), + Color::White => (255, 255, 255), Color::RGB(r, g, b) => (r, g, b), } } @@ -264,12 +267,12 @@ fn test_color_from() { } let test = Color::from_string(&"red".to_owned()); match test { - Color::Red => {}, + Color::Red => {} _ => panic!("Wrong type"), } let test = Color::from_string(&"dark_blue".to_owned()); match test { - Color::DarkBlue => {}, + Color::DarkBlue => {} _ => panic!("Wrong type"), } } @@ -297,10 +300,11 @@ pub fn convert_legacy(c: &mut Component) { None => break, }; let color_char = next.1.to_lowercase().next().unwrap(); - current.text = txt.text[last .. i].to_owned(); + current.text = txt.text[last..i].to_owned(); last = next.0 + 1; - let mut modifier = if (color_char >= 'a' && color_char <= 'f') || (color_char >= '0' && color_char <= '9') { + let mut modifier = if (color_char >= 'a' && color_char <= 'f') || + (color_char >= '0' && color_char <= '9') { Default::default() } else { current.modifier.clone() @@ -331,7 +335,7 @@ pub fn convert_legacy(c: &mut Component) { 'm' => modifier.strikethrough = Some(true), 'n' => modifier.underlined = Some(true), 'o' => modifier.italic = Some(true), - 'r' => {}, + 'r' => {} _ => unimplemented!(), } @@ -352,6 +356,6 @@ pub fn convert_legacy(c: &mut Component) { } txt.text = "".to_owned(); } - }, + } } -} \ No newline at end of file +} diff --git a/src/gl/mod.rs b/src/gl/mod.rs index 4c76865..599a04a 100644 --- a/src/gl/mod.rs +++ b/src/gl/mod.rs @@ -48,13 +48,17 @@ pub fn draw_elements(ty: DrawType, count: usize, dty: Type, offset: usize) { /// Sets the size of the viewport of this context. pub fn viewport(x: i32, y: i32, w: i32, h: i32) { - unsafe { gl::Viewport(x, y, w, h); } + unsafe { + gl::Viewport(x, y, w, h); + } } /// Sets the color the color buffer should be cleared to /// when Clear is called with the color flag. pub fn clear_color(r: f32, g: f32, b: f32, a: f32) { - unsafe { gl::ClearColor(r, g, b, a); } + unsafe { + gl::ClearColor(r, g, b, a); + } } /// ClearFlags is a set of flags to mark what should be cleared during @@ -64,7 +68,7 @@ pub enum ClearFlags { Color, /// Marks the depth buffer to be cleared Depth, - Internal(u32) + Internal(u32), } impl ClearFlags { @@ -72,7 +76,7 @@ impl ClearFlags { match self { ClearFlags::Color => gl::COLOR_BUFFER_BIT, ClearFlags::Depth => gl::DEPTH_BUFFER_BIT, - ClearFlags::Internal(val) => val + ClearFlags::Internal(val) => val, } } } @@ -101,7 +105,9 @@ pub const ALWAYS: Func = gl::ALWAYS; pub const EQUAL: Func = gl::EQUAL; pub fn depth_func(f: Func) { - unsafe { gl::DepthFunc(f); } + unsafe { + gl::DepthFunc(f); + } } /// Flag is a setting that can be enabled or disabled on the context. @@ -115,18 +121,24 @@ pub const MULTISAMPLE: Flag = gl::MULTISAMPLE; /// Enables the passed flag. pub fn enable(f: Flag) { - unsafe { gl::Enable(f); } + unsafe { + gl::Enable(f); + } } /// Disables the passed flag. pub fn disable(f: Flag) { - unsafe { gl::Disable(f); } + unsafe { + gl::Disable(f); + } } /// Sets the texture slot with the passed id as the /// currently active one. pub fn active_texture(id: u32) { - unsafe { gl::ActiveTexture(gl::TEXTURE0 + id); } + unsafe { + gl::ActiveTexture(gl::TEXTURE0 + id); + } } /// Factor is used in blending @@ -138,7 +150,9 @@ 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); } + unsafe { + gl::BlendFunc(s_factor, d_factor); + } } // Face specifies a face to act on. @@ -148,7 +162,9 @@ pub const FRONT: Face = gl::FRONT; /// Sets the face to be culled by the gpu. pub fn cull_face(face: Face) { - unsafe { gl::CullFace(face); } + unsafe { + gl::CullFace(face); + } } // FaceDirection is used to specify an order of vertices, normally @@ -219,7 +235,9 @@ impl Texture { // Allocates a new texture. pub fn new() -> Texture { let mut t = Texture(0); - unsafe { gl::GenTextures(1, &mut t.0); } + unsafe { + gl::GenTextures(1, &mut t.0); + } t } @@ -230,25 +248,75 @@ impl Texture { } } - pub fn get_pixels(&self, target: TextureTarget, level: i32, format: TextureFormat, ty: Type, pixels: &mut [u8]) { + pub fn get_pixels(&self, + target: TextureTarget, + level: i32, + format: TextureFormat, + ty: Type, + pixels: &mut [u8]) { unsafe { - gl::GetTexImage(target, level, format, ty, pixels.as_mut_ptr() as *mut gl::types::GLvoid); + gl::GetTexImage(target, + level, + format, + ty, + pixels.as_mut_ptr() as *mut gl::types::GLvoid); } } - pub fn image_3d(&self, target: TextureTarget, level: i32, width: u32, height: u32, depth: u32, format: TextureFormat, ty: Type, pix: &[u8]) { + pub fn image_3d(&self, + target: TextureTarget, + level: i32, + width: u32, + height: u32, + depth: u32, + format: TextureFormat, + ty: Type, + pix: &[u8]) { unsafe { - gl::TexImage3D(target, level, format as i32, width as i32, height as i32, depth as i32, 0, format, ty, pix.as_ptr() as *const gl::types::GLvoid); + gl::TexImage3D(target, + level, + format as i32, + width as i32, + height as i32, + depth as i32, + 0, + format, + ty, + pix.as_ptr() as *const gl::types::GLvoid); } } - pub fn sub_image_3d(&self, target: TextureTarget, level: i32, x: u32, y: u32, z: u32, width: u32, height: u32, depth: u32, format: TextureFormat, ty: Type, pix: &[u8]) { + pub fn sub_image_3d(&self, + target: TextureTarget, + level: i32, + x: u32, + y: u32, + z: u32, + width: u32, + height: u32, + depth: u32, + format: TextureFormat, + ty: Type, + pix: &[u8]) { unsafe { - gl::TexSubImage3D(target, level, x as i32, y as i32, z as i32, width as i32, height as i32, depth as i32, format, ty, pix.as_ptr() as *const gl::types::GLvoid); + gl::TexSubImage3D(target, + level, + x as i32, + y as i32, + z as i32, + width as i32, + height as i32, + depth as i32, + format, + ty, + pix.as_ptr() as *const gl::types::GLvoid); } } - pub fn set_parameter(&self, target: TextureTarget, param: TextureParameter, value: TextureValue) { + pub fn set_parameter(&self, + target: TextureTarget, + param: TextureParameter, + value: TextureValue) { unsafe { gl::TexParameteri(target, param, value); } @@ -257,7 +325,9 @@ impl Texture { impl Drop for Texture { fn drop(&mut self) { - unsafe { gl::DeleteTextures(1, &self.0); } + unsafe { + gl::DeleteTextures(1, &self.0); + } } } @@ -298,17 +368,23 @@ impl Program { } pub fn uniform_location(&self, name: &str) -> Uniform { - Uniform(unsafe { gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) } ) + Uniform(unsafe { + gl::GetUniformLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) + }) } pub fn attribute_location(&self, name: &str) -> Attribute { - Attribute(unsafe { gl::GetAttribLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) }) + Attribute(unsafe { + gl::GetAttribLocation(self.0, ffi::CString::new(name).unwrap().as_ptr()) + }) } } impl Drop for Program { fn drop(&mut self) { - unsafe { gl::DeleteProgram(self.0); } + unsafe { + gl::DeleteProgram(self.0); + } } } @@ -321,7 +397,10 @@ impl Shader { pub fn set_source(&self, src: &str) { unsafe { - gl::ShaderSource(self.0, 1, &ffi::CString::new(src).unwrap().as_ptr(), ptr::null()); + gl::ShaderSource(self.0, + 1, + &ffi::CString::new(src).unwrap().as_ptr(), + ptr::null()); } } @@ -332,8 +411,10 @@ impl Shader { } pub fn get_parameter(&self, param: ShaderParameter) -> i32 { - let mut ret : i32 = 0; - unsafe { gl::GetShaderiv(self.0, param, &mut ret); } + let mut ret: i32 = 0; + unsafe { + gl::GetShaderiv(self.0, param, &mut ret); + } ret } @@ -406,13 +487,22 @@ impl Attribute { pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) { unsafe { - gl::VertexAttribPointer(self.0 as u32, size, ty, normalized as u8, stride, offset as *const gl::types::GLvoid); + gl::VertexAttribPointer(self.0 as u32, + size, + ty, + normalized as u8, + stride, + offset as *const gl::types::GLvoid); } } pub fn vertex_pointer_int(&self, size: i32, ty: Type, stride: i32, offset: i32) { unsafe { - gl::VertexAttribIPointer(self.0 as u32, size, ty, stride, offset as *const gl::types::GLvoid); + gl::VertexAttribIPointer(self.0 as u32, + size, + ty, + stride, + offset as *const gl::types::GLvoid); } } } @@ -426,7 +516,9 @@ impl VertexArray { /// Allocates a new VertexArray. pub fn new() -> VertexArray { let mut va = VertexArray(0); - unsafe { gl::GenVertexArrays(1, &mut va.0); } + unsafe { + gl::GenVertexArrays(1, &mut va.0); + } va } @@ -434,13 +526,17 @@ impl VertexArray { /// means buffers/the format of the buffers etc will be bound to /// this VertexArray. pub fn bind(&self) { - unsafe { gl::BindVertexArray(self.0); } + unsafe { + gl::BindVertexArray(self.0); + } } } impl Drop for VertexArray { fn drop(&mut self) { - unsafe { gl::DeleteVertexArrays(1, &self.0); } + unsafe { + gl::DeleteVertexArrays(1, &self.0); + } self.0 = 0; } } @@ -480,7 +576,9 @@ impl Buffer { /// Allocates a new Buffer. pub fn new() -> Buffer { let mut b = Buffer(0); - unsafe { gl::GenBuffers(1, &mut b.0); } + unsafe { + gl::GenBuffers(1, &mut b.0); + } b } @@ -488,12 +586,17 @@ impl Buffer { /// This will allow it to be the source of operations that act on a buffer /// (Data, Map etc). pub fn bind(&self, target: BufferTarget) { - unsafe { gl::BindBuffer(target, self.0); } + unsafe { + gl::BindBuffer(target, self.0); + } } pub fn set_data(&self, target: BufferTarget, data: &[u8], usage: BufferUsage) { unsafe { - gl::BufferData(target, data.len() as i64, data.as_ptr() as *const gl::types::GLvoid, usage); + gl::BufferData(target, + data.len() as i64, + data.as_ptr() as *const gl::types::GLvoid, + usage); } } @@ -506,7 +609,10 @@ impl Buffer { /// length is valid. pub fn map(&self, target: BufferTarget, access: Access, length: usize) -> MappedBuffer { unsafe { - MappedBuffer{inner: Vec::from_raw_parts(gl::MapBuffer(target, access) as *mut u8, 0, length), target: target} + MappedBuffer { + inner: Vec::from_raw_parts(gl::MapBuffer(target, access) as *mut u8, 0, length), + target: target, + } } } } @@ -540,7 +646,9 @@ impl DerefMut for MappedBuffer { impl Drop for MappedBuffer { fn drop(&mut self) { - unsafe { gl::UnmapBuffer(self.target); } + unsafe { + gl::UnmapBuffer(self.target); + } mem::forget(mem::replace(&mut self.inner, Vec::new())); } } diff --git a/src/item.rs b/src/item.rs index 5f143ad..a6ab829 100644 --- a/src/item.rs +++ b/src/item.rs @@ -13,7 +13,7 @@ // limitations under the License. use nbt; -use protocol::{Serializable}; +use protocol::Serializable; use std::io; use std::io::{Read, Write}; use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; @@ -44,7 +44,7 @@ impl Serializable for Option { if id == -1 { return Ok(None); } - Ok(Some(Stack{ + Ok(Some(Stack { id: id as isize, count: try!(buf.read_u8()) as isize, damage: try!(buf.read_i16::()) as isize, @@ -58,7 +58,7 @@ impl Serializable for Option { try!(buf.write_u8(val.count as u8)); try!(buf.write_i16::(val.damage as i16)); try!(val.tag.write_to(buf)); - }, + } None => try!(buf.write_i16::(-1)), } Result::Ok(()) diff --git a/src/main.rs b/src/main.rs index c1f3a01..b9d27dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,8 +44,8 @@ use std::marker::PhantomData; const CL_BRAND: console::CVar = console::CVar { ty: PhantomData, name: "cl_brand", - description: "cl_brand has the value of the clients current 'brand'. \ - e.g. \"Steven\" or \"Vanilla\"", + description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \ + \"Vanilla\"", mutable: false, serializable: false, default: &|| "steven".to_owned(), @@ -74,22 +74,27 @@ fn main() { log::set_logger(|max_log_level| { max_log_level.set(log::LogLevelFilter::Trace); Box::new(proxy) - }).unwrap(); + }) + .unwrap(); info!("Starting steven"); let resource_manager = Arc::new(RwLock::new(resources::Manager::new())); - { resource_manager.write().unwrap().tick(); } + { + resource_manager.write().unwrap().tick(); + } let mut window = glutin::WindowBuilder::new() - .with_title("Steven".to_string()) - .with_dimensions(854, 480) - .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2))) - .with_gl_profile(glutin::GlProfile::Core) - .with_depth_buffer(24) - .with_stencil_buffer(0) - .with_vsync() - .build().ok().expect("Could not create Glutin window."); + .with_title("Steven".to_string()) + .with_dimensions(854, 480) + .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2))) + .with_gl_profile(glutin::GlProfile::Core) + .with_depth_buffer(24) + .with_stencil_buffer(0) + .with_vsync() + .build() + .ok() + .expect("Could not create Glutin window."); unsafe { window.make_current().ok().expect("Could not set current context."); @@ -116,7 +121,9 @@ fn main() { }; while !game.should_close { - { game.resource_manager.write().unwrap().tick(); } + { + game.resource_manager.write().unwrap().tick(); + } let now = time::now(); let diff = now - last_frame; @@ -125,7 +132,10 @@ fn main() { let (width, height) = window.get_inner_size_pixels().unwrap(); game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container); - game.console.lock().unwrap().tick(&mut ui_container, &mut game.renderer, delta, width as f64); + game.console + .lock() + .unwrap() + .tick(&mut ui_container, &mut game.renderer, delta, width as f64); ui_container.tick(&mut game.renderer, delta, width as f64, height as f64); game.renderer.tick(delta, width, height); @@ -137,7 +147,10 @@ fn main() { } } -fn handle_window_event(window: &glutin::Window, game: &mut Game, ui_container: &mut ui::Container, event: glutin::Event) { +fn handle_window_event(window: &glutin::Window, + game: &mut Game, + ui_container: &mut ui::Container, + event: glutin::Event) { use glutin::{Event, VirtualKeyCode}; match event { Event::Closed => game.should_close = true, @@ -147,34 +160,34 @@ fn handle_window_event(window: &glutin::Window, game: &mut Game, ui_container: & let (width, height) = window.get_inner_size_pixels().unwrap(); ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64); - }, + } Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => { let (x, y) = game.mouse_pos; let (width, height) = window.get_inner_size_pixels().unwrap(); ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64); - }, + } Event::MouseWheel(delta) => { let (x, y) = match delta { glutin::MouseScrollDelta::LineDelta(x, y) => (x, y), - glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y) + glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y), }; game.screen_sys.on_scroll(x as f64, y as f64); - }, + } Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _) => { game.console.lock().unwrap().toggle(); - }, + } Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => { game.console.lock().unwrap().toggle(); - }, + } Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => { println!("Key: {:?} {:?}", key, virt); - }, + } - _ => () + _ => (), } } diff --git a/src/nbt/mod.rs b/src/nbt/mod.rs index 4100448..32d4a64 100644 --- a/src/nbt/mod.rs +++ b/src/nbt/mod.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use std::io; use std::io::{Read, Write}; -use super::protocol::{Serializable}; +use super::protocol::Serializable; use super::protocol; use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; @@ -173,52 +173,53 @@ impl Tag { } fn read_type(id: u8, buf: &mut io::Read) -> Result { - match id { - 0 => unreachable!(), - 1 => Ok(Tag::Byte(try!(buf.read_i8()))), - 2 => Ok(Tag::Short(try!(buf.read_i16::()))), - 3 => Ok(Tag::Int(try!(buf.read_i32::()))), - 4 => Ok(Tag::Long(try!(buf.read_i64::()))), - 5 => Ok(Tag::Float(try!(buf.read_f32::()))), - 6 => Ok(Tag::Double(try!(buf.read_f64::()))), - 7 => Ok(Tag::ByteArray({ - let len : i32 = try!(Serializable::read_from(buf)); - let mut data = Vec::with_capacity(len as usize); - try!(buf.take(len as u64).read_to_end(&mut data)); - data - })), - 8 => Ok(Tag::String(try!(read_string(buf)))), - 9 => { - let mut l = Vec::new(); - let ty = try!(buf.read_u8()); - let len : i32 = try!(Serializable::read_from(buf)); - for _ in 0 .. len { - l.push(try!(Tag::read_type(ty, buf))); - } - Ok(Tag::List(l)) - }, - 10 => { - let mut c = Tag::new_compound(); - loop { - let ty = try!(buf.read_u8()); - if ty == 0 { - break; - } - let name: String = try!(read_string(buf)); - c.put(&name[..], try!(Tag::read_type(ty, buf))); - } - Ok(c) - }, - 11 => Ok(Tag::IntArray({ - let len : i32 = try!(Serializable::read_from(buf)); - let mut data = Vec::with_capacity(len as usize); - for _ in 0 .. len { - data.push(try!(buf.read_i32::())); - } - data - })), - _ => Err(io::Error::new(io::ErrorKind::InvalidData, protocol::Error::Err("invalid tag".to_owned()))), + match id { + 0 => unreachable!(), + 1 => Ok(Tag::Byte(try!(buf.read_i8()))), + 2 => Ok(Tag::Short(try!(buf.read_i16::()))), + 3 => Ok(Tag::Int(try!(buf.read_i32::()))), + 4 => Ok(Tag::Long(try!(buf.read_i64::()))), + 5 => Ok(Tag::Float(try!(buf.read_f32::()))), + 6 => Ok(Tag::Double(try!(buf.read_f64::()))), + 7 => Ok(Tag::ByteArray({ + let len: i32 = try!(Serializable::read_from(buf)); + let mut data = Vec::with_capacity(len as usize); + try!(buf.take(len as u64).read_to_end(&mut data)); + data + })), + 8 => Ok(Tag::String(try!(read_string(buf)))), + 9 => { + let mut l = Vec::new(); + let ty = try!(buf.read_u8()); + let len: i32 = try!(Serializable::read_from(buf)); + for _ in 0..len { + l.push(try!(Tag::read_type(ty, buf))); + } + Ok(Tag::List(l)) } + 10 => { + let mut c = Tag::new_compound(); + loop { + let ty = try!(buf.read_u8()); + if ty == 0 { + break; + } + let name: String = try!(read_string(buf)); + c.put(&name[..], try!(Tag::read_type(ty, buf))); + } + Ok(c) + } + 11 => Ok(Tag::IntArray({ + let len: i32 = try!(Serializable::read_from(buf)); + let mut data = Vec::with_capacity(len as usize); + for _ in 0..len { + data.push(try!(buf.read_i32::())); + } + data + })), + _ => Err(io::Error::new(io::ErrorKind::InvalidData, + protocol::Error::Err("invalid tag".to_owned()))), + } } } @@ -229,7 +230,7 @@ impl Serializable for Tag { fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { match *self { - Tag::End => {}, + Tag::End => {} Tag::Byte(val) => try!(buf.write_i8(val)), Tag::Short(val) => try!(buf.write_i16::(val)), Tag::Int(val) => try!(buf.write_i32::(val)), @@ -239,20 +240,20 @@ impl Serializable for Tag { Tag::ByteArray(ref val) => { try!((val.len() as i32).write_to(buf)); try!(buf.write_all(val)); - }, + } Tag::String(ref val) => try!(write_string(buf, val)), Tag::List(ref val) => { - if val.is_empty() { - try!(buf.write_u8(0)); - try!(buf.write_i32::(0)); - } else { - try!(buf.write_u8(val[0].internal_id())); - try!(buf.write_i32::(val.len() as i32)); - for e in val { - try!(e.write_to(buf)); - } + if val.is_empty() { + try!(buf.write_u8(0)); + try!(buf.write_i32::(0)); + } else { + try!(buf.write_u8(val[0].internal_id())); + try!(buf.write_i32::(val.len() as i32)); + for e in val { + try!(e.write_to(buf)); } - }, + } + } Tag::Compound(ref val) => { for (k, v) in val { try!(v.internal_id().write_to(buf)); @@ -260,19 +261,19 @@ impl Serializable for Tag { try!(v.write_to(buf)); } try!(buf.write_u8(0)); - }, + } Tag::IntArray(ref val) => { try!((val.len() as i32).write_to(buf)); for v in val { try!(v.write_to(buf)); } - }, + } } Result::Ok(()) } } -pub fn write_string(buf: &mut io::Write, s: &String)-> io::Result<()> { +pub fn write_string(buf: &mut io::Write, s: &String) -> io::Result<()> { let data = s.as_bytes(); try!((data.len() as i16).write_to(buf)); buf.write_all(data) diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 25734cf..10f19b1 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -139,7 +139,7 @@ pub trait Serializable: Sized { } impl Serializable for Vec { - fn read_from(buf: &mut io::Read) -> Result , io::Error> { + fn read_from(buf: &mut io::Read) -> Result, io::Error> { let mut v = Vec::new(); try!(buf.read_to_end(&mut v)); Ok(v) @@ -206,7 +206,7 @@ impl Serializable for format::Component { let len = try!(VarInt::read_from(buf)).0; let mut ret = String::new(); try!(buf.take(len as u64).read_to_string(&mut ret)); - let val : serde_json::Value = serde_json::from_str(&ret[..]).unwrap(); + let val: serde_json::Value = serde_json::from_str(&ret[..]).unwrap(); Result::Ok(Self::from_value(&val)) } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { @@ -232,7 +232,11 @@ impl Serializable for bool { Result::Ok(try!(buf.read_u8()) != 0) } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { - try!(buf.write_u8(if *self { 1 } else { 0 })); + try!(buf.write_u8(if *self { + 1 + } else { + 0 + })); Result::Ok(()) } } @@ -321,17 +325,15 @@ impl Serializable for f64 { pub struct UUID(u64, u64); impl Default for UUID { - fn default() -> Self { UUID(0, 0) } + fn default() -> Self { + UUID(0, 0) + } } impl Serializable for UUID { fn read_from(buf: &mut io::Read) -> Result { - Result::Ok( - UUID( - try!(buf.read_u64::()), - try!(buf.read_u64::()), - ) - ) + Result::Ok(UUID(try!(buf.read_u64::()), + try!(buf.read_u64::()))) } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { try!(buf.write_u64::(self.0)); @@ -348,7 +350,7 @@ pub trait Lengthable : Serializable + Copy + Default { pub struct LenPrefixed { len: L, - pub data: Vec + pub data: Vec, } impl LenPrefixed { @@ -362,17 +364,20 @@ impl LenPrefixed { impl Serializable for LenPrefixed { fn read_from(buf: &mut io::Read) -> Result, io::Error> { - let len_data : L = try!(Serializable::read_from(buf)); - let len : usize = len_data.into(); - let mut data : Vec = Vec::with_capacity(len); - for _ in 0 .. len { + let len_data: L = try!(Serializable::read_from(buf)); + let len: usize = len_data.into(); + let mut data: Vec = Vec::with_capacity(len); + for _ in 0..len { data.push(try!(Serializable::read_from(buf))); } - Result::Ok(LenPrefixed{len: len_data, data: data}) + Result::Ok(LenPrefixed { + len: len_data, + data: data, + }) } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { - let len_data : L = L::from(self.data.len()); + let len_data: L = L::from(self.data.len()); try!(len_data.write_to(buf)); let data = &self.data; for val in data { @@ -387,7 +392,7 @@ impl Default for LenPrefixed { fn default() -> Self { LenPrefixed { len: default::Default::default(), - data: default::Default::default() + data: default::Default::default(), } } } @@ -401,7 +406,7 @@ impl fmt::Debug for LenPrefixed { // Optimization pub struct LenPrefixedBytes { len: L, - pub data: Vec + pub data: Vec, } impl LenPrefixedBytes { @@ -415,15 +420,18 @@ impl LenPrefixedBytes { impl Serializable for LenPrefixedBytes { fn read_from(buf: &mut io::Read) -> Result, io::Error> { - let len_data : L = try!(Serializable::read_from(buf)); - let len : usize = len_data.into(); - let mut data : Vec = Vec::with_capacity(len); + let len_data: L = try!(Serializable::read_from(buf)); + let len: usize = len_data.into(); + let mut data: Vec = Vec::with_capacity(len); try!(buf.take(len as u64).read_to_end(&mut data)); - Result::Ok(LenPrefixedBytes{len: len_data, data: data}) + Result::Ok(LenPrefixedBytes { + len: len_data, + data: data, + }) } fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { - let len_data : L = L::from(self.data.len()); + let len_data: L = L::from(self.data.len()); try!(len_data.write_to(buf)); try!(buf.write_all(&self.data[..])); Result::Ok(()) @@ -435,7 +443,7 @@ impl Default for LenPrefixedBytes { fn default() -> Self { LenPrefixedBytes { len: default::Default::default(), - data: default::Default::default() + data: default::Default::default(), } } } @@ -490,9 +498,10 @@ impl Serializable for VarInt { loop { let b = try!(buf.read_u8()) as u32; val |= (b & PART) << (size * 7); - size+=1; + size += 1; if size > 5 { - return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_owned()))) + return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, + Error::Err("VarInt too big".to_owned()))) } if (b & 0x80) == 0 { break @@ -518,7 +527,9 @@ impl Serializable for VarInt { } impl default::Default for VarInt { - fn default() -> VarInt { VarInt(0) } + fn default() -> VarInt { + VarInt(0) + } } impl fmt::Debug for VarInt { @@ -551,9 +562,10 @@ impl Serializable for VarLong { loop { let b = try!(buf.read_u8()) as u64; val |= (b & PART) << (size * 7); - size+=1; + size += 1; if size > 10 { - return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarLong too big".to_owned()))) + return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, + Error::Err("VarLong too big".to_owned()))) } if (b & 0x80) == 0 { break @@ -579,7 +591,9 @@ impl Serializable for VarLong { } impl default::Default for VarLong { - fn default() -> VarLong { VarLong(0) } + fn default() -> VarLong { + VarLong(0) + } } impl fmt::Debug for VarLong { @@ -593,7 +607,7 @@ impl fmt::Debug for VarLong { #[derive(Clone, Copy)] pub enum Direction { Serverbound, - Clientbound + Clientbound, } /// The protocol has multiple 'sub-protocols' or states which control which @@ -603,7 +617,7 @@ pub enum State { Handshaking, Play, Status, - Login + Login, } /// Return for any protocol related error. @@ -614,7 +628,7 @@ pub enum Error { } impl convert::From for Error { - fn from(e : io::Error) -> Error { + fn from(e: io::Error) -> Error { Error::IOError(e) } } @@ -629,10 +643,10 @@ impl ::std::error::Error for Error { } impl ::std::fmt::Display for Error { - fn fmt(&self, f : &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { Error::Err(ref val) => write!(f, "protocol error: {}", val), - Error::IOError(ref e) => e.fmt(f) + Error::IOError(ref e) => e.fmt(f), } } } @@ -647,12 +661,12 @@ pub struct Conn { cipher: Option, compression_threshold: i32, - compression_read: Option>>>, + compression_read: Option>>>, compression_write: Option>>>, } impl Conn { - pub fn new(target: &str) -> Result{ + pub fn new(target: &str) -> Result { // TODO SRV record support let mut parts = target.split(":").collect::>(); let address = if parts.len() == 1 { @@ -680,7 +694,11 @@ impl Conn { try!(VarInt(packet.packet_id()).write_to(&mut buf)); try!(packet.write(&mut buf)); - let mut extra = if self.compression_threshold >= 0 { 1 } else { 0 }; + let mut extra = if self.compression_threshold >= 0 { + 1 + } else { + 0 + }; if self.compression_threshold >= 0 && buf.len() as i32 > self.compression_threshold { extra = 0; let uncompressed_size = buf.len(); @@ -734,11 +752,14 @@ impl Conn { let pos = buf.position() as usize; let ibuf = buf.into_inner(); if ibuf.len() != pos { - return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, had {} bytes left", id, ibuf.len() - pos))) + return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, \ + had {} bytes left", + id, + ibuf.len() - pos))) } Result::Ok(val) - }, - None => Result::Err(Error::Err("missing packet".to_owned())) + } + None => Result::Err(Error::Err("missing packet".to_owned())), } } @@ -749,28 +770,29 @@ impl Conn { pub fn set_compresssion(&mut self, threshold: i32, read: bool) { self.compression_threshold = threshold; if !read { - self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()), flate2::Compression::Default)); + self.compression_write = Some(ZlibEncoder::new(io::Cursor::new(Vec::new()), + flate2::Compression::Default)); } else { self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new()))); } } - pub fn do_status(mut self) -> Result<(Status, time::Duration), Error>{ + pub fn do_status(mut self) -> Result<(Status, time::Duration), Error> { use serde_json::Value; use self::packet::status::serverbound::*; use self::packet::handshake::serverbound::*; use self::packet::Packet; let host = self.host.clone(); let port = self.port; - try!(self.write_packet(Handshake{ + try!(self.write_packet(Handshake { protocol_version: VarInt(SUPPORTED_PROTOCOL), host: host, port: port, next: VarInt(1), })); self.state = State::Status; - - try!(self.write_packet(StatusRequest{empty: ()})); + + try!(self.write_packet(StatusRequest { empty: () })); let status = if let Packet::StatusResponse(res) = try!(self.read_packet()) { res.status @@ -779,7 +801,7 @@ impl Conn { }; let start = time::now(); - try!(self.write_packet(StatusPing{ping: 42})); + try!(self.write_packet(StatusPing { ping: 42 })); if let Packet::StatusPong(_) = try!(self.read_packet()) { } else { @@ -800,17 +822,26 @@ impl Conn { Ok((Status { version: StatusVersion { - name: try!(version.find("name").and_then(Value::as_string).ok_or(invalid_status())).to_owned(), - protocol: try!(version.find("protocol").and_then(Value::as_i64).ok_or(invalid_status())) as i32, + name: try!(version.find("name").and_then(Value::as_string).ok_or(invalid_status())) + .to_owned(), + protocol: try!(version.find("protocol") + .and_then(Value::as_i64) + .ok_or(invalid_status())) as i32, }, players: StatusPlayers { - max: try!(players.find("max").and_then(Value::as_i64).ok_or(invalid_status())) as i32, - online: try!(players.find("online").and_then(Value::as_i64).ok_or(invalid_status())) as i32, - sample: Vec::new(), // TODO + max: try!(players.find("max") + .and_then(Value::as_i64) + .ok_or(invalid_status())) as i32, + online: try!(players.find("online") + .and_then(Value::as_i64) + .ok_or(invalid_status())) as i32, + sample: Vec::new(), /* TODO */ }, - description: format::Component::from_value(try!(val.find("description").ok_or(invalid_status()))), + description: format::Component::from_value(try!(val.find("description") + .ok_or(invalid_status()))), favicon: val.find("favicon").and_then(Value::as_string).map(|v| v.to_owned()), - }, ping)) + }, + ping)) } } @@ -848,11 +879,11 @@ impl Read for Conn { Option::Some(cipher) => { let ret = try!(self.stream.read(buf)); let data = cipher.decrypt(&buf[..ret]); - for i in 0 .. ret { + for i in 0..ret { buf[i] = data[i]; } Ok(ret) - }, + } } } } @@ -865,7 +896,7 @@ impl Write for Conn { let data = cipher.encrypt(buf); try!(self.stream.write_all(&data[..])); Ok(buf.len()) - }, + } } } @@ -901,14 +932,16 @@ pub trait PacketType: Sized { pub fn test() { let mut c = Conn::new("localhost:25565").unwrap(); - c.write_packet(packet::handshake::serverbound::Handshake{ - protocol_version: VarInt(71), - host: "localhost".to_owned(), - port: 25565, - next: VarInt(2), - }).unwrap(); + c.write_packet(packet::handshake::serverbound::Handshake { + protocol_version: VarInt(71), + host: "localhost".to_owned(), + port: 25565, + next: VarInt(2), + }) + .unwrap(); c.state = State::Login; - c.write_packet(packet::login::serverbound::LoginStart{username: "Think".to_owned()}).unwrap(); + c.write_packet(packet::login::serverbound::LoginStart { username: "Think".to_owned() }) + .unwrap(); let packet = match c.read_packet().unwrap() { packet::Packet::EncryptionRequest(val) => val, @@ -921,18 +954,19 @@ pub fn test() { let shared_e = key.encrypt(&shared); let token_e = key.encrypt(&packet.verify_token.data); - let profile = mojang::Profile{ + let profile = mojang::Profile { username: "Think".to_owned(), id: "b1184d43168441cfa2128b9a3df3b6ab".to_owned(), - access_token: "".to_owned() + access_token: "".to_owned(), }; profile.join_server(&packet.server_id, &shared, &packet.public_key.data); - c.write_packet(packet::login::serverbound::EncryptionResponse{ - shared_secret: LenPrefixedBytes::new(shared_e), - verify_token: LenPrefixedBytes::new(token_e), - }).unwrap(); + c.write_packet(packet::login::serverbound::EncryptionResponse { + shared_secret: LenPrefixedBytes::new(shared_e), + verify_token: LenPrefixedBytes::new(token_e), + }) + .unwrap(); let mut read = c.clone(); let mut write = c.clone(); @@ -940,35 +974,39 @@ pub fn test() { read.enable_encyption(&shared, true); write.enable_encyption(&shared, false); - loop { match read.read_packet().unwrap() { - packet::Packet::LoginDisconnect(val) => { - panic!("Discconect {}", val.reason); - }, - packet::Packet::SetInitialCompression(val) => { - read.set_compresssion(val.threshold.0, true); - write.set_compresssion(val.threshold.0, false); - println!("Compression: {}", val.threshold.0) - }, - packet::Packet::LoginSuccess(val) => { - println!("Login: {} {}", val.username, val.uuid); - read.state = State::Play; - write.state = State::Play; - break; + loop { + match read.read_packet().unwrap() { + packet::Packet::LoginDisconnect(val) => { + panic!("Discconect {}", val.reason); + } + packet::Packet::SetInitialCompression(val) => { + read.set_compresssion(val.threshold.0, true); + write.set_compresssion(val.threshold.0, false); + println!("Compression: {}", val.threshold.0) + } + packet::Packet::LoginSuccess(val) => { + println!("Login: {} {}", val.username, val.uuid); + read.state = State::Play; + write.state = State::Play; + break; + } + _ => panic!("Unknown packet"), } - _ => panic!("Unknown packet"), - } } + } let mut first = true; let mut count = 0; - loop { match read.read_packet().unwrap() { + loop { + match read.read_packet().unwrap() { packet::Packet::ServerMessage(val) => println!("MSG: {}", val.message), - packet::Packet::ChunkData(_) => {}, + packet::Packet::ChunkData(_) => {} val => { println!("{:?}", val); if first { - write.write_packet(packet::play::serverbound::ChatMessage{ - message: "Hello world".to_owned(), - }).unwrap(); + write.write_packet(packet::play::serverbound::ChatMessage { + message: "Hello world".to_owned(), + }) + .unwrap(); first = false; } count += 1; @@ -976,7 +1014,8 @@ pub fn test() { break; } } - } } + } + } unimplemented!(); } diff --git a/src/protocol/mojang.rs b/src/protocol/mojang.rs index 542de20..71a21a6 100644 --- a/src/protocol/mojang.rs +++ b/src/protocol/mojang.rs @@ -19,7 +19,7 @@ use hyper; pub struct Profile { pub username: String, pub id: String, - pub access_token: String + pub access_token: String, } const JOIN_URL: &'static str = "https://sessionserver.mojang.com/session/minecraft/join"; @@ -34,7 +34,7 @@ impl Profile { // Mojang uses a hex method which allows for // negatives so we have to account for that. - let negative = hash[0] & 0x80 == 0x80; + let negative = hash[0] & 0x80 == 0x80; if negative { twos_compliment(&mut hash); } @@ -47,17 +47,18 @@ impl Profile { }; let join_msg = serde_json::builder::ObjectBuilder::new() - .insert("accessToken", &self.access_token) - .insert("selectedProfile", &self.id) - .insert("serverId", hash_str) - .unwrap(); + .insert("accessToken", &self.access_token) + .insert("selectedProfile", &self.id) + .insert("serverId", hash_str) + .unwrap(); let join = serde_json::to_string(&join_msg).unwrap(); let client = hyper::Client::new(); let res = client.post(JOIN_URL) - .body(&join) - .header(hyper::header::ContentType("application/json".parse().unwrap())) - .send().unwrap(); + .body(&join) + .header(hyper::header::ContentType("application/json".parse().unwrap())) + .send() + .unwrap(); let ret: serde_json::Value = match serde_json::from_reader(res) { Result::Ok(val) => val, @@ -69,7 +70,7 @@ impl Profile { fn twos_compliment(data: &mut Vec) { let mut carry = true; - for i in (0 .. data.len()).rev() { + for i in (0..data.len()).rev() { data[i] = !data[i]; if carry { carry = data[i] == 0xFF; diff --git a/src/protocol/packet.rs b/src/protocol/packet.rs index 9db8a03..944ada8 100644 --- a/src/protocol/packet.rs +++ b/src/protocol/packet.rs @@ -91,7 +91,7 @@ state_packets!( button: u8 =, action_number: u16 =, mode: u8 =, - clicked_item: Option =, // TODO + clicked_item: Option =, } // CloseWindow is sent when the client closes a window. CloseWindow => 0x07 { @@ -936,7 +936,7 @@ pub struct BlockChangeRecord { impl Serializable for BlockChangeRecord { fn read_from(buf: &mut io::Read) -> Result { - Ok(BlockChangeRecord{ + Ok(BlockChangeRecord { xz: try!(Serializable::read_from(buf)), y: try!(Serializable::read_from(buf)), block_id: try!(Serializable::read_from(buf)), @@ -959,7 +959,7 @@ pub struct ExplosionRecord { impl Serializable for ExplosionRecord { fn read_from(buf: &mut io::Read) -> Result { - Ok(ExplosionRecord{ + Ok(ExplosionRecord { x: try!(Serializable::read_from(buf)), y: try!(Serializable::read_from(buf)), z: try!(Serializable::read_from(buf)), @@ -982,7 +982,7 @@ pub struct MapIcon { impl Serializable for MapIcon { fn read_from(buf: &mut io::Read) -> Result { - Ok(MapIcon{ + Ok(MapIcon { direction_type: try!(Serializable::read_from(buf)), x: try!(Serializable::read_from(buf)), z: try!(Serializable::read_from(buf)), @@ -998,7 +998,7 @@ impl Serializable for MapIcon { impl Default for MapIcon { fn default() -> Self { - MapIcon { + MapIcon { direction_type: 0, x: 0, z: 0, @@ -1015,7 +1015,7 @@ pub struct EntityProperty { impl Serializable for EntityProperty { fn read_from(buf: &mut io::Read) -> Result { - Ok(EntityProperty{ + Ok(EntityProperty { key: try!(Serializable::read_from(buf)), value: try!(Serializable::read_from(buf)), modifiers: try!(Serializable::read_from(buf)), @@ -1038,7 +1038,7 @@ pub struct PropertyModifier { impl Serializable for PropertyModifier { fn read_from(buf: &mut io::Read) -> Result { - Ok(PropertyModifier{ + Ok(PropertyModifier { uuid: try!(Serializable::read_from(buf)), amount: try!(Serializable::read_from(buf)), operation: try!(Serializable::read_from(buf)), @@ -1060,19 +1060,19 @@ pub struct PlayerInfoData { impl Serializable for PlayerInfoData { fn read_from(buf: &mut io::Read) -> Result { - let mut m = PlayerInfoData{ + let mut m = PlayerInfoData { action: try!(Serializable::read_from(buf)), players: Vec::new(), }; let len = try!(VarInt::read_from(buf)); - for _ in 0 .. len.0 { - let uuid = try!(UUID::read_from(buf)); + for _ in 0..len.0 { + let uuid = try!(UUID::read_from(buf)); match m.action.0 { 0 => { let name = try!(String::read_from(buf)); let mut props = Vec::new(); let plen = try!(VarInt::read_from(buf)).0; - for _ in 0 .. plen { + for _ in 0..plen { let mut prop = PlayerProperty { name: try!(String::read_from(buf)), value: try!(String::read_from(buf)), @@ -1098,21 +1098,21 @@ impl Serializable for PlayerInfoData { }, }; m.players.push(p); - }, + } 1 => { - m.players.push(PlayerDetail::UpdateGamemode{ + m.players.push(PlayerDetail::UpdateGamemode { uuid: uuid, gamemode: try!(Serializable::read_from(buf)), }) - }, + } 2 => { - m.players.push(PlayerDetail::UpdateLatency{ + m.players.push(PlayerDetail::UpdateLatency { uuid: uuid, ping: try!(Serializable::read_from(buf)), }) - }, + } 3 => { - m.players.push(PlayerDetail::UpdateDisplayName{ + m.players.push(PlayerDetail::UpdateDisplayName { uuid: uuid, display: { if try!(bool::read_from(buf)) { @@ -1122,12 +1122,10 @@ impl Serializable for PlayerInfoData { } }, }) - }, + } 4 => { - m.players.push(PlayerDetail::Remove{ - uuid: uuid, - }) - }, + m.players.push(PlayerDetail::Remove { uuid: uuid }) + } _ => panic!(), } } @@ -1150,11 +1148,29 @@ impl Default for PlayerInfoData { #[derive(Debug)] pub enum PlayerDetail { - Add{uuid: UUID, name: String, properties: Vec, gamemode: VarInt, ping: VarInt, display: Option}, - UpdateGamemode{uuid: UUID, gamemode: VarInt}, - UpdateLatency{uuid: UUID, ping: VarInt}, - UpdateDisplayName{uuid: UUID, display: Option}, - Remove{uuid: UUID}, + Add { + uuid: UUID, + name: String, + properties: Vec, + gamemode: VarInt, + ping: VarInt, + display: Option, + }, + UpdateGamemode { + uuid: UUID, + gamemode: VarInt, + }, + UpdateLatency { + uuid: UUID, + ping: VarInt, + }, + UpdateDisplayName { + uuid: UUID, + display: Option, + }, + Remove { + uuid: UUID, + }, } #[derive(Debug)] diff --git a/src/render/atlas.rs b/src/render/atlas.rs index d88bde7..43622b8 100644 --- a/src/render/atlas.rs +++ b/src/render/atlas.rs @@ -13,80 +13,85 @@ // limitations under the License. pub struct Atlas { - free_space: Vec, + free_space: Vec, } #[derive(Debug, Clone, Copy)] pub struct Rect { - pub x: usize, - pub y: usize, - pub width: usize, - pub height: usize, + pub x: usize, + pub y: usize, + pub width: usize, + pub height: usize, } impl Atlas { - pub fn new(width: usize, height: usize) -> Atlas { - let mut a = Atlas { - free_space: Vec::new(), - }; - a.free_space.push(Rect{ - x: 0, y: 0, - width: width, height: height, - }); - a - } + pub fn new(width: usize, height: usize) -> Atlas { + let mut a = Atlas { free_space: Vec::new() }; + a.free_space.push(Rect { + x: 0, + y: 0, + width: width, + height: height, + }); + a + } - pub fn add(&mut self, width: usize, height: usize) -> Option { - let mut priority = usize::max_value(); - let mut target: Option = None; - let mut target_index = 0; + pub fn add(&mut self, width: usize, height: usize) -> Option { + let mut priority = usize::max_value(); + let mut target: Option = None; + let mut target_index = 0; // Search through and find the best fit for this texture - for (index, free) in self.free_space.iter().enumerate() { - if free.width >= width && free.height >= height { - let current_priority = (free.width - width) * (free.height - height); - if target.is_none() || current_priority < priority { - target = Some(*free); - priority = current_priority; - target_index = index; - } + for (index, free) in self.free_space.iter().enumerate() { + if free.width >= width && free.height >= height { + let current_priority = (free.width - width) * (free.height - height); + if target.is_none() || current_priority < priority { + target = Some(*free); + priority = current_priority; + target_index = index; + } // Perfect match, we can break early - if priority == 0 { - break; - } - } - } - if target.is_none() { - return None; - } - let mut t = target.unwrap(); - let ret = Rect{ - x: t.x, y: t.y, - width: width, height: height, - }; + if priority == 0 { + break; + } + } + } + if target.is_none() { + return None; + } + let mut t = target.unwrap(); + let ret = Rect { + x: t.x, + y: t.y, + width: width, + height: height, + }; - if width == t.width { - t.y += height; - t.height -= height; - if t.height == 0 { + if width == t.width { + t.y += height; + t.height -= height; + if t.height == 0 { // Remove empty sections - self.free_space.remove(target_index); - } else { - self.free_space[target_index] = t; - } - } else { - if t.height > height { + self.free_space.remove(target_index); + } else { + self.free_space[target_index] = t; + } + } else { + if t.height > height { // Split by height - self.free_space.insert(0, Rect{ - x: t.x, y: t.y + height, - width: width, height: t.height - height, - }); - target_index += 1; - } - t.x += width; - t.width -= width; - self.free_space[target_index] = t; - } + self.free_space.insert(0, + Rect { + x: t.x, + y: t.y + height, + width: width, + height: t.height - height, + }); + target_index += 1; + } + t.x += width; + t.width -= width; + self.free_space[target_index] = t; + } - Some(ret) - } -} \ No newline at end of file + Some(ret) + } +} diff --git a/src/render/glsl.rs b/src/render/glsl.rs index c7d6e90..6a64424 100644 --- a/src/render/glsl.rs +++ b/src/render/glsl.rs @@ -15,50 +15,48 @@ use std::collections::HashMap; pub struct Registry { - shaders: HashMap, + shaders: HashMap, } impl Registry { - pub fn new() -> Registry { - Registry { - shaders: HashMap::new(), - } - } + pub fn new() -> Registry { + Registry { shaders: HashMap::new() } + } - pub fn register(&mut self, name: &str, source: &str) { - if self.shaders.contains_key(name) { - panic!("shader {} is already defined", name); - } - self.shaders.insert(name.to_owned(), source.trim().to_owned()); - } + pub fn register(&mut self, name: &str, source: &str) { + if self.shaders.contains_key(name) { + panic!("shader {} is already defined", name); + } + self.shaders.insert(name.to_owned(), source.trim().to_owned()); + } - pub fn get(&self, name: &str) -> String { - let mut out = String::new(); - out.push_str("#version 150\n"); - self.get_internal(&mut out, name); - out - } + pub fn get(&self, name: &str) -> String { + let mut out = String::new(); + out.push_str("#version 150\n"); + self.get_internal(&mut out, name); + out + } - pub fn get_define(&self, name: &str, define: &str) -> String { - let mut out = String::new(); - out.push_str("#version 150\n"); - out.push_str("#define "); - out.push_str(define); - out.push_str("\n"); - self.get_internal(&mut out, name); - out - } + pub fn get_define(&self, name: &str, define: &str) -> String { + let mut out = String::new(); + out.push_str("#version 150\n"); + out.push_str("#define "); + out.push_str(define); + out.push_str("\n"); + self.get_internal(&mut out, name); + out + } - fn get_internal(&self, out: &mut String, name: &str) { - let src = self.shaders.get(name).unwrap(); - for line in src.lines() { - if line.starts_with("#include ") { - let inc = line["#include ".len()..].trim(); - self.get_internal(out, &inc); - continue; - } - out.push_str(&line); - out.push_str("\n"); - } - } -} \ No newline at end of file + fn get_internal(&self, out: &mut String, name: &str) { + let src = self.shaders.get(name).unwrap(); + for line in src.lines() { + if line.starts_with("#include ") { + let inc = line["#include ".len()..].trim(); + self.get_internal(out, &inc); + continue; + } + out.push_str(&line); + out.push_str("\n"); + } + } +} diff --git a/src/render/mod.rs b/src/render/mod.rs index f532bae..9408c12 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -23,46 +23,55 @@ use std::sync::{Arc, RwLock}; use resources; use gl; use image; -use image::{GenericImage}; +use image::GenericImage; use byteorder::{WriteBytesExt, NativeEndian}; use serde_json; const ATLAS_SIZE: usize = 1024; pub struct Renderer { - resource_version: usize, - pub resources: Arc>, - textures: Arc>, - pub ui: ui::UIState, + resource_version: usize, + pub resources: Arc>, + textures: Arc>, + pub ui: ui::UIState, - gl_texture: gl::Texture, - texture_layers: usize, + gl_texture: gl::Texture, + texture_layers: usize, - last_width: u32, - last_height: u32, + last_width: u32, + last_height: u32, } impl Renderer { - pub fn new(res: Arc>) -> Renderer { - let version = { res.read().unwrap().version() }; - let tex = gl::Texture::new(); - tex.bind(gl::TEXTURE_2D_ARRAY); - tex.image_3d(gl::TEXTURE_2D_ARRAY, 0, ATLAS_SIZE as u32, ATLAS_SIZE as u32, 1, gl::RGBA, gl::UNSIGNED_BYTE, &[0; ATLAS_SIZE*ATLAS_SIZE*4]); - tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST); - tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::NEAREST); - tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE); - tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE); + pub fn new(res: Arc>) -> Renderer { + let version = { + res.read().unwrap().version() + }; + let tex = gl::Texture::new(); + tex.bind(gl::TEXTURE_2D_ARRAY); + tex.image_3d(gl::TEXTURE_2D_ARRAY, + 0, + ATLAS_SIZE as u32, + ATLAS_SIZE as u32, + 1, + gl::RGBA, + gl::UNSIGNED_BYTE, + &[0; ATLAS_SIZE * ATLAS_SIZE * 4]); + tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MAG_FILTER, gl::NEAREST); + tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_MIN_FILTER, gl::NEAREST); + tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE); + tex.set_parameter(gl::TEXTURE_2D_ARRAY, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE); - let textures = Arc::new(RwLock::new(TextureManager::new(res.clone()))); + let textures = Arc::new(RwLock::new(TextureManager::new(res.clone()))); - let mut greg = glsl::Registry::new(); - shaders::add_shaders(&mut greg); - let ui = ui::UIState::new(&greg, textures.clone(), res.clone()); + let mut greg = glsl::Registry::new(); + shaders::add_shaders(&mut greg); + let ui = ui::UIState::new(&greg, textures.clone(), res.clone()); - gl::enable(gl::DEPTH_TEST); - gl::enable(gl::CULL_FACE_FLAG); - gl::cull_face(gl::BACK); - gl::front_face(gl::CLOCK_WISE); + gl::enable(gl::DEPTH_TEST); + gl::enable(gl::CULL_FACE_FLAG); + gl::cull_face(gl::BACK); + gl::front_face(gl::CLOCK_WISE); // Shaders @@ -71,524 +80,574 @@ impl Renderer { // Models // Clouds - gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); - Renderer { - resource_version: version, - textures: textures, - ui: ui, - resources: res, - gl_texture: tex, - texture_layers: 1, - last_width: 0, - last_height: 0, - } - } + Renderer { + resource_version: version, + textures: textures, + ui: ui, + resources: res, + gl_texture: tex, + texture_layers: 1, + last_width: 0, + last_height: 0, + } + } - pub fn tick(&mut self, delta: f64, width: u32, height: u32) { - { - let rm = self.resources.read().unwrap(); - if rm.version() != self.resource_version { - self.resource_version = rm.version(); - println!("Updating textures to {}", self.resource_version); - self.textures.write().unwrap().update_textures(self.resource_version); - } - } + pub fn tick(&mut self, delta: f64, width: u32, height: u32) { + { + let rm = self.resources.read().unwrap(); + if rm.version() != self.resource_version { + self.resource_version = rm.version(); + println!("Updating textures to {}", self.resource_version); + self.textures.write().unwrap().update_textures(self.resource_version); + } + } - self.update_textures(delta); + self.update_textures(delta); - if self.last_height != height || self.last_width != width { - self.last_width = width; - self.last_height = height; - gl::viewport(0, 0, width as i32, height as i32); - } + if self.last_height != height || self.last_width != width { + self.last_width = width; + self.last_height = height; + gl::viewport(0, 0, width as i32, height as i32); + } - gl::active_texture(0); - self.gl_texture.bind(gl::TEXTURE_2D_ARRAY); + gl::active_texture(0); + self.gl_texture.bind(gl::TEXTURE_2D_ARRAY); - 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); self.ui.tick(width, height); - } + } - fn update_textures(&mut self, delta: f64) { - self.gl_texture.bind(gl::TEXTURE_2D_ARRAY); - let len = { - let tex = self.textures.read().unwrap(); - if self.texture_layers != tex.atlases.len() { - let len = ATLAS_SIZE*ATLAS_SIZE*4*tex.atlases.len(); - let mut data = Vec::with_capacity(len); - unsafe { data.set_len(len); } - self.gl_texture.get_pixels(gl::TEXTURE_2D_ARRAY, 0, gl::RGBA, gl::UNSIGNED_BYTE, &mut data[..]); - self.gl_texture.image_3d(gl::TEXTURE_2D_ARRAY, 0, ATLAS_SIZE as u32, ATLAS_SIZE as u32, tex.atlases.len() as u32, gl::RGBA, gl::UNSIGNED_BYTE, &data[..]); - self.texture_layers = tex.atlases.len(); - } - tex.pending_uploads.len() - }; - if len > 0 { - let mut tex = self.textures.write().unwrap(); - for upload in &tex.pending_uploads { - let atlas = upload.0; - let rect = upload.1; - let img = &upload.2; - self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, 0, rect.x as u32, rect.y as u32, atlas as u32, rect.width as u32, rect.height as u32, 1, gl::RGBA, gl::UNSIGNED_BYTE, &img[..]); - } - tex.pending_uploads.clear(); - } + fn update_textures(&mut self, delta: f64) { + self.gl_texture.bind(gl::TEXTURE_2D_ARRAY); + let len = { + let tex = self.textures.read().unwrap(); + if self.texture_layers != tex.atlases.len() { + let len = ATLAS_SIZE * ATLAS_SIZE * 4 * tex.atlases.len(); + let mut data = Vec::with_capacity(len); + unsafe { + data.set_len(len); + } + self.gl_texture.get_pixels(gl::TEXTURE_2D_ARRAY, + 0, + gl::RGBA, + gl::UNSIGNED_BYTE, + &mut data[..]); + self.gl_texture.image_3d(gl::TEXTURE_2D_ARRAY, + 0, + ATLAS_SIZE as u32, + ATLAS_SIZE as u32, + tex.atlases.len() as u32, + gl::RGBA, + gl::UNSIGNED_BYTE, + &data[..]); + self.texture_layers = tex.atlases.len(); + } + tex.pending_uploads.len() + }; + if len > 0 { + let mut tex = self.textures.write().unwrap(); + for upload in &tex.pending_uploads { + let atlas = upload.0; + let rect = upload.1; + let img = &upload.2; + self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, + 0, + rect.x as u32, + rect.y as u32, + atlas as u32, + rect.width as u32, + rect.height as u32, + 1, + gl::RGBA, + gl::UNSIGNED_BYTE, + &img[..]); + } + tex.pending_uploads.clear(); + } - for ani in &mut self.textures.write().unwrap().animated_textures { - if ani.remaining_time <= 0.0 { - ani.current_frame = (ani.current_frame + 1) % ani.frames.len(); - ani.remaining_time += ani.frames[ani.current_frame].time as f64; - let offset = ani.texture.width * ani.texture.width * ani.frames[ani.current_frame].index * 4; - let offset2 = offset + ani.texture.width * ani.texture.width * 4; - self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, - 0, - ani.texture.get_x() as u32, ani.texture.get_y() as u32, ani.texture.atlas as u32, - ani.texture.get_width() as u32, ani.texture.get_height() as u32, 1, - gl::RGBA, gl::UNSIGNED_BYTE, - &ani.data[offset .. offset2] - ); - } else { - ani.remaining_time -= delta / 3.0; - } - } + for ani in &mut self.textures.write().unwrap().animated_textures { + if ani.remaining_time <= 0.0 { + ani.current_frame = (ani.current_frame + 1) % ani.frames.len(); + ani.remaining_time += ani.frames[ani.current_frame].time as f64; + let offset = ani.texture.width * ani.texture.width * + ani.frames[ani.current_frame].index * 4; + let offset2 = offset + ani.texture.width * ani.texture.width * 4; + self.gl_texture.sub_image_3d(gl::TEXTURE_2D_ARRAY, + 0, + ani.texture.get_x() as u32, + ani.texture.get_y() as u32, + ani.texture.atlas as u32, + ani.texture.get_width() as u32, + ani.texture.get_height() as u32, + 1, + gl::RGBA, + gl::UNSIGNED_BYTE, + &ani.data[offset..offset2]); + } else { + ani.remaining_time -= delta / 3.0; + } + } - } + } - pub fn get_textures(&self) -> Arc> { - self.textures.clone() - } + pub fn get_textures(&self) -> Arc> { + self.textures.clone() + } - pub fn get_textures_ref(&self) -> &RwLock { - &self.textures - } + pub fn get_textures_ref(&self) -> &RwLock { + &self.textures + } - pub fn check_texture(&self, tex: Texture) -> Texture { - if tex.version == self.resource_version { - tex - } else { - let mut new = Renderer::get_texture(&self.textures, &tex.name); - new.rel_x = tex.rel_x; - new.rel_y = tex.rel_y; - new.rel_width = tex.rel_width; - new.rel_height = tex.rel_height; - new.is_rel = tex.is_rel; - new - } - } + pub fn check_texture(&self, tex: Texture) -> Texture { + if tex.version == self.resource_version { + tex + } else { + let mut new = Renderer::get_texture(&self.textures, &tex.name); + new.rel_x = tex.rel_x; + new.rel_y = tex.rel_y; + new.rel_width = tex.rel_width; + new.rel_height = tex.rel_height; + new.is_rel = tex.is_rel; + new + } + } - pub fn get_texture(textures: &RwLock, name: &str) -> Texture { - let tex = { textures.read().unwrap().get_texture(name) }; - match tex { - Some(val) => val, - None => { - let mut t = textures.write().unwrap(); - // Make sure it hasn't already been loaded since we switched + pub fn get_texture(textures: &RwLock, name: &str) -> Texture { + let tex = { + textures.read().unwrap().get_texture(name) + }; + match tex { + Some(val) => val, + None => { + let mut t = textures.write().unwrap(); + // Make sure it hasn't already been loaded since we switched // locks. - if let Some(val) = t.get_texture(name) { - val - } else { - t.load_texture(name); - t.get_texture(name).unwrap() - } - } - } - } + if let Some(val) = t.get_texture(name) { + val + } else { + t.load_texture(name); + t.get_texture(name).unwrap() + } + } + } + } } pub struct TextureManager { - textures: HashMap, - version: usize, - resources: Arc>, - atlases: Vec, + textures: HashMap, + version: usize, + resources: Arc>, + atlases: Vec, - animated_textures: Vec, - pending_uploads: Vec<(i32, atlas::Rect, Vec)>, + animated_textures: Vec, + pending_uploads: Vec<(i32, atlas::Rect, Vec)>, - dynamic_textures: HashMap, - free_dynamics: Vec<(i32, atlas::Rect)>, + dynamic_textures: HashMap, + free_dynamics: Vec<(i32, atlas::Rect)>, } impl TextureManager { - fn new(res: Arc>) -> TextureManager { - let mut tm = TextureManager { - textures: HashMap::new(), - version: 0xFFFF, - resources: res, - atlases: Vec::new(), - animated_textures: Vec::new(), - pending_uploads: Vec::new(), + fn new(res: Arc>) -> TextureManager { + let mut tm = TextureManager { + textures: HashMap::new(), + version: 0xFFFF, + resources: res, + atlases: Vec::new(), + animated_textures: Vec::new(), + pending_uploads: Vec::new(), - dynamic_textures: HashMap::new(), - free_dynamics: Vec::new(), - }; - tm.add_defaults(); - tm - } + dynamic_textures: HashMap::new(), + free_dynamics: Vec::new(), + }; + tm.add_defaults(); + tm + } - fn add_defaults(&mut self) { - self.put_texture("steven", "missing_texture", 2, 2, vec![ + fn add_defaults(&mut self) { + self.put_texture("steven", + "missing_texture", + 2, + 2, + vec![ 0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255, ]); - self.put_texture("steven", "solid", 1, 1, vec![ + self.put_texture("steven", + "solid", + 1, + 1, + vec![ 255, 255, 255, 255, ]); - } + } - fn update_textures(&mut self, version: usize) { - self.dynamic_textures.clear(); - self.free_dynamics.clear(); - self.pending_uploads.clear(); - self.atlases.clear(); - self.animated_textures.clear(); - self.version = version; - let map = self.textures.clone(); - self.textures.clear(); + fn update_textures(&mut self, version: usize) { + self.dynamic_textures.clear(); + self.free_dynamics.clear(); + self.pending_uploads.clear(); + self.atlases.clear(); + self.animated_textures.clear(); + self.version = version; + let map = self.textures.clone(); + self.textures.clear(); - self.add_defaults(); + self.add_defaults(); - for name in map.keys() { - self.load_texture(name); - } - } + for name in map.keys() { + self.load_texture(name); + } + } - fn get_texture(&self, name: &str) -> Option { - self.textures.get(name).map(|v| v.clone()) - } + fn get_texture(&self, name: &str) -> Option { + self.textures.get(name).map(|v| v.clone()) + } - fn load_texture(&mut self, name: &str) { - let (plugin, name) = if let Some(pos) = name.find(':') { - (&name[..pos], &name[pos+1..]) - } else { - ("minecraft", name) - }; - let path = format!("textures/{}.png", name); - let res = self.resources.clone(); - if let Some(mut val) = res.read().unwrap().open(plugin, &path) { - let mut data = Vec::new(); - val.read_to_end(&mut data).unwrap(); - if let Ok(img) = image::load_from_memory(&data) { - let (width, height) = img.dimensions(); + fn load_texture(&mut self, name: &str) { + let (plugin, name) = if let Some(pos) = name.find(':') { + (&name[..pos], &name[pos + 1..]) + } else { + ("minecraft", name) + }; + let path = format!("textures/{}.png", name); + let res = self.resources.clone(); + if let Some(mut val) = res.read().unwrap().open(plugin, &path) { + let mut data = Vec::new(); + val.read_to_end(&mut data).unwrap(); + if let Ok(img) = image::load_from_memory(&data) { + let (width, height) = img.dimensions(); // Might be animated - if (name.starts_with("blocks/") || name.starts_with("items/")) && width != height { - let id = img.to_rgba().into_vec(); - let frame = id[ - .. (width*width*4) as usize - ].to_owned(); - if let Some(mut ani) = self.load_animation(plugin, name, &img, id) { - ani.texture = self.put_texture(plugin, name, width, width, frame); - self.animated_textures.push(ani); - return; - } - } - self.put_texture(plugin, name, width, height, img.to_rgba().into_vec()); - return; - } - } - self.insert_texture_dummy(plugin, name); - } + if (name.starts_with("blocks/") || name.starts_with("items/")) && width != height { + let id = img.to_rgba().into_vec(); + let frame = id[..(width * width * 4) as usize].to_owned(); + if let Some(mut ani) = self.load_animation(plugin, name, &img, id) { + ani.texture = self.put_texture(plugin, name, width, width, frame); + self.animated_textures.push(ani); + return; + } + } + self.put_texture(plugin, name, width, height, img.to_rgba().into_vec()); + return; + } + } + self.insert_texture_dummy(plugin, name); + } - fn load_animation(&mut self, plugin: &str, name: &str, img: &image::DynamicImage, data: Vec) -> Option { - let path = format!("textures/{}.png.mcmeta", name); - let res = self.resources.clone(); - if let Some(val) = res.read().unwrap().open(plugin, &path) { - let meta: serde_json::Value = serde_json::from_reader(val).unwrap(); - let animation = meta.find("animation").unwrap(); - let frame_time = animation.find("frameTime").and_then(|v| v.as_i64()).unwrap_or(1); - let interpolate = animation.find("interpolate").and_then(|v| v.as_boolean()).unwrap_or(false); - let frames = if let Some(frames) = animation.find("frames").and_then(|v| v.as_array()) { - let mut out = Vec::with_capacity(frames.len()); - for frame in frames { - if let Some(index) = frame.as_i64() { - out.push(AnimationFrame{ - index: index as usize, - time: frame_time, - }) - } else { - out.push(AnimationFrame{ + fn load_animation(&mut self, + plugin: &str, + name: &str, + img: &image::DynamicImage, + data: Vec) + -> Option { + let path = format!("textures/{}.png.mcmeta", name); + let res = self.resources.clone(); + if let Some(val) = res.read().unwrap().open(plugin, &path) { + let meta: serde_json::Value = serde_json::from_reader(val).unwrap(); + let animation = meta.find("animation").unwrap(); + let frame_time = animation.find("frameTime").and_then(|v| v.as_i64()).unwrap_or(1); + let interpolate = animation.find("interpolate") + .and_then(|v| v.as_boolean()) + .unwrap_or(false); + let frames = if let Some(frames) = animation.find("frames") + .and_then(|v| v.as_array()) { + let mut out = Vec::with_capacity(frames.len()); + for frame in frames { + if let Some(index) = frame.as_i64() { + out.push(AnimationFrame { + index: index as usize, + time: frame_time, + }) + } else { + out.push(AnimationFrame{ index: frame.find("index").unwrap().as_i64().unwrap() as usize, time: frame_time * frame.find("frameTime").unwrap().as_i64().unwrap(), }) - } - } - out - } else { - let (width, height) = img.dimensions(); - let count = height / width; - let mut frames = Vec::with_capacity(count as usize); - for i in 0 .. count { - frames.push(AnimationFrame{ - index: i as usize, - time: frame_time, - }) - } - frames - }; + } + } + out + } else { + let (width, height) = img.dimensions(); + let count = height / width; + let mut frames = Vec::with_capacity(count as usize); + for i in 0..count { + frames.push(AnimationFrame { + index: i as usize, + time: frame_time, + }) + } + frames + }; - return Some(AnimatedTexture{ - frames: frames, - data: data, - interpolate: interpolate, - current_frame: 0, - remaining_time: 0.0, - texture: self.get_texture("steven:missing_texture").unwrap(), - }); - } - None - } + return Some(AnimatedTexture { + frames: frames, + data: data, + interpolate: interpolate, + current_frame: 0, + remaining_time: 0.0, + texture: self.get_texture("steven:missing_texture").unwrap(), + }); + } + None + } - fn put_texture(&mut self, plugin: &str, name: &str, width: u32, height: u32, data: Vec) -> Texture { - let (atlas, rect) = self.find_free(width as usize, height as usize); - self.pending_uploads.push((atlas, rect, data)); + fn put_texture(&mut self, + plugin: &str, + name: &str, + width: u32, + height: u32, + data: Vec) + -> Texture { + let (atlas, rect) = self.find_free(width as usize, height as usize); + self.pending_uploads.push((atlas, rect, data)); - let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } - full_name.push_str(name); + let mut full_name = String::new(); + if plugin != "minecraft" { + full_name.push_str(plugin); + full_name.push_str(":"); + } + full_name.push_str(name); - let tex = Texture { - name: full_name.clone(), - version: self.version, - atlas: atlas, - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - rel_x: 0.0, - rel_y: 0.0, - rel_width: 1.0, - rel_height: 1.0, - is_rel: false, - }; - self.textures.insert(full_name, tex.clone()); - tex - } + let tex = Texture { + name: full_name.clone(), + version: self.version, + atlas: atlas, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + rel_x: 0.0, + rel_y: 0.0, + rel_width: 1.0, + rel_height: 1.0, + is_rel: false, + }; + self.textures.insert(full_name, tex.clone()); + tex + } - fn find_free(&mut self, width: usize, height: usize) -> (i32, atlas::Rect) { - let mut index = 0; - for atlas in &mut self.atlases { - if let Some(rect) = atlas.add(width, height) { - return (index, rect); - } - index += 1; - } - let mut atlas = atlas::Atlas::new(ATLAS_SIZE, ATLAS_SIZE); - let rect = atlas.add(width, height); - self.atlases.push(atlas); - (index, rect.unwrap()) - } + fn find_free(&mut self, width: usize, height: usize) -> (i32, atlas::Rect) { + let mut index = 0; + for atlas in &mut self.atlases { + if let Some(rect) = atlas.add(width, height) { + return (index, rect); + } + index += 1; + } + let mut atlas = atlas::Atlas::new(ATLAS_SIZE, ATLAS_SIZE); + let rect = atlas.add(width, height); + self.atlases.push(atlas); + (index, rect.unwrap()) + } - fn insert_texture_dummy(&mut self, plugin: &str, name: &str) -> Texture { - let missing = self.get_texture("steven:missing_texture").unwrap(); + fn insert_texture_dummy(&mut self, plugin: &str, name: &str) -> Texture { + let missing = self.get_texture("steven:missing_texture").unwrap(); - let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } - full_name.push_str(name); + let mut full_name = String::new(); + if plugin != "minecraft" { + full_name.push_str(plugin); + full_name.push_str(":"); + } + full_name.push_str(name); - let t = Texture { - name: full_name.to_owned(), - version: self.version, - atlas: missing.atlas, - x: missing.x, - y: missing.y, - width: missing.width, - height: missing.height, - rel_x: 0.0, - rel_y: 0.0, - rel_width: 1.0, - rel_height: 1.0, - is_rel: false, - }; - self.textures.insert(full_name.to_owned(), t.clone()); - t - } + let t = Texture { + name: full_name.to_owned(), + version: self.version, + atlas: missing.atlas, + x: missing.x, + y: missing.y, + width: missing.width, + height: missing.height, + rel_x: 0.0, + rel_y: 0.0, + rel_width: 1.0, + rel_height: 1.0, + is_rel: false, + }; + self.textures.insert(full_name.to_owned(), t.clone()); + t + } - pub fn put_dynamic(&mut self, plugin: &str, name: &str, img: image::DynamicImage) -> Texture { - let (width, height) = img.dimensions(); - let (width, height) = (width as usize, height as usize); - let mut rect = None; - let mut rect_pos = 0; - for (i, r) in self.free_dynamics.iter().enumerate() { - let (atlas, r) = *r; - if r.width == width && r.height == height { - rect_pos = i; - rect = Some((atlas, r)); - break; - } else if r.width >= width && r.height >= height { - rect_pos = i; - rect = Some((atlas, r)); - } - } - let data = img.to_rgba().into_vec(); - let mut new = false; - let (atlas, rect) = if let Some(r) = rect { - self.free_dynamics.remove(rect_pos); - r - } else { - new = true; - self.find_free(width as usize, height as usize) - }; + pub fn put_dynamic(&mut self, plugin: &str, name: &str, img: image::DynamicImage) -> Texture { + let (width, height) = img.dimensions(); + let (width, height) = (width as usize, height as usize); + let mut rect = None; + let mut rect_pos = 0; + for (i, r) in self.free_dynamics.iter().enumerate() { + let (atlas, r) = *r; + if r.width == width && r.height == height { + rect_pos = i; + rect = Some((atlas, r)); + break; + } else if r.width >= width && r.height >= height { + rect_pos = i; + rect = Some((atlas, r)); + } + } + let data = img.to_rgba().into_vec(); + let mut new = false; + let (atlas, rect) = if let Some(r) = rect { + self.free_dynamics.remove(rect_pos); + r + } else { + new = true; + self.find_free(width as usize, height as usize) + }; - let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } - full_name.push_str(name); + let mut full_name = String::new(); + if plugin != "minecraft" { + full_name.push_str(plugin); + full_name.push_str(":"); + } + full_name.push_str(name); - self.dynamic_textures.insert(full_name.clone(), (atlas, rect)); - if new { - self.put_texture(plugin, name, width as u32, height as u32, data) - } else { - let t = Texture { - name: full_name.clone(), - version: self.version, - atlas: atlas, - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - rel_x: 0.0, - rel_y: 0.0, - rel_width: 1.0, - rel_height: 1.0, - is_rel: false, - }; - let rect = atlas::Rect { - x: rect.x, - y: rect.y, - width: width, - height: height, - }; - self.pending_uploads.push((atlas, rect, data)); - self.textures.insert(full_name.to_owned(), t.clone()); - t - } - } + self.dynamic_textures.insert(full_name.clone(), (atlas, rect)); + if new { + self.put_texture(plugin, name, width as u32, height as u32, data) + } else { + let t = Texture { + name: full_name.clone(), + version: self.version, + atlas: atlas, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + rel_x: 0.0, + rel_y: 0.0, + rel_width: 1.0, + rel_height: 1.0, + is_rel: false, + }; + let rect = atlas::Rect { + x: rect.x, + y: rect.y, + width: width, + height: height, + }; + self.pending_uploads.push((atlas, rect, data)); + self.textures.insert(full_name.to_owned(), t.clone()); + t + } + } - pub fn remove_dynamic(&mut self, plugin: &str, name: &str) { - let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } - full_name.push_str(name); + pub fn remove_dynamic(&mut self, plugin: &str, name: &str) { + let mut full_name = String::new(); + if plugin != "minecraft" { + full_name.push_str(plugin); + full_name.push_str(":"); + } + full_name.push_str(name); - let desc = self.dynamic_textures.remove(&full_name).unwrap(); - self.free_dynamics.push(desc); - } + let desc = self.dynamic_textures.remove(&full_name).unwrap(); + self.free_dynamics.push(desc); + } } #[allow(dead_code)] struct AnimatedTexture { - frames: Vec, - data: Vec, - interpolate: bool, - current_frame: usize, - remaining_time: f64, - texture: Texture, + frames: Vec, + data: Vec, + interpolate: bool, + current_frame: usize, + remaining_time: f64, + texture: Texture, } struct AnimationFrame { - index: usize, - time: i64, + index: usize, + time: i64, } #[derive(Clone, Debug)] pub struct Texture { - name: String, - version: usize, - pub atlas: i32, - x: usize, - y: usize, - width: usize, - height: usize, - is_rel: bool, // Save some cycles for none relative textures - rel_x: f32, - rel_y: f32, - rel_width: f32, - rel_height: f32, + name: String, + version: usize, + pub atlas: i32, + x: usize, + y: usize, + width: usize, + height: usize, + is_rel: bool, // Save some cycles for none relative textures + rel_x: f32, + rel_y: f32, + rel_width: f32, + rel_height: f32, } impl Texture { - pub fn get_x(&self) -> usize { - if self.is_rel { - self.x + ((self.width as f32) * self.rel_x) as usize - } else { - self.x - } - } + pub fn get_x(&self) -> usize { + if self.is_rel { + self.x + ((self.width as f32) * self.rel_x) as usize + } else { + self.x + } + } - pub fn get_y(&self) -> usize { - if self.is_rel { - self.y + ((self.height as f32) * self.rel_y) as usize - } else { - self.y - } - } + pub fn get_y(&self) -> usize { + if self.is_rel { + self.y + ((self.height as f32) * self.rel_y) as usize + } else { + self.y + } + } - pub fn get_width(&self) -> usize { - if self.is_rel { - ((self.width as f32) * self.rel_width) as usize - } else { - self.width - } - } + pub fn get_width(&self) -> usize { + if self.is_rel { + ((self.width as f32) * self.rel_width) as usize + } else { + self.width + } + } - pub fn get_height(&self) -> usize { - if self.is_rel { - ((self.height as f32) * self.rel_height) as usize - } else { - self.height - } - } + pub fn get_height(&self) -> usize { + if self.is_rel { + ((self.height as f32) * self.rel_height) as usize + } else { + self.height + } + } - pub fn relative(&self, x: f32, y: f32, width: f32, height: f32) -> Texture { - Texture { - name: self.name.clone(), - version: self.version, - x: self.x, - y: self.y, - atlas: self.atlas, - width: self.width, - height: self.height, - is_rel: true, - rel_x: self.rel_x + x * self.rel_width, - rel_y: self.rel_y + y * self.rel_height, - rel_width: width * self.rel_width, - rel_height: height * self.rel_height, - } - } + pub fn relative(&self, x: f32, y: f32, width: f32, height: f32) -> Texture { + Texture { + name: self.name.clone(), + version: self.version, + x: self.x, + y: self.y, + atlas: self.atlas, + width: self.width, + height: self.height, + is_rel: true, + rel_x: self.rel_x + x * self.rel_width, + rel_y: self.rel_y + y * self.rel_height, + rel_width: width * self.rel_width, + rel_height: height * self.rel_height, + } + } } #[allow(unused_must_use)] pub fn generate_element_buffer(size: usize) -> (Vec, gl::Type) { - let mut ty = gl::UNSIGNED_SHORT; - let mut data = if (size/6)*4*3 >= u16::max_value() as usize { - ty = gl::UNSIGNED_INT; - Vec::with_capacity(size*4) - } else { - Vec::with_capacity(size*2) - }; - for i in 0 .. size/6 { - for val in &[0, 1, 2, 2, 1, 3] { - if ty == gl::UNSIGNED_INT { - data.write_u32::((i as u32) * 4 + val); - } else { - data.write_u16::((i as u16) * 4 + (*val as u16)); - } - } - } + let mut ty = gl::UNSIGNED_SHORT; + let mut data = if (size / 6) * 4 * 3 >= u16::max_value() as usize { + ty = gl::UNSIGNED_INT; + Vec::with_capacity(size * 4) + } else { + Vec::with_capacity(size * 2) + }; + for i in 0..size / 6 { + for val in &[0, 1, 2, 2, 1, 3] { + if ty == gl::UNSIGNED_INT { + data.write_u32::((i as u32) * 4 + val); + } else { + data.write_u16::((i as u16) * 4 + (*val as u16)); + } + } + } - (data, ty) -} \ No newline at end of file + (data, ty) +} diff --git a/src/render/shaders.rs b/src/render/shaders.rs index 0221f9d..c950227 100644 --- a/src/render/shaders.rs +++ b/src/render/shaders.rs @@ -16,11 +16,12 @@ use render::glsl; use gl; pub fn add_shaders(reg: &mut glsl::Registry) { - reg.register("lookup_texture", include_str!("shaders/lookup_texture.glsl")); - reg.register("get_light", include_str!("shaders/get_light.glsl")); + reg.register("lookup_texture", + include_str!("shaders/lookup_texture.glsl")); + reg.register("get_light", include_str!("shaders/get_light.glsl")); - reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl")); - reg.register("ui_frag", include_str!("shaders/ui_frag.glsl")); + reg.register("ui_vertex", include_str!("shaders/ui_vertex.glsl")); + reg.register("ui_frag", include_str!("shaders/ui_frag.glsl")); } #[macro_export] @@ -71,39 +72,39 @@ macro_rules! init_shader { } pub fn create_program(vertex: &str, fragment: &str) -> gl::Program { - let program = gl::Program::new(); + let program = gl::Program::new(); - let v = gl::Shader::new(gl::VERTEX_SHADER); - v.set_source(vertex); - v.compile(); + let v = gl::Shader::new(gl::VERTEX_SHADER); + v.set_source(vertex); + v.compile(); - if v.get_parameter(gl::COMPILE_STATUS) == 0 { - println!("Src: {}", vertex); - panic!("Shader error: {}", v.get_info_log()); - } else { - let log = v.get_info_log(); - if !log.is_empty() { - println!("{}", log); - } - } + if v.get_parameter(gl::COMPILE_STATUS) == 0 { + println!("Src: {}", vertex); + panic!("Shader error: {}", v.get_info_log()); + } else { + let log = v.get_info_log(); + if !log.is_empty() { + println!("{}", log); + } + } - let f = gl::Shader::new(gl::FRAGMENT_SHADER); - f.set_source(fragment); - f.compile(); + let f = gl::Shader::new(gl::FRAGMENT_SHADER); + f.set_source(fragment); + f.compile(); - if f.get_parameter(gl::COMPILE_STATUS) == 0 { - println!("Src: {}", fragment); - panic!("Shader error: {}", f.get_info_log()); - } else { - let log = f.get_info_log(); - if !log.is_empty() { - println!("{}", log); - } - } + if f.get_parameter(gl::COMPILE_STATUS) == 0 { + println!("Src: {}", fragment); + panic!("Shader error: {}", f.get_info_log()); + } else { + let log = f.get_info_log(); + if !log.is_empty() { + println!("{}", log); + } + } - program.attach_shader(v); - program.attach_shader(f); - program.link(); - program.use_program(); - program -} \ No newline at end of file + program.attach_shader(v); + program.attach_shader(f); + program.link(); + program.use_program(); + program +} diff --git a/src/render/ui.rs b/src/render/ui.rs index f08aee1..e4fb135 100644 --- a/src/render/ui.rs +++ b/src/render/ui.rs @@ -22,34 +22,34 @@ use render::glsl; use render::shaders; use byteorder::{WriteBytesExt, NativeEndian}; use image; -use image::{GenericImage}; +use image::GenericImage; const UI_WIDTH: f64 = 854.0; const UI_HEIGHT: f64 = 480.0; -pub struct UIState { - textures: Arc>, - resources: Arc>, - pub version: usize, +pub struct UIState { + textures: Arc>, + resources: Arc>, + pub version: usize, - data: Vec, - prev_size: usize, - count: usize, + data: Vec, + prev_size: usize, + count: usize, - array: gl::VertexArray, - buffer: gl::Buffer, - index_buffer: gl::Buffer, - index_type: gl::Type, - max_index: usize, + array: gl::VertexArray, + buffer: gl::Buffer, + index_buffer: gl::Buffer, + index_type: gl::Type, + max_index: usize, - shader: UIShader, + shader: UIShader, - // Font - font_pages: Vec>, - font_character_info: Vec<(i32,i32)>, - char_map: HashMap, - page_width: f64, - page_height: f64, + // Font + font_pages: Vec>, + font_character_info: Vec<(i32, i32)>, + char_map: HashMap, + page_width: f64, + page_height: f64, } init_shader! { @@ -70,390 +70,478 @@ init_shader! { } impl UIState { - pub fn new(glsl: &glsl::Registry, textures: Arc>, res: Arc>) -> UIState { - let shader = UIShader::new(glsl); + pub fn new(glsl: &glsl::Registry, + textures: Arc>, + res: Arc>) + -> UIState { + let shader = UIShader::new(glsl); - let array = gl::VertexArray::new(); - array.bind(); - let buffer = gl::Buffer::new(); - buffer.bind(gl::ARRAY_BUFFER); - shader.position.enable(); - shader.texture_info.enable(); - shader.texture_offset.enable(); - shader.color.enable(); - shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0); - shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8); - shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16); - shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24); + let array = gl::VertexArray::new(); + array.bind(); + let buffer = gl::Buffer::new(); + buffer.bind(gl::ARRAY_BUFFER); + shader.position.enable(); + shader.texture_info.enable(); + shader.texture_offset.enable(); + shader.color.enable(); + shader.position.vertex_pointer_int(3, gl::SHORT, 28, 0); + shader.texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8); + shader.texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16); + shader.color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24); - let index_buffer = gl::Buffer::new(); - index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); + let index_buffer = gl::Buffer::new(); + index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); - let mut pages = Vec::with_capacity(0x100); - for _ in 0 .. 0x100 { - pages.push(Option::None); - } + let mut pages = Vec::with_capacity(0x100); + for _ in 0..0x100 { + pages.push(Option::None); + } - let mut char_map = HashMap::new(); - let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■"; - for (pos, c) in ascii_chars.chars().enumerate() { - char_map.insert(c, ::std::char::from_u32(pos as u32).unwrap()); - } + let mut char_map = HashMap::new(); + let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ \ + !\"#$%&'()*+,-./0123456789:;\ + <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ + ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞\ + ╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■"; + for (pos, c) in ascii_chars.chars().enumerate() { + char_map.insert(c, ::std::char::from_u32(pos as u32).unwrap()); + } - let mut state = UIState { - textures: textures, - resources: res, - version: 0xFFFF, + let mut state = UIState { + textures: textures, + resources: res, + version: 0xFFFF, - data: Vec::new(), - count: 0, - prev_size: 0, + data: Vec::new(), + count: 0, + prev_size: 0, - index_type: gl::UNSIGNED_BYTE, - array: array, - buffer: buffer, - index_buffer: index_buffer, - max_index: 0, + index_type: gl::UNSIGNED_BYTE, + array: array, + buffer: buffer, + index_buffer: index_buffer, + max_index: 0, - shader: shader, + shader: shader, - // Font - font_pages: pages, - font_character_info: vec![(0, 0); 0x10000], - char_map: char_map, - page_width: 0.0, - page_height: 0.0, - }; - state.load_font(); - state - } + // Font + font_pages: pages, + font_character_info: vec![(0, 0); 0x10000], + char_map: char_map, + page_width: 0.0, + page_height: 0.0, + }; + state.load_font(); + state + } - pub fn tick(&mut self, width: u32, height: u32) { - { - let version = self.resources.read().unwrap().version(); - if self.version != version { - self.version = version; - self.load_font(); - } - } + pub fn tick(&mut self, width: u32, height: u32) { + { + let version = self.resources.read().unwrap().version(); + if self.version != version { + self.version = version; + self.load_font(); + } + } // Prevent clipping with the world - 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); + 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.program.use_program(); - self.shader.texture.set_int(0); - if self.count > 0 { - self.array.bind(); - if self.max_index < self.count { - let (data, ty) = render::generate_element_buffer(self.count); - self.index_type = ty; - self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); - self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); - self.max_index = self.count; - } + self.shader.program.use_program(); + self.shader.texture.set_int(0); + if self.count > 0 { + self.array.bind(); + if self.max_index < self.count { + let (data, ty) = render::generate_element_buffer(self.count); + self.index_type = ty; + self.index_buffer.bind(gl::ELEMENT_ARRAY_BUFFER); + self.index_buffer.set_data(gl::ELEMENT_ARRAY_BUFFER, &data, gl::DYNAMIC_DRAW); + self.max_index = self.count; + } - self.shader.screensize.set_float2(width as f32, height as f32); + self.shader.screensize.set_float2(width as f32, height as f32); - self.buffer.bind(gl::ARRAY_BUFFER); - if self.data.len() > self.prev_size { - self.prev_size = self.data.len(); - self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW); - } else { - let mut target = self.buffer.map(gl::ARRAY_BUFFER, gl::WRITE_ONLY, self.data.len()); - target.write_all(&self.data[..]).unwrap(); - } - gl::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0); - } + self.buffer.bind(gl::ARRAY_BUFFER); + if self.data.len() > self.prev_size { + self.prev_size = self.data.len(); + self.buffer.set_data(gl::ARRAY_BUFFER, &self.data, gl::STREAM_DRAW); + } else { + let mut target = self.buffer.map(gl::ARRAY_BUFFER, gl::WRITE_ONLY, self.data.len()); + target.write_all(&self.data[..]).unwrap(); + } + gl::draw_elements(gl::TRIANGLES, self.count, self.index_type, 0); + } - gl::disable(gl::BLEND); - self.data.clear(); - self.count = 0; - } + gl::disable(gl::BLEND); + self.data.clear(); + self.count = 0; + } - pub fn add_bytes(&mut self, data: &Vec) { - self.data.extend(data); - self.count += (data.len() / (28 * 4)) * 6; - } + pub fn add_bytes(&mut self, data: &Vec) { + self.data.extend(data); + self.count += (data.len() / (28 * 4)) * 6; + } - pub fn character_texture(&mut self, c: char) -> render::Texture { - let raw = c as u32; - let page = raw >> 8; + pub fn character_texture(&mut self, c: char) -> render::Texture { + let raw = c as u32; + let page = raw >> 8; // Lazy load fonts to size memory - if self.font_pages[page as usize].is_none() { - let name = if page == 0 { - "font/ascii".to_owned() - } else { - format!("font/unicode_page_{:02X}", page) - }; - let textures = self.textures.clone(); - self.font_pages[page as usize] = Some(render::Renderer::get_texture(&textures, &name)); - } - let p = self.font_pages[page as usize].clone().unwrap(); + if self.font_pages[page as usize].is_none() { + let name = if page == 0 { + "font/ascii".to_owned() + } else { + format!("font/unicode_page_{:02X}", page) + }; + let textures = self.textures.clone(); + self.font_pages[page as usize] = Some(render::Renderer::get_texture(&textures, &name)); + } + let p = self.font_pages[page as usize].clone().unwrap(); - let raw = if page == 0 { - (*self.char_map.get(&c).unwrap_or(&c)) as u32 - } else { - raw - }; - let ch = raw & 0xFF; - let cx = ch & 0xF; - let cy = ch >> 4; - let info = self.font_character_info[raw as usize]; - if page == 0 { - let sw = (self.page_width / 16.0) as u32; - let sh = (self.page_height / 16.0) as u32; - return p.relative( - (cx * sw + info.0 as u32) as f32 / (self.page_width as f32), - (cy * sh) as f32 / (self.page_height as f32), - (info.1 - info.0) as f32 / (self.page_width as f32), - (sh as f32) / (self.page_height as f32) - ) - } - p.relative( - (cx * 16 + info.0 as u32) as f32 / 256.0, - (cy * 16) as f32 / 256.0, - (info.1 - info.0) as f32 / 256.0, - 16.0 / 256.0 - ) - } + let raw = if page == 0 { + (*self.char_map.get(&c).unwrap_or(&c)) as u32 + } else { + raw + }; + let ch = raw & 0xFF; + let cx = ch & 0xF; + let cy = ch >> 4; + let info = self.font_character_info[raw as usize]; + if page == 0 { + let sw = (self.page_width / 16.0) as u32; + let sh = (self.page_height / 16.0) as u32; + return p.relative((cx * sw + info.0 as u32) as f32 / (self.page_width as f32), + (cy * sh) as f32 / (self.page_height as f32), + (info.1 - info.0) as f32 / (self.page_width as f32), + (sh as f32) / (self.page_height as f32)) + } + p.relative((cx * 16 + info.0 as u32) as f32 / 256.0, + (cy * 16) as f32 / 256.0, + (info.1 - info.0) as f32 / 256.0, + 16.0 / 256.0) + } - pub fn size_of_string(&self, val: &str) -> f64 { - let mut size = 0.0; - for c in val.chars() { - size += self.size_of_char(c) + 2.0; - } - size - 2.0 - } + pub fn size_of_string(&self, val: &str) -> f64 { + let mut size = 0.0; + for c in val.chars() { + size += self.size_of_char(c) + 2.0; + } + size - 2.0 + } - pub fn size_of_char(&self, c: char) -> f64 { - if c == ' ' { - return 4.0; - } - let r = c as u32; - if r >> 8 == 0 { - let r = (*self.char_map.get(&c).unwrap_or(&c)) as u32; - let info = self.font_character_info[r as usize]; - let sw = self.page_width / 16.0; - return (((info.1 - info.0) as f64) / sw) * 16.0; - } - let info = self.font_character_info[c as usize]; - (info.1 - info.0) as f64 - } + pub fn size_of_char(&self, c: char) -> f64 { + if c == ' ' { + return 4.0; + } + let r = c as u32; + if r >> 8 == 0 { + let r = (*self.char_map.get(&c).unwrap_or(&c)) as u32; + let info = self.font_character_info[r as usize]; + let sw = self.page_width / 16.0; + return (((info.1 - info.0) as f64) / sw) * 16.0; + } + let info = self.font_character_info[c as usize]; + (info.1 - info.0) as f64 + } - fn load_font(&mut self) { - for page in &mut self.font_pages { - *page = None; - } - let res = self.resources.read().unwrap(); - if let Some(mut info) = res.open("minecraft", "font/glyph_sizes.bin") { - let mut data = Vec::with_capacity(0x10000); - info.read_to_end(&mut data).unwrap(); - for (i, info) in self.font_character_info.iter_mut().enumerate() { + fn load_font(&mut self) { + for page in &mut self.font_pages { + *page = None; + } + let res = self.resources.read().unwrap(); + if let Some(mut info) = res.open("minecraft", "font/glyph_sizes.bin") { + let mut data = Vec::with_capacity(0x10000); + info.read_to_end(&mut data).unwrap(); + for (i, info) in self.font_character_info.iter_mut().enumerate() { // Top nibble - start position // Bottom nibble - end position - info.0 = (data[i] >> 4) as i32; - info.1 = (data[i] & 0xF) as i32 + 1; - } - } - if let Some(mut val) = res.open("minecraft", "textures/font/ascii.png") { - let mut data = Vec::new(); - val.read_to_end(&mut data).unwrap(); - if let Ok(img) = image::load_from_memory(&data) { - let (width, height) = img.dimensions(); - self.page_width = width as f64; - self.page_height = height as f64; - let sw = width / 16; - let sh = height / 16; - for i in 0 .. 256 { - let cx = (i & 0xF) * sw; - let cy = (i >> 4) * sh; - let mut start = true; - 'x_loop: for x in 0 .. sw { - for y in 0 .. sh { - let a = img.get_pixel(cx+x, cy+y).data[3]; - if start && a != 0 { - self.font_character_info[i as usize].0 = x as i32; - start = false; - continue 'x_loop; - } else if !start && a != 0 { - continue 'x_loop; - } - } - if !start { - self.font_character_info[i as usize].1 = x as i32; - break; - } - } - } - } - } - } + info.0 = (data[i] >> 4) as i32; + info.1 = (data[i] & 0xF) as i32 + 1; + } + } + if let Some(mut val) = res.open("minecraft", "textures/font/ascii.png") { + let mut data = Vec::new(); + val.read_to_end(&mut data).unwrap(); + if let Ok(img) = image::load_from_memory(&data) { + let (width, height) = img.dimensions(); + self.page_width = width as f64; + self.page_height = height as f64; + let sw = width / 16; + let sh = height / 16; + for i in 0..256 { + let cx = (i & 0xF) * sw; + let cy = (i >> 4) * sh; + let mut start = true; + 'x_loop: for x in 0..sw { + for y in 0..sh { + let a = img.get_pixel(cx + x, cy + y).data[3]; + if start && a != 0 { + self.font_character_info[i as usize].0 = x as i32; + start = false; + continue 'x_loop; + } else if !start && a != 0 { + continue 'x_loop; + } + } + if !start { + self.font_character_info[i as usize].1 = x as i32; + break; + } + } + } + } + } + } - pub fn new_text(&mut self, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> UIText { - self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b) - } + pub fn new_text(&mut self, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> UIText { + self.new_text_scaled(val, x, y, 1.0, 1.0, r, g, b) + } - pub fn new_text_scaled(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, r: u8, g: u8, b: u8) -> UIText { - self.create_text(val, x, y, sx, sy, 0.0, r, g, b) - } + pub fn new_text_scaled(&mut self, + val: &str, + x: f64, + y: f64, + sx: f64, + sy: f64, + r: u8, + g: u8, + b: u8) + -> UIText { + self.create_text(val, x, y, sx, sy, 0.0, r, g, b) + } - pub fn new_text_rotated(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, rotation: f64, r: u8, g: u8, b: u8) -> UIText { - self.create_text(val, x, y, sx, sy, rotation, r, g, b) - } + pub fn new_text_rotated(&mut self, + val: &str, + x: f64, + y: f64, + sx: f64, + sy: f64, + rotation: f64, + r: u8, + g: u8, + b: u8) + -> UIText { + self.create_text(val, x, y, sx, sy, rotation, r, g, b) + } - fn create_text(&mut self, val: &str, x: f64, y: f64, sx: f64, sy: f64, rotation: f64, r: u8, g: u8, b: u8) -> UIText { - let mut elements = Vec::new(); - let mut offset = 0.0; - for ch in val.chars() { - if ch == ' ' { - offset += 6.0; - continue; - } - let texture = self.character_texture(ch); - let w = self.size_of_char(ch); + fn create_text(&mut self, + val: &str, + x: f64, + y: f64, + sx: f64, + sy: f64, + rotation: f64, + r: u8, + g: u8, + b: u8) + -> UIText { + let mut elements = Vec::new(); + let mut offset = 0.0; + for ch in val.chars() { + if ch == ' ' { + offset += 6.0; + continue; + } + let texture = self.character_texture(ch); + let w = self.size_of_char(ch); - let mut dsx = offset + 2.0; - let mut dsy = 2.0; - let mut dx = offset; - let mut dy = 0.0; - if rotation != 0.0 { - let c = rotation.cos(); - let s = rotation.sin(); - let tmpx = dsx - (w * 0.5); - let tmpy = dsy - (16.0 * 0.5); - dsx = (w * 0.5) + (tmpx*c - tmpy*s); - dsy = (16.0 * 0.5) + (tmpy*c + tmpx*s); - let tmpx = dx - (w * 0.5); - let tmpy = dy - (16.0 * 0.5); - dx = (w * 0.5) + (tmpx*c - tmpy*s); - dy = (16.0 * 0.5) + (tmpy*c + tmpx*s); - } + let mut dsx = offset + 2.0; + let mut dsy = 2.0; + let mut dx = offset; + let mut dy = 0.0; + if rotation != 0.0 { + let c = rotation.cos(); + let s = rotation.sin(); + let tmpx = dsx - (w * 0.5); + let tmpy = dsy - (16.0 * 0.5); + dsx = (w * 0.5) + (tmpx * c - tmpy * s); + dsy = (16.0 * 0.5) + (tmpy * c + tmpx * s); + let tmpx = dx - (w * 0.5); + let tmpy = dy - (16.0 * 0.5); + dx = (w * 0.5) + (tmpx * c - tmpy * s); + dy = (16.0 * 0.5) + (tmpy * c + tmpx * s); + } - let mut shadow = UIElement::new(&texture, x+dsx*sx, y+dsy*sy, w*sx, 16.0*sy, 0.0, 0.0, 1.0, 1.0); - shadow.r = ((r as f64) * 0.25) as u8; - shadow.g = ((g as f64) * 0.25) as u8; - shadow.b = ((b as f64) * 0.25) as u8; - shadow.rotation = rotation; - elements.push(shadow); + let mut shadow = UIElement::new(&texture, + x + dsx * sx, + y + dsy * sy, + w * sx, + 16.0 * sy, + 0.0, + 0.0, + 1.0, + 1.0); + shadow.r = ((r as f64) * 0.25) as u8; + shadow.g = ((g as f64) * 0.25) as u8; + shadow.b = ((b as f64) * 0.25) as u8; + shadow.rotation = rotation; + elements.push(shadow); - let mut text = UIElement::new(&texture, x+dx*sx, y+dy*sy, w*sx, 16.0*sy, 0.0, 0.0, 1.0, 1.0); - text.r = r; - text.g = g; - text.b = b; - text.rotation = rotation; - elements.push(text); - offset += w + 2.0; - } - UIText { - elements: elements, - width: (offset - 2.0) * sx, - } - } + let mut text = UIElement::new(&texture, + x + dx * sx, + y + dy * sy, + w * sx, + 16.0 * sy, + 0.0, + 0.0, + 1.0, + 1.0); + text.r = r; + text.g = g; + text.b = b; + text.rotation = rotation; + elements.push(text); + offset += w + 2.0; + } + UIText { + elements: elements, + width: (offset - 2.0) * sx, + } + } } pub struct UIText { - pub elements: Vec, - pub width: f64, + pub elements: Vec, + pub width: f64, } impl UIText { - pub fn bytes(&self, width: f64, height: f64) -> Vec { - let mut buf = Vec::with_capacity(28*4*self.elements.len()); - for e in &self.elements { - buf.extend(e.bytes(width, height)); - } - buf - } + pub fn bytes(&self, width: f64, height: f64) -> Vec { + let mut buf = Vec::with_capacity(28 * 4 * self.elements.len()); + for e in &self.elements { + buf.extend(e.bytes(width, height)); + } + buf + } } pub struct UIElement { - pub x: f64, - pub y: f64, - pub w: f64, - pub h: f64, - pub layer: isize, - pub t_x: u16, - pub t_y: u16, - pub t_w: u16, - pub t_h: u16, - pub t_offsetx: i16, - pub t_offsety: i16, - pub t_atlas: i16, - pub t_sizew: i16, - pub t_sizeh: i16, - pub r: u8, - pub g: u8, - pub b: u8, - pub a: u8, - pub rotation: f64, + pub x: f64, + pub y: f64, + pub w: f64, + pub h: f64, + pub layer: isize, + pub t_x: u16, + pub t_y: u16, + pub t_w: u16, + pub t_h: u16, + pub t_offsetx: i16, + pub t_offsety: i16, + pub t_atlas: i16, + pub t_sizew: i16, + pub t_sizeh: i16, + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, + pub rotation: f64, } impl UIElement { - pub fn new(tex: &render::Texture, x: f64, y: f64, width: f64, height: f64, tx: f64, ty: f64, tw: f64, th: f64) -> UIElement { - let twidth = tex.get_width(); - let theight = tex.get_height(); - UIElement { - x: x / UI_WIDTH, - y: y / UI_HEIGHT, - w: width / UI_WIDTH, - h: height / UI_HEIGHT, - layer: 0, - t_x: tex.get_x() as u16, - t_y: tex.get_y() as u16, - t_w: twidth as u16, - t_h: theight as u16, - t_atlas: tex.atlas as i16, - t_offsetx: (tx * (twidth as f64) * 16.0) as i16, - t_offsety: (ty * (theight as f64) * 16.0) as i16, - t_sizew: (tw * (twidth as f64) * 16.0) as i16, - t_sizeh: (th * (theight as f64) * 16.0) as i16, - r: 255, - g: 255, - b: 255, - a: 255, - rotation: 0.0, - } - } + pub fn new(tex: &render::Texture, + x: f64, + y: f64, + width: f64, + height: f64, + tx: f64, + ty: f64, + tw: f64, + th: f64) + -> UIElement { + let twidth = tex.get_width(); + let theight = tex.get_height(); + UIElement { + x: x / UI_WIDTH, + y: y / UI_HEIGHT, + w: width / UI_WIDTH, + h: height / UI_HEIGHT, + layer: 0, + t_x: tex.get_x() as u16, + t_y: tex.get_y() as u16, + t_w: twidth as u16, + t_h: theight as u16, + t_atlas: tex.atlas as i16, + t_offsetx: (tx * (twidth as f64) * 16.0) as i16, + t_offsety: (ty * (theight as f64) * 16.0) as i16, + t_sizew: (tw * (twidth as f64) * 16.0) as i16, + t_sizeh: (th * (theight as f64) * 16.0) as i16, + r: 255, + g: 255, + b: 255, + a: 255, + rotation: 0.0, + } + } - pub fn bytes(&self, width: f64, height: f64) -> Vec { - let mut buf = Vec::with_capacity(28*4); - self.append_vertex(&mut buf, self.x, self.y, self.t_offsetx, self.t_offsety, width, height); - self.append_vertex(&mut buf, self.x + self.w, self.y, self.t_offsetx + self.t_sizew, self.t_offsety, width, height); - self.append_vertex(&mut buf, self.x, self.y + self.h, self.t_offsetx, self.t_offsety + self.t_sizeh, width, height); - self.append_vertex(&mut buf, self.x + self.w, self.y + self.h, self.t_offsetx + self.t_sizew, self.t_offsety + self.t_sizeh, width, height); - buf - } + pub fn bytes(&self, width: f64, height: f64) -> Vec { + let mut buf = Vec::with_capacity(28 * 4); + self.append_vertex(&mut buf, + self.x, + self.y, + self.t_offsetx, + self.t_offsety, + width, + height); + self.append_vertex(&mut buf, + self.x + self.w, + self.y, + self.t_offsetx + self.t_sizew, + self.t_offsety, + width, + height); + self.append_vertex(&mut buf, + self.x, + self.y + self.h, + self.t_offsetx, + self.t_offsety + self.t_sizeh, + width, + height); + self.append_vertex(&mut buf, + self.x + self.w, + self.y + self.h, + self.t_offsetx + self.t_sizew, + self.t_offsety + self.t_sizeh, + width, + height); + buf + } - #[allow(unused_must_use)] - pub fn append_vertex(&self, buf: &mut Vec, x: f64, y: f64, tx: i16, ty: i16, width: f64, height: f64) { - let mut dx = x as f64; - let mut dy = y as f64; - if self.rotation != 0.0 { - let c = self.rotation.cos(); - let s = self.rotation.sin(); - let tmpx = dx - self.x - (self.w / 2.0); - let tmpy = dy - self.y - (self.h / 2.0); - dx = (self.w / 2.0) + (tmpx * c - tmpy * s) + self.x; - dy = (self.h / 2.0) + (tmpy * c + tmpx * s) + self.y; - } + #[allow(unused_must_use)] + pub fn append_vertex(&self, + buf: &mut Vec, + x: f64, + y: f64, + tx: i16, + ty: i16, + width: f64, + height: f64) { + let mut dx = x as f64; + let mut dy = y as f64; + if self.rotation != 0.0 { + let c = self.rotation.cos(); + let s = self.rotation.sin(); + let tmpx = dx - self.x - (self.w / 2.0); + let tmpy = dy - self.y - (self.h / 2.0); + dx = (self.w / 2.0) + (tmpx * c - tmpy * s) + self.x; + dy = (self.h / 2.0) + (tmpy * c + tmpx * s) + self.y; + } - buf.write_i16::((dx*width+0.5).floor() as i16); - buf.write_i16::((dy*height+0.5).floor() as i16); - buf.write_i16::((self.layer * 256) as i16); - buf.write_i16::(0); - buf.write_u16::(self.t_x); - buf.write_u16::(self.t_y); - buf.write_u16::(self.t_w); - buf.write_u16::(self.t_h); - buf.write_i16::(tx); - buf.write_i16::(ty); - buf.write_i16::(self.t_atlas); - buf.write_i16::(0); - buf.write_u8(self.r); - buf.write_u8(self.g); - buf.write_u8(self.b); - buf.write_u8(self.a); - } -} \ No newline at end of file + buf.write_i16::((dx * width + 0.5).floor() as i16); + buf.write_i16::((dy * height + 0.5).floor() as i16); + buf.write_i16::((self.layer * 256) as i16); + buf.write_i16::(0); + buf.write_u16::(self.t_x); + buf.write_u16::(self.t_y); + buf.write_u16::(self.t_w); + buf.write_u16::(self.t_h); + buf.write_i16::(tx); + buf.write_i16::(ty); + buf.write_i16::(self.t_atlas); + buf.write_i16::(0); + buf.write_u8(self.r); + buf.write_u8(self.g); + buf.write_u8(self.b); + buf.write_u8(self.a); + } +} diff --git a/src/resources.rs b/src/resources.rs index 5a840b4..1330c96 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -33,7 +33,7 @@ pub trait Pack { pub struct Manager { packs: Vec>, - version: usize, + version: usize, vanilla_chan: Option>, } @@ -41,16 +41,16 @@ pub struct Manager { impl Manager { pub fn new() -> Manager { let mut m = Manager { - packs: Vec::new(), - version: 0, - vanilla_chan: None, + packs: Vec::new(), + version: 0, + vanilla_chan: None, }; m.add_pack(Box::new(InternalPack)); m.download_vanilla(); m } - /// Returns the 'version' of the manager. The version is + /// Returns the 'version' of the manager. The version is /// increase everytime a pack is added or removed. pub fn version(&self) -> usize { self.version @@ -61,7 +61,7 @@ impl Manager { let path = format!("assets/{}/{}", plugin, name); match pack.open(&path) { Some(val) => return Some(val), - None => {}, + None => {} } } None @@ -73,14 +73,14 @@ impl Manager { let path = format!("assets/{}/{}", plugin, name); match pack.open(&path) { Some(val) => ret.push(val), - None => {}, + None => {} } } ret } pub fn tick(&mut self) { - // Check to see if the download of vanilla has completed + // Check to see if the download of vanilla has completed // (if it was started) let mut done = false; if let Some(ref recv) = self.vanilla_chan { @@ -102,9 +102,7 @@ impl Manager { fn load_vanilla(&mut self) { let loc = format!("./resources-{}", RESOURCES_VERSION); let location = path::Path::new(&loc); - self.add_pack(Box::new(DirPack{ - root: location.to_path_buf(), - })) + self.add_pack(Box::new(DirPack { root: location.to_path_buf() })) } fn download_vanilla(&mut self) { @@ -120,9 +118,11 @@ impl Manager { println!("Vanilla assets missing, obtaining"); thread::spawn(move || { let client = hyper::Client::new(); - let url = format!("https://s3.amazonaws.com/Minecraft.Download/versions/{0}/{0}.jar", RESOURCES_VERSION); + let url = format!("https://s3.amazonaws.com/Minecraft.Download/versions/{0}/{0}.jar", + RESOURCES_VERSION); let res = client.get(&url) - .send().unwrap(); + .send() + .unwrap(); let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap(); let length = *res.headers.get::().unwrap(); @@ -140,7 +140,7 @@ impl Manager { let loc = format!("./resources-{}", RESOURCES_VERSION); let location = path::Path::new(&loc); let count = zip.len(); - for i in 0 .. count { + for i in 0..count { let mut file = zip.by_index(i).unwrap(); if !file.name().starts_with("assets/") { continue; @@ -194,7 +194,8 @@ impl io::Read for ProgressRead { fn read(&mut self, buf: &mut [u8]) -> io::Result { let size = try!(self.read.read(buf)); self.progress += size as u64; - println!("Progress: {:.2}", (self.progress as f64) / (self.total as f64)); + println!("Progress: {:.2}", + (self.progress as f64) / (self.total as f64)); Ok(size) } } diff --git a/src/screen/login.rs b/src/screen/login.rs index bcedbc1..1cf2677 100644 --- a/src/screen/login.rs +++ b/src/screen/login.rs @@ -18,65 +18,81 @@ use ui; use render; pub struct Login { - elements: Option, + elements: Option, } struct UIElements { - logo: ui::logo::Logo, - elements: ui::Collection, + logo: ui::logo::Logo, + elements: ui::Collection, } impl Login { - pub fn new() -> Login { - Login { - elements: None, - } - } + pub fn new() -> Login { + Login { elements: None } + } } impl super::Screen for Login { - fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); - let mut elements = ui::Collection::new(); + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); + let mut elements = ui::Collection::new(); // Login - let (mut login, mut txt) = super::new_button_text(renderer, "Login", 0.0, 100.0, 400.0, 40.0); - login.set_v_attach(ui::VAttach::Middle); - login.set_h_attach(ui::HAttach::Center); - let re = ui_container.add(login); - txt.set_parent(&re); - let tre = ui_container.add(txt); - super::button_action(ui_container, re.clone(), Some(tre.clone()), Some(Rc::new(|game, _| { - game.screen_sys.replace_screen(Box::new(super::ServerList::new(None))); - }))); - elements.add(re); - elements.add(tre); + let (mut login, mut txt) = super::new_button_text(renderer, + "Login", + 0.0, + 100.0, + 400.0, + 40.0); + login.set_v_attach(ui::VAttach::Middle); + login.set_h_attach(ui::HAttach::Center); + let re = ui_container.add(login); + txt.set_parent(&re); + let tre = ui_container.add(txt); + super::button_action(ui_container, + re.clone(), + Some(tre.clone()), + Some(Rc::new(|game, _| { + game.screen_sys + .replace_screen(Box::new(super::ServerList::new(None))); + }))); + elements.add(re); + elements.add(tre); // Disclaimer - let mut warn = ui::Text::new(renderer, "Not affiliated with Mojang/Minecraft", 5.0, 5.0, 255, 200, 200); - warn.set_v_attach(ui::VAttach::Bottom); - warn.set_h_attach(ui::HAttach::Right); - elements.add(ui_container.add(warn)); + let mut warn = ui::Text::new(renderer, + "Not affiliated with Mojang/Minecraft", + 5.0, + 5.0, + 255, + 200, + 200); + warn.set_v_attach(ui::VAttach::Bottom); + warn.set_h_attach(ui::HAttach::Right); + elements.add(ui_container.add(warn)); - self.elements = Some(UIElements { - logo: logo, - elements: elements, - }); - } - fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + self.elements = Some(UIElements { + logo: logo, + elements: elements, + }); + } + fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { // Clean up - { - let elements = self.elements.as_mut().unwrap(); - elements.logo.remove(ui_container); - elements.elements.remove_all(ui_container); - } - self.elements = None - } + { + let elements = self.elements.as_mut().unwrap(); + elements.logo.remove(ui_container); + elements.elements.remove_all(ui_container); + } + self.elements = None + } - fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let elements = self.elements.as_mut().unwrap(); + fn tick(&mut self, + delta: f64, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) { + let elements = self.elements.as_mut().unwrap(); - elements.logo.tick(renderer, ui_container); - } -} \ No newline at end of file + elements.logo.tick(renderer, ui_container); + } +} diff --git a/src/screen/mod.rs b/src/screen/mod.rs index deb24b3..acd7d59 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -25,189 +25,318 @@ use ui; #[allow(unused_variables)] pub trait Screen { // Called once - fn init(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {} - fn deinit(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) {} + fn init(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + } + fn deinit(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + } // May be called multiple times - fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); - fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); + fn on_deactive(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container); // Called every frame the screen is active - fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container); + fn tick(&mut self, + delta: f64, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container); // Events - fn on_scroll(&mut self, x: f64, y: f64) {} + fn on_scroll(&mut self, x: f64, y: f64) { + } } struct ScreenInfo { - screen: Box, - init: bool, - active: bool, + screen: Box, + init: bool, + active: bool, } pub struct ScreenSystem { - screens: Vec, - remove_queue: Vec, + screens: Vec, + remove_queue: Vec, } impl ScreenSystem { - pub fn new() -> ScreenSystem { - ScreenSystem { - screens: Vec::new(), - remove_queue: Vec::new(), - } - } + pub fn new() -> ScreenSystem { + ScreenSystem { + screens: Vec::new(), + remove_queue: Vec::new(), + } + } - pub fn add_screen(&mut self, screen: Box) { - self.screens.push(ScreenInfo { - screen: screen, - init: false, - active: false, - }); - } + pub fn add_screen(&mut self, screen: Box) { + self.screens.push(ScreenInfo { + screen: screen, + init: false, + active: false, + }); + } - pub fn pop_screen(&mut self) { - if let Some(screen) = self.screens.pop() { - self.remove_queue.push(screen); - } - } + pub fn pop_screen(&mut self) { + if let Some(screen) = self.screens.pop() { + self.remove_queue.push(screen); + } + } - pub fn replace_screen(&mut self, screen: Box) { - self.pop_screen(); - self.add_screen(screen); - } + pub fn replace_screen(&mut self, screen: Box) { + self.pop_screen(); + self.add_screen(screen); + } - pub fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - for screen in &mut self.remove_queue { - if screen.active { - screen.screen.on_deactive(renderer, ui_container); - } - if screen.init { - screen.screen.deinit(renderer, ui_container); - } - } - self.remove_queue.clear(); - if self.screens.is_empty() { - return; - } + pub fn tick(&mut self, + delta: f64, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) { + for screen in &mut self.remove_queue { + if screen.active { + screen.screen.on_deactive(renderer, ui_container); + } + if screen.init { + screen.screen.deinit(renderer, ui_container); + } + } + self.remove_queue.clear(); + if self.screens.is_empty() { + return; + } // Update state for screens - let len = self.screens.len(); - for screen in &mut self.screens[..len - 1] { - if screen.active { - screen.active = false; - screen.screen.on_deactive(renderer, ui_container); - } - } - let current = self.screens.last_mut().unwrap(); - if !current.init { - current.init = true; - current.screen.init(renderer, ui_container); - } - if !current.active { - current.active = true; - current.screen.on_active(renderer, ui_container); - } + let len = self.screens.len(); + for screen in &mut self.screens[..len - 1] { + if screen.active { + screen.active = false; + screen.screen.on_deactive(renderer, ui_container); + } + } + let current = self.screens.last_mut().unwrap(); + if !current.init { + current.init = true; + current.screen.init(renderer, ui_container); + } + if !current.active { + current.active = true; + current.screen.on_active(renderer, ui_container); + } // Handle current - current.screen.tick(delta, renderer, ui_container); - } + current.screen.tick(delta, renderer, ui_container); + } - pub fn on_scroll(&mut self, x: f64, y: f64) { - if self.screens.is_empty() { - return; - } - let current = self.screens.last_mut().unwrap(); - current.screen.on_scroll(x, y); - } + pub fn on_scroll(&mut self, x: f64, y: f64) { + if self.screens.is_empty() { + return; + } + let current = self.screens.last_mut().unwrap(); + current.screen.on_scroll(x, y); + } } pub fn new_button(renderer: &mut render::Renderer, x: f64, y: f64, w: f64, h: f64) -> ui::Batch { - let mut batch = ui::Batch::new(x, y, w, h); + let mut batch = ui::Batch::new(x, y, w, h); - let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets").relative( - 0.0, 66.0 / 256.0, 200.0 / 256.0, 20.0 / 256.0 - ); + let texture = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/widgets") + .relative(0.0, 66.0 / 256.0, 200.0 / 256.0, 20.0 / 256.0); // Corners - batch.add(ui::Image::new(texture.clone(), 0.0, 0.0, 4.0, 4.0, 0.0, 0.0, 2.0 / 200.0, 2.0 / 20.0, 255, 255, 255)); - batch.add(ui::Image::new(texture.clone(), w - 4.0, 0.0, 4.0, 4.0, 198.0 / 200.0, 0.0, 2.0 / 200.0, 2.0 / 20.0, 255, 255, 255)); - batch.add(ui::Image::new(texture.clone(), 0.0, h - 6.0, 4.0, 6.0, 0.0, 17.0 / 20.0, 2.0 / 200.0, 3.0 / 20.0, 255, 255, 255)); - batch.add(ui::Image::new(texture.clone(), w - 4.0, h - 6.0, 4.0, 6.0, 198.0 / 200.0, 17.0 / 20.0, 2.0 / 200.0, 3.0 / 20.0, 255, 255, 255)); + batch.add(ui::Image::new(texture.clone(), + 0.0, + 0.0, + 4.0, + 4.0, + 0.0, + 0.0, + 2.0 / 200.0, + 2.0 / 20.0, + 255, + 255, + 255)); + batch.add(ui::Image::new(texture.clone(), + w - 4.0, + 0.0, + 4.0, + 4.0, + 198.0 / 200.0, + 0.0, + 2.0 / 200.0, + 2.0 / 20.0, + 255, + 255, + 255)); + batch.add(ui::Image::new(texture.clone(), + 0.0, + h - 6.0, + 4.0, + 6.0, + 0.0, + 17.0 / 20.0, + 2.0 / 200.0, + 3.0 / 20.0, + 255, + 255, + 255)); + batch.add(ui::Image::new(texture.clone(), + w - 4.0, + h - 6.0, + 4.0, + 6.0, + 198.0 / 200.0, + 17.0 / 20.0, + 2.0 / 200.0, + 3.0 / 20.0, + 255, + 255, + 255)); // Widths - batch.add(ui::Image::new(texture.clone().relative( - 2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0 - ), 4.0, 0.0, w - 8.0, 4.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255)); - batch.add(ui::Image::new(texture.clone().relative( - 2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0 - ), 4.0, h - 6.0, w - 8.0, 6.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255)); + batch.add(ui::Image::new(texture.clone() + .relative(2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0), + 4.0, + 0.0, + w - 8.0, + 4.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255)); + batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0, + 17.0 / 20.0, + 196.0 / 200.0, + 3.0 / 20.0), + 4.0, + h - 6.0, + w - 8.0, + 6.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255)); // Heights - batch.add(ui::Image::new(texture.clone().relative( - 0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0 - ), 0.0, 4.0, 4.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255)); - batch.add(ui::Image::new(texture.clone().relative( - 198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0 - ), w - 4.0, 4.0, 4.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255)); + batch.add(ui::Image::new(texture.clone().relative(0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0), + 0.0, + 4.0, + 4.0, + h - 10.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255)); + batch.add(ui::Image::new(texture.clone().relative(198.0 / 200.0, + 2.0 / 20.0, + 2.0 / 200.0, + 15.0 / 20.0), + w - 4.0, + 4.0, + 4.0, + h - 10.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255)); // Center - batch.add(ui::Image::new(texture.clone().relative( - 2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0 - ), 4.0, 4.0, w - 8.0, h - 10.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255)); + batch.add(ui::Image::new(texture.clone().relative(2.0 / 200.0, + 2.0 / 20.0, + 196.0 / 200.0, + 15.0 / 20.0), + 4.0, + 4.0, + w - 8.0, + h - 10.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255)); - batch + batch } -pub fn new_button_text(renderer: &mut render::Renderer, val: &str, x: f64, y: f64, w: f64, h: f64) -> (ui::Batch, ui::Text) { - let batch = new_button(renderer, x, y, w, h); - let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255); - text.set_v_attach(ui::VAttach::Middle); - text.set_h_attach(ui::HAttach::Center); - (batch, text) +pub fn new_button_text(renderer: &mut render::Renderer, + val: &str, + x: f64, + y: f64, + w: f64, + h: f64) + -> (ui::Batch, ui::Text) { + let batch = new_button(renderer, x, y, w, h); + let mut text = ui::Text::new(renderer, val, 0.0, 0.0, 255, 255, 255); + text.set_v_attach(ui::VAttach::Middle); + text.set_h_attach(ui::HAttach::Center); + (batch, text) } -pub fn button_action(ui_container: &mut ui::Container, - btn: ui::ElementRef, txt: Option>, - click: Option -) { - let batch = ui_container.get_mut(&btn); - batch.add_hover_func(Rc::new(move |over, game, ui_container| { - let texture = render::Renderer::get_texture(game.renderer.get_textures_ref(), "gui/widgets").relative( - 0.0, (if over { 86.0 } else { 66.0 }) / 256.0, 200.0 / 256.0, 20.0 / 256.0 - ); +pub fn button_action(ui_container: &mut ui::Container, + btn: ui::ElementRef, + txt: Option>, + click: Option) { + let batch = ui_container.get_mut(&btn); + batch.add_hover_func(Rc::new(move |over, game, ui_container| { + let texture = render::Renderer::get_texture(game.renderer.get_textures_ref(), + "gui/widgets") + .relative(0.0, + (if over { + 86.0 + } else { + 66.0 + }) / 256.0, + 200.0 / 256.0, + 20.0 / 256.0); - { - let batch = ui_container.get_mut(&btn); - for i in 0 .. batch.len() { - let img = batch.get_mut_at::(i); - match i { - _i @ 0 ...3 => img.set_texture(texture.clone()), - 4 => img.set_texture(texture.clone().relative( - 2.0 / 200.0, 0.0, 196.0 / 200.0, 2.0 / 20.0 - )), - 5 => img.set_texture(texture.clone().relative( - 2.0 / 200.0, 17.0 / 20.0, 196.0 / 200.0, 3.0 / 20.0 - )), - 6 => img.set_texture(texture.clone().relative( - 0.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0 - )), - 7 => img.set_texture(texture.clone().relative( - 198.0 / 200.0, 2.0 / 20.0, 2.0 / 200.0, 15.0 / 20.0 - )), - 8 => img.set_texture(texture.clone().relative( - 2.0 / 200.0, 2.0 / 20.0, 196.0 / 200.0, 15.0 / 20.0 - )), - _ => unreachable!(), - } - } - } - let txt = txt.clone(); - if let Some(txt) = txt { - let text = ui_container.get_mut(&txt); - text.set_b(if over { 160 } else { 255 }); - } - })); - if let Some(click) = click { - batch.add_click_func(click); - } -} \ No newline at end of file + { + let batch = ui_container.get_mut(&btn); + for i in 0..batch.len() { + let img = batch.get_mut_at::(i); + match i { + _i @ 0 ...3 => img.set_texture(texture.clone()), + 4 => img.set_texture(texture.clone().relative(2.0 / 200.0, + 0.0, + 196.0 / 200.0, + 2.0 / 20.0)), + 5 => img.set_texture(texture.clone().relative(2.0 / 200.0, + 17.0 / 20.0, + 196.0 / 200.0, + 3.0 / 20.0)), + 6 => img.set_texture(texture.clone().relative(0.0, + 2.0 / 20.0, + 2.0 / 200.0, + 15.0 / 20.0)), + 7 => img.set_texture(texture.clone().relative(198.0 / 200.0, + 2.0 / 20.0, + 2.0 / 200.0, + 15.0 / 20.0)), + 8 => img.set_texture(texture.clone().relative(2.0 / 200.0, + 2.0 / 20.0, + 196.0 / 200.0, + 15.0 / 20.0)), + _ => unreachable!(), + } + } + } + let txt = txt.clone(); + if let Some(txt) = txt { + let text = ui_container.get_mut(&txt); + text.set_b(if over { + 160 + } else { + 255 + }); + } + })); + if let Some(click) = click { + batch.add_click_func(click); + } +} diff --git a/src/screen/server_list.rs b/src/screen/server_list.rs index a0d2d3a..382f5f6 100644 --- a/src/screen/server_list.rs +++ b/src/screen/server_list.rs @@ -29,448 +29,549 @@ use time; use image; use rustc_serialize::base64::FromBase64; use rand; -use rand::{Rng}; +use rand::Rng; pub struct ServerList { - elements: Option, - disconnect_reason: Option, + elements: Option, + disconnect_reason: Option, - needs_reload: Rc>, + needs_reload: Rc>, } struct UIElements { - logo: ui::logo::Logo, - elements: ui::Collection, - servers: Vec, + logo: ui::logo::Logo, + elements: ui::Collection, + servers: Vec, } struct Server { - collection: ui::Collection, - back: ui::ElementRef, - offset: f64, - y: f64, + collection: ui::Collection, + back: ui::ElementRef, + offset: f64, + y: f64, - motd: ui::ElementRef, - ping: ui::ElementRef, - players: ui::ElementRef, - version: ui::ElementRef, + motd: ui::ElementRef, + ping: ui::ElementRef, + players: ui::ElementRef, + version: ui::ElementRef, - icon: ui::ElementRef, - icon_texture: Option, + icon: ui::ElementRef, + icon_texture: Option, - done_ping: bool, - recv: mpsc::Receiver, + done_ping: bool, + recv: mpsc::Receiver, } struct PingInfo { - motd: format::Component, - ping: time::Duration, - exists: bool, - online: i32, - max: i32, - protocol_version: i32, - protocol_name: String, - favicon: Option, + motd: format::Component, + ping: time::Duration, + exists: bool, + online: i32, + max: i32, + protocol_version: i32, + protocol_name: String, + favicon: Option, } impl Server { - fn update_position(&mut self) { - if self.offset < 0.0 { - self.y = self.offset * 200.0; - } else { - self.y = self.offset * 100.0; - } - } + fn update_position(&mut self) { + if self.offset < 0.0 { + self.y = self.offset * 200.0; + } else { + self.y = self.offset * 100.0; + } + } } impl ServerList { - pub fn new(disconnect_reason: Option) -> ServerList { - ServerList { - elements: None, - disconnect_reason: disconnect_reason, - needs_reload: Rc::new(RefCell::new(false)), - } - } + pub fn new(disconnect_reason: Option) -> ServerList { + ServerList { + elements: None, + disconnect_reason: disconnect_reason, + needs_reload: Rc::new(RefCell::new(false)), + } + } - fn reload_server_list(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let elements = self.elements.as_mut().unwrap(); - *self.needs_reload.borrow_mut() = false; - { + fn reload_server_list(&mut self, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) { + let elements = self.elements.as_mut().unwrap(); + *self.needs_reload.borrow_mut() = false; + { // Clean up previous list entries and icons. - let mut tex = renderer.get_textures_ref().write().unwrap(); - for server in &mut elements.servers { - server.collection.remove_all(ui_container); - if let Some(ref icon) = server.icon_texture { - tex.remove_dynamic("steven_icon", &icon); - } - } - } - elements.servers.clear(); + let mut tex = renderer.get_textures_ref().write().unwrap(); + for server in &mut elements.servers { + server.collection.remove_all(ui_container); + if let Some(ref icon) = server.icon_texture { + tex.remove_dynamic("steven_icon", &icon); + } + } + } + elements.servers.clear(); - let file = match fs::File::open("servers.json") { - Ok(val) => val, - Err(_) => return, - }; - let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap(); - let servers = servers_info.find("servers").unwrap().as_array().unwrap(); - let mut offset = 0.0; + let file = match fs::File::open("servers.json") { + Ok(val) => val, + Err(_) => return, + }; + let servers_info: serde_json::Value = serde_json::from_reader(file).unwrap(); + let servers = servers_info.find("servers").unwrap().as_array().unwrap(); + let mut offset = 0.0; // Default icon whilst we ping the servers or if the server doesn't provide one - let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(), "misc/unknown_server"); + let default_icon = render::Renderer::get_texture(renderer.get_textures_ref(), + "misc/unknown_server"); // General gui icons - let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons"); + let icons = render::Renderer::get_texture(renderer.get_textures_ref(), "gui/icons"); - for svr in servers { - let name = svr.find("name").unwrap().as_string().unwrap(); - let address = svr.find("address").unwrap().as_string().unwrap().to_owned(); + for svr in servers { + let name = svr.find("name").unwrap().as_string().unwrap(); + let address = svr.find("address").unwrap().as_string().unwrap().to_owned(); - let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); + let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); // Everything is attached to this - let mut back = ui::Image::new(solid, 0.0, offset * 100.0, 700.0, 100.0, 0.0, 0.0, 1.0, 1.0, 0, 0, 0); - back.set_a(100); - back.set_v_attach(ui::VAttach::Middle); - back.set_h_attach(ui::HAttach::Center); + let mut back = ui::Image::new(solid, + 0.0, + offset * 100.0, + 700.0, + 100.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0, + 0, + 0); + back.set_a(100); + back.set_v_attach(ui::VAttach::Middle); + back.set_h_attach(ui::HAttach::Center); - let (send, recv) = mpsc::channel::(); - let mut server = Server { - collection: ui::Collection::new(), - back: ui_container.add(back), - offset: offset, - y: 0.0, - done_ping: false, - recv: recv, + let (send, recv) = mpsc::channel::(); + let mut server = Server { + collection: ui::Collection::new(), + back: ui_container.add(back), + offset: offset, + y: 0.0, + done_ping: false, + recv: recv, - motd: Default::default(), - ping: Default::default(), - players: Default::default(), - version: Default::default(), + motd: Default::default(), + ping: Default::default(), + players: Default::default(), + version: Default::default(), - icon: Default::default(), - icon_texture: None, - }; - server.collection.add(server.back.clone()); - server.update_position(); + icon: Default::default(), + icon_texture: None, + }; + server.collection.add(server.back.clone()); + server.update_position(); // Make whole entry interactable - { - let back = ui_container.get_mut(&server.back); - let back_ref = server.back.clone(); - let address = address.clone(); - back.add_hover_func(Rc::new(move |over, _, ui_container| { - let back = ui_container.get_mut(&back_ref); - back.set_a(if over { 200 } else { 100 }); - })); + { + let back = ui_container.get_mut(&server.back); + let back_ref = server.back.clone(); + let address = address.clone(); + back.add_hover_func(Rc::new(move |over, _, ui_container| { + let back = ui_container.get_mut(&back_ref); + back.set_a(if over { + 200 + } else { + 100 + }); + })); - back.add_click_func(Rc::new(move |_, _| { - println!("Connecting to {}", address); - })); - } + back.add_click_func(Rc::new(move |_, _| { + println!("Connecting to {}", address); + })); + } // Server name - let mut text = ui::Text::new(renderer, &name, 100.0, 5.0, 255, 255, 255); - text.set_parent(&server.back); - server.collection.add(ui_container.add(text)); + let mut text = ui::Text::new(renderer, &name, 100.0, 5.0, 255, 255, 255); + text.set_parent(&server.back); + server.collection.add(ui_container.add(text)); // Server icon - let mut icon = ui::Image::new(default_icon.clone(), 5.0, 5.0, 90.0, 90.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255); - icon.set_parent(&server.back); - server.icon = server.collection.add(ui_container.add(icon)); + let mut icon = ui::Image::new(default_icon.clone(), + 5.0, + 5.0, + 90.0, + 90.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255); + icon.set_parent(&server.back); + server.icon = server.collection.add(ui_container.add(icon)); // Ping indicator - let mut ping = ui::Image::new(icons.clone(), 5.0, 5.0, 20.0, 16.0, 0.0, 56.0/256.0, 10.0/256.0, 8.0/256.0, 255, 255, 255); - ping.set_h_attach(ui::HAttach::Right); - ping.set_parent(&server.back); - server.ping = server.collection.add(ui_container.add(ping)); + let mut ping = ui::Image::new(icons.clone(), + 5.0, + 5.0, + 20.0, + 16.0, + 0.0, + 56.0 / 256.0, + 10.0 / 256.0, + 8.0 / 256.0, + 255, + 255, + 255); + ping.set_h_attach(ui::HAttach::Right); + ping.set_parent(&server.back); + server.ping = server.collection.add(ui_container.add(ping)); // Player count - let mut players = ui::Text::new(renderer, "???", 30.0, 5.0, 255, 255, 255); - players.set_h_attach(ui::HAttach::Right); - players.set_parent(&server.back); - server.players = server.collection.add(ui_container.add(players)); + let mut players = ui::Text::new(renderer, "???", 30.0, 5.0, 255, 255, 255); + players.set_h_attach(ui::HAttach::Right); + players.set_parent(&server.back); + server.players = server.collection.add(ui_container.add(players)); // Server's message of the day - let mut motd = ui::Formatted::with_width_limit(renderer, Component::Text(TextComponent::new("Connecting...")), 100.0, 23.0, 700.0 - (90.0 + 10.0 + 5.0)); - motd.set_parent(&server.back); - server.motd = server.collection.add(ui_container.add(motd)); + let mut motd = + ui::Formatted::with_width_limit(renderer, + Component::Text(TextComponent::new("Connecting.\ + ..")), + 100.0, + 23.0, + 700.0 - (90.0 + 10.0 + 5.0)); + motd.set_parent(&server.back); + server.motd = server.collection.add(ui_container.add(motd)); // Version information - let mut version = ui::Formatted::with_width_limit(renderer, Component::Text(TextComponent::new("")), 100.0, 5.0, 700.0 - (90.0 + 10.0 + 5.0)); - version.set_v_attach(ui::VAttach::Bottom); - version.set_parent(&server.back); - server.version = server.collection.add(ui_container.add(version)); + let mut version = + ui::Formatted::with_width_limit(renderer, + Component::Text(TextComponent::new("")), + 100.0, + 5.0, + 700.0 - (90.0 + 10.0 + 5.0)); + version.set_v_attach(ui::VAttach::Bottom); + version.set_parent(&server.back); + server.version = server.collection.add(ui_container.add(version)); // Delete entry button - let (mut del, mut txt) = super::new_button_text(renderer, "X", 0.0, 0.0, 25.0, 25.0); - del.set_v_attach(ui::VAttach::Bottom); - del.set_h_attach(ui::HAttach::Right); - del.set_parent(&server.back); - let re = ui_container.add(del); - txt.set_parent(&re); - let tre = ui_container.add(txt); - super::button_action(ui_container, re.clone(), Some(tre.clone()), None); - server.collection.add(re); - server.collection.add(tre); + let (mut del, mut txt) = super::new_button_text(renderer, "X", 0.0, 0.0, 25.0, 25.0); + del.set_v_attach(ui::VAttach::Bottom); + del.set_h_attach(ui::HAttach::Right); + del.set_parent(&server.back); + let re = ui_container.add(del); + txt.set_parent(&re); + let tre = ui_container.add(txt); + super::button_action(ui_container, re.clone(), Some(tre.clone()), None); + server.collection.add(re); + server.collection.add(tre); // Edit entry button - let (mut edit, mut txt) = super::new_button_text(renderer, "E", 25.0, 0.0, 25.0, 25.0); - edit.set_v_attach(ui::VAttach::Bottom); - edit.set_h_attach(ui::HAttach::Right); - edit.set_parent(&server.back); - let re = ui_container.add(edit); - txt.set_parent(&re); - let tre = ui_container.add(txt); - super::button_action(ui_container, re.clone(), Some(tre.clone()), None); - server.collection.add(re); - server.collection.add(tre); + let (mut edit, mut txt) = super::new_button_text(renderer, "E", 25.0, 0.0, 25.0, 25.0); + edit.set_v_attach(ui::VAttach::Bottom); + edit.set_h_attach(ui::HAttach::Right); + edit.set_parent(&server.back); + let re = ui_container.add(edit); + txt.set_parent(&re); + let tre = ui_container.add(txt); + super::button_action(ui_container, re.clone(), Some(tre.clone()), None); + server.collection.add(re); + server.collection.add(tre); - elements.servers.push(server); - offset += 1.0; + elements.servers.push(server); + offset += 1.0; // Don't block the main thread whilst pinging the server - thread::spawn(move || { - match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) { - Ok(res) => { - let mut desc = res.0.description; - format::convert_legacy(&mut desc); - let favicon = if let Some(icon) = res.0.favicon { - let data = icon["data:image/png;base64,".len()..].from_base64().unwrap(); - Some(image::load_from_memory( - &data - ).unwrap()) - } else { - None - }; - drop(send.send(PingInfo { - motd: desc, - ping: res.1, - exists: true, - online: res.0.players.online, - max: res.0.players.max, - protocol_version: res.0.version.protocol, - protocol_name: res.0.version.name, - favicon: favicon, - })); - }, - Err(err) => { - let e = format!("{}", err); - let mut msg = TextComponent::new(&e); - msg.modifier.color = Some(format::Color::Red); - drop(send.send(PingInfo { - motd: Component::Text(msg), - ping: time::Duration::seconds(99999), - exists: false, - online: 0, - max: 0, - protocol_version: 0, - protocol_name: "".to_owned(), - favicon: None, - })); - }, - } - }); - } - } + thread::spawn(move || { + match protocol::Conn::new(&address).and_then(|conn| conn.do_status()) { + Ok(res) => { + let mut desc = res.0.description; + format::convert_legacy(&mut desc); + let favicon = if let Some(icon) = res.0.favicon { + let data = icon["data:image/png;base64,".len()..] + .from_base64() + .unwrap(); + Some(image::load_from_memory(&data).unwrap()) + } else { + None + }; + drop(send.send(PingInfo { + motd: desc, + ping: res.1, + exists: true, + online: res.0.players.online, + max: res.0.players.max, + protocol_version: res.0.version.protocol, + protocol_name: res.0.version.name, + favicon: favicon, + })); + } + Err(err) => { + let e = format!("{}", err); + let mut msg = TextComponent::new(&e); + msg.modifier.color = Some(format::Color::Red); + drop(send.send(PingInfo { + motd: Component::Text(msg), + ping: time::Duration::seconds(99999), + exists: false, + online: 0, + max: 0, + protocol_version: 0, + protocol_name: "".to_owned(), + favicon: None, + })); + } + } + }); + } + } } impl super::Screen for ServerList { - fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); - let mut elements = ui::Collection::new(); + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); + let mut elements = ui::Collection::new(); // Refresh the server list - let (mut refresh, mut txt) = super::new_button_text(renderer, "Refresh", 300.0, -50.0-15.0, 100.0, 30.0); - refresh.set_v_attach(ui::VAttach::Middle); - refresh.set_h_attach(ui::HAttach::Center); - let re = ui_container.add(refresh); - txt.set_parent(&re); - let tre = ui_container.add(txt); - let nr = self.needs_reload.clone(); - super::button_action(ui_container, re.clone(), Some(tre.clone()), Some(Rc::new(move |_, _| { - *nr.borrow_mut() = true; - }))); - elements.add(re); - elements.add(tre); + let (mut refresh, mut txt) = super::new_button_text(renderer, + "Refresh", + 300.0, + -50.0 - 15.0, + 100.0, + 30.0); + refresh.set_v_attach(ui::VAttach::Middle); + refresh.set_h_attach(ui::HAttach::Center); + let re = ui_container.add(refresh); + txt.set_parent(&re); + let tre = ui_container.add(txt); + let nr = self.needs_reload.clone(); + super::button_action(ui_container, + re.clone(), + Some(tre.clone()), + Some(Rc::new(move |_, _| { + *nr.borrow_mut() = true; + }))); + elements.add(re); + elements.add(tre); // Add a new server to the list - let (mut add, mut txt) = super::new_button_text(renderer, "Add", 200.0, -50.0-15.0, 100.0, 30.0); - add.set_v_attach(ui::VAttach::Middle); - add.set_h_attach(ui::HAttach::Center); - let re = ui_container.add(add); - txt.set_parent(&re); - let tre = ui_container.add(txt); - super::button_action(ui_container, re.clone(), Some(tre.clone()), None); - elements.add(re); - elements.add(tre); + let (mut add, mut txt) = super::new_button_text(renderer, + "Add", + 200.0, + -50.0 - 15.0, + 100.0, + 30.0); + add.set_v_attach(ui::VAttach::Middle); + add.set_h_attach(ui::HAttach::Center); + let re = ui_container.add(add); + txt.set_parent(&re); + let tre = ui_container.add(txt); + super::button_action(ui_container, re.clone(), Some(tre.clone()), None); + elements.add(re); + elements.add(tre); // Options menu - let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0); - options.set_v_attach(ui::VAttach::Bottom); - options.set_h_attach(ui::HAttach::Right); - let re = ui_container.add(options); - let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), "steven:gui/cog"), 0.0, 0.0, 40.0, 40.0, 0.0, 0.0, 1.0, 1.0, 255, 255, 255); - cog.set_parent(&re); - cog.set_v_attach(ui::VAttach::Middle); - cog.set_h_attach(ui::HAttach::Center); - super::button_action(ui_container, re.clone(), None, None); - elements.add(re); - elements.add(ui_container.add(cog)); - + let mut options = super::new_button(renderer, 5.0, 25.0, 40.0, 40.0); + options.set_v_attach(ui::VAttach::Bottom); + options.set_h_attach(ui::HAttach::Right); + let re = ui_container.add(options); + let mut cog = ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), + "steven:gui/cog"), + 0.0, + 0.0, + 40.0, + 40.0, + 0.0, + 0.0, + 1.0, + 1.0, + 255, + 255, + 255); + cog.set_parent(&re); + cog.set_v_attach(ui::VAttach::Middle); + cog.set_h_attach(ui::HAttach::Center); + super::button_action(ui_container, re.clone(), None, None); + elements.add(re); + elements.add(ui_container.add(cog)); + // Disclaimer - let mut warn = ui::Text::new(renderer, "Not affiliated with Mojang/Minecraft", 5.0, 5.0, 255, 200, 200); - warn.set_v_attach(ui::VAttach::Bottom); - warn.set_h_attach(ui::HAttach::Right); - elements.add(ui_container.add(warn)); + let mut warn = ui::Text::new(renderer, + "Not affiliated with Mojang/Minecraft", + 5.0, + 5.0, + 255, + 200, + 200); + warn.set_v_attach(ui::VAttach::Bottom); + warn.set_h_attach(ui::HAttach::Right); + elements.add(ui_container.add(warn)); // If we are kicked from a server display the reason - if let Some(ref disconnect_reason) = self.disconnect_reason { - let mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0); - dis_msg.set_h_attach(ui::HAttach::Center); - let mut dis = ui::Formatted::with_width_limit(renderer, disconnect_reason.clone(), 0.0, 48.0, 600.0); - dis.set_h_attach(ui::HAttach::Center); - let mut back = ui::Image::new( - render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"), - 0.0, 30.0, - dis.get_width().max(dis_msg.get_width()) + 4.0, dis.get_height() + 4.0 + 16.0, - 0.0, 0.0, 1.0, 1.0, - 0, 0, 0 - ); - back.set_a(100); - back.set_h_attach(ui::HAttach::Center); - elements.add(ui_container.add(back)); - elements.add(ui_container.add(dis)); - elements.add(ui_container.add(dis_msg)); - } + if let Some(ref disconnect_reason) = self.disconnect_reason { + let mut dis_msg = ui::Text::new(renderer, "Disconnected", 0.0, 32.0, 255, 0, 0); + dis_msg.set_h_attach(ui::HAttach::Center); + let mut dis = ui::Formatted::with_width_limit(renderer, + disconnect_reason.clone(), + 0.0, + 48.0, + 600.0); + dis.set_h_attach(ui::HAttach::Center); + let mut back = + ui::Image::new(render::Renderer::get_texture(renderer.get_textures_ref(), + "steven:solid"), + 0.0, + 30.0, + dis.get_width().max(dis_msg.get_width()) + 4.0, + dis.get_height() + 4.0 + 16.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0, + 0, + 0); + back.set_a(100); + back.set_h_attach(ui::HAttach::Center); + elements.add(ui_container.add(back)); + elements.add(ui_container.add(dis)); + elements.add(ui_container.add(dis_msg)); + } - self.elements = Some(UIElements { - logo: logo, - elements: elements, - servers: Vec::new(), - }); - self.reload_server_list(renderer, ui_container); - } - fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + self.elements = Some(UIElements { + logo: logo, + elements: elements, + servers: Vec::new(), + }); + self.reload_server_list(renderer, ui_container); + } + fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { // Clean up - { - let elements = self.elements.as_mut().unwrap(); - elements.logo.remove(ui_container); - elements.elements.remove_all(ui_container); - for server in &mut elements.servers { - server.collection.remove_all(ui_container); - } - elements.servers.clear(); - } - self.elements = None - } + { + let elements = self.elements.as_mut().unwrap(); + elements.logo.remove(ui_container); + elements.elements.remove_all(ui_container); + for server in &mut elements.servers { + server.collection.remove_all(ui_container); + } + elements.servers.clear(); + } + self.elements = None + } - fn tick(&mut self, delta: f64, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - if *self.needs_reload.borrow() { - self.reload_server_list(renderer, ui_container); - } - let elements = self.elements.as_mut().unwrap(); + fn tick(&mut self, + delta: f64, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) { + if *self.needs_reload.borrow() { + self.reload_server_list(renderer, ui_container); + } + let elements = self.elements.as_mut().unwrap(); - elements.logo.tick(renderer, ui_container); + elements.logo.tick(renderer, ui_container); - for s in &mut elements.servers { + for s in &mut elements.servers { // Animate the entries - { - let back = ui_container.get_mut(&s.back); - let dy = s.y - back.get_y(); - if dy*dy > 1.0 { - let y = back.get_y(); - back.set_y(y + delta * dy * 0.1); - } else { - back.set_y(s.y); - } - } + { + let back = ui_container.get_mut(&s.back); + let dy = s.y - back.get_y(); + if dy * dy > 1.0 { + let y = back.get_y(); + back.set_y(y + delta * dy * 0.1); + } else { + back.set_y(s.y); + } + } - // Keep checking to see if the server has finished being + // Keep checking to see if the server has finished being // pinged - if !s.done_ping { - match s.recv.try_recv() { - Ok(res) => { - s.done_ping = true; - { - let motd = ui_container.get_mut(&s.motd); - motd.set_component(renderer, res.motd); - } - { - let ping = ui_container.get_mut(&s.ping); + if !s.done_ping { + match s.recv.try_recv() { + Ok(res) => { + s.done_ping = true; + { + let motd = ui_container.get_mut(&s.motd); + motd.set_component(renderer, res.motd); + } + { + let ping = ui_container.get_mut(&s.ping); // Selects the icon for the given ping range - let y = match res.ping.num_milliseconds() { - _x @ 0 ... 75 => 16.0 / 256.0, - _x @ 76 ... 150 => 24.0 / 256.0, - _x @ 151 ... 225 => 32.0 / 256.0, - _x @ 226 ... 350 => 40.0 / 256.0, - _x @ 351 ... 999 => 48.0 / 256.0, - _ => 56.0 / 256.0, - }; - ping.set_t_y(y); - } - if res.exists { - { - let players = ui_container.get_mut(&s.players); - let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL { - players.set_g(255); - players.set_b(255); - format!("{}/{}", res.online, res.max) - } else { - players.set_g(85); - players.set_b(85); - format!("Out of date {}/{}", res.online, res.max) - }; - players.set_text(renderer, &txt); - } - { - let version = ui_container.get_mut(&s.version); - let mut txt = TextComponent::new(&res.protocol_name); - txt.modifier.color = Some(format::Color::Yellow); - let mut msg = Component::Text(txt); - format::convert_legacy(&mut msg); - version.set_component(renderer, msg); - } - } - if let Some(favicon) = res.favicon { - let name: String = rand::thread_rng().gen_ascii_chars().take(30).collect(); - let tex = renderer.get_textures_ref(); - s.icon_texture = Some(name.clone()); - let icon_tex = tex.write().unwrap().put_dynamic("steven_icon", &name, favicon); - let icon = ui_container.get_mut(&s.icon); - icon.set_texture(icon_tex); - } - }, - Err(mpsc::TryRecvError::Disconnected) => { - s.done_ping = true; - let motd = ui_container.get_mut(&s.motd); - let mut txt = TextComponent::new("Channel dropped"); - txt.modifier.color = Some(format::Color::Red); - motd.set_component(renderer, Component::Text(txt)); - }, - _ => {} - } - } - } - } + let y = match res.ping.num_milliseconds() { + _x @ 0 ... 75 => 16.0 / 256.0, + _x @ 76 ... 150 => 24.0 / 256.0, + _x @ 151 ... 225 => 32.0 / 256.0, + _x @ 226 ... 350 => 40.0 / 256.0, + _x @ 351 ... 999 => 48.0 / 256.0, + _ => 56.0 / 256.0, + }; + ping.set_t_y(y); + } + if res.exists { + { + let players = ui_container.get_mut(&s.players); + let txt = if res.protocol_version == protocol::SUPPORTED_PROTOCOL { + players.set_g(255); + players.set_b(255); + format!("{}/{}", res.online, res.max) + } else { + players.set_g(85); + players.set_b(85); + format!("Out of date {}/{}", res.online, res.max) + }; + players.set_text(renderer, &txt); + } + { + let version = ui_container.get_mut(&s.version); + let mut txt = TextComponent::new(&res.protocol_name); + txt.modifier.color = Some(format::Color::Yellow); + let mut msg = Component::Text(txt); + format::convert_legacy(&mut msg); + version.set_component(renderer, msg); + } + } + if let Some(favicon) = res.favicon { + let name: String = rand::thread_rng() + .gen_ascii_chars() + .take(30) + .collect(); + let tex = renderer.get_textures_ref(); + s.icon_texture = Some(name.clone()); + let icon_tex = tex.write() + .unwrap() + .put_dynamic("steven_icon", &name, favicon); + let icon = ui_container.get_mut(&s.icon); + icon.set_texture(icon_tex); + } + } + Err(mpsc::TryRecvError::Disconnected) => { + s.done_ping = true; + let motd = ui_container.get_mut(&s.motd); + let mut txt = TextComponent::new("Channel dropped"); + txt.modifier.color = Some(format::Color::Red); + motd.set_component(renderer, Component::Text(txt)); + } + _ => {} + } + } + } + } - fn on_scroll(&mut self, _: f64, y: f64) { - let elements = self.elements.as_mut().unwrap(); - if elements.servers.is_empty() { - return; - } - let mut diff = y / 1.0; - { - let last = elements.servers.last().unwrap(); - if last.offset+diff <= 2.0 { - diff = 2.0 - last.offset; - } - let first = elements.servers.first().unwrap(); - if first.offset + diff >= 0.0 { - diff = -first.offset; - } - } + fn on_scroll(&mut self, _: f64, y: f64) { + let elements = self.elements.as_mut().unwrap(); + if elements.servers.is_empty() { + return; + } + let mut diff = y / 1.0; + { + let last = elements.servers.last().unwrap(); + if last.offset + diff <= 2.0 { + diff = 2.0 - last.offset; + } + let first = elements.servers.first().unwrap(); + if first.offset + diff >= 0.0 { + diff = -first.offset; + } + } - for s in &mut elements.servers { - s.offset += diff; - s.update_position(); - } - } -} \ No newline at end of file + for s in &mut elements.servers { + s.offset += diff; + s.update_position(); + } + } +} diff --git a/src/types/bit/map.rs b/src/types/bit/map.rs index b1b9e05..4814f2a 100644 --- a/src/types/bit/map.rs +++ b/src/types/bit/map.rs @@ -15,14 +15,14 @@ pub struct Map { bits: Vec, bit_size: usize, - length: usize + length: usize, } #[test] fn test_map() { let mut map = Map::new(4096, 4); - for i in 0 .. 4096 { - for j in 0 .. 16 { + for i in 0..4096 { + for j in 0..16 { map.set(i, j); if map.get(i) != j { panic!("Fail"); @@ -33,11 +33,11 @@ fn test_map() { #[test] fn test_map_odd() { - for size in 1 .. 16 { - let mut map = Map::new(64*3, size); + for size in 1..16 { + let mut map = Map::new(64 * 3, size); let max = (1 << size) - 1; - for i in 0 .. 64*3 { - for j in 0 .. max { + for i in 0..64 * 3 { + for j in 0..max { map.set(i, j); if map.get(i) != j { panic!("Index: {} wanted {} and got {}", i, j, map.get(i)); @@ -52,9 +52,9 @@ impl Map { let mut map = Map { bit_size: size, length: len, - bits: Vec::with_capacity((len*size)/64) + bits: Vec::with_capacity((len * size) / 64), }; - for _ in 0 .. len { + for _ in 0..len { map.bits.push(0) } map @@ -62,7 +62,7 @@ impl Map { pub fn resize(self, size: usize) -> Map { let mut n = Map::new(self.length, size); - for i in 0 .. self.length { + for i in 0..self.length { n.set(i, self.get(i)); } n @@ -73,7 +73,7 @@ impl Map { let pos = i / 64; let mask = (1 << self.bit_size) - 1; let ii = i % 64; - self.bits[pos] = (self.bits[pos] & !(mask << ii )) | ((val << ii) as u64); + self.bits[pos] = (self.bits[pos] & !(mask << ii)) | ((val << ii) as u64); let pos2 = (i + self.bit_size - 1) / 64; if pos2 != pos { let used = 64 - ii; diff --git a/src/types/bit/set.rs b/src/types/bit/set.rs index e74f6c5..123b0f9 100644 --- a/src/types/bit/set.rs +++ b/src/types/bit/set.rs @@ -13,19 +13,19 @@ // limitations under the License. pub struct Set { - data : Vec + data: Vec, } #[test] fn test_set() { let mut set = Set::new(200); - for i in 0 .. 200 { + for i in 0..200 { if i % 3 == 0 { set.set(i, true) } } - for i in 0 .. 200 { - if set.get(i) != (i%3 == 0) { + for i in 0..200 { + if set.get(i) != (i % 3 == 0) { panic!("Fail") } } @@ -33,10 +33,8 @@ fn test_set() { impl Set { pub fn new(size: usize) -> Set { - let mut set = Set { - data: Vec::with_capacity(size) - }; - for _ in 0 .. size { + let mut set = Set { data: Vec::with_capacity(size) }; + for _ in 0..size { set.data.push(0) } set @@ -44,13 +42,13 @@ impl Set { pub fn set(&mut self, i: usize, v: bool) { if v { - self.data[i>>6] |= 1 << (i & 0x3F) + self.data[i >> 6] |= 1 << (i & 0x3F) } else { - self.data[i>>6] &= !(1 << (i & 0x3F)) + self.data[i >> 6] &= !(1 << (i & 0x3F)) } } pub fn get(&mut self, i: usize) -> bool { - (self.data[i>>6] & (1 << (i & 0x3F))) != 0 + (self.data[i >> 6] & (1 << (i & 0x3F))) != 0 } } diff --git a/src/types/blockpos.rs b/src/types/blockpos.rs index cc38604..8455811 100644 --- a/src/types/blockpos.rs +++ b/src/types/blockpos.rs @@ -15,7 +15,7 @@ extern crate byteorder; use std::fmt; -use protocol::{Serializable}; +use protocol::Serializable; use std::io; use std::io::{Read, Write}; use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; @@ -26,11 +26,8 @@ pub struct Position(u64); impl Position { #[allow(dead_code)] fn new(x: i32, y: i32, z: i32) -> Position { - Position( - (((x as u64) & 0x3FFFFFF) << 38) | - (((y as u64) & 0xFFF) << 26) | - ((z as u64) & 0x3FFFFFF) - ) + Position((((x as u64) & 0x3FFFFFF) << 38) | (((y as u64) & 0xFFF) << 26) | + ((z as u64) & 0x3FFFFFF)) } fn get_x(&self) -> i32 { diff --git a/src/types/metadata.rs b/src/types/metadata.rs index f4281b6..b7443f3 100644 --- a/src/types/metadata.rs +++ b/src/types/metadata.rs @@ -18,7 +18,7 @@ use std::io; use std::io::{Read, Write}; use std::fmt; use protocol; -use protocol::{Serializable}; +use protocol::Serializable; use format; use item; @@ -30,7 +30,7 @@ pub struct MetadataKey { impl MetadataKey { #[allow(dead_code)] // TODO: Make const later when possible - /*const*/ fn new(index: i32) -> MetadataKey { + /*const*/ fn new(index: i32) -> MetadataKey { MetadataKey { index: index, ty: PhantomData, @@ -78,11 +78,10 @@ impl Serializable for Metadata { 4 => m.put_raw(index, try!(format::Component::read_from(buf))), 5 => m.put_raw(index, try!(Option::::read_from(buf))), 6 => m.put_raw(index, try!(bool::read_from(buf))), - 7 => m.put_raw(index, [ - try!(f32::read_from(buf)), - try!(f32::read_from(buf)), - try!(f32::read_from(buf)) - ]), + 7 => m.put_raw(index, + [try!(f32::read_from(buf)), + try!(f32::read_from(buf)), + try!(f32::read_from(buf))]), 8 => m.put_raw(index, try!(super::Position::read_from(buf))), 9 => { if try!(bool::read_from(buf)) { @@ -90,7 +89,7 @@ impl Serializable for Metadata { } else { m.put_raw::>(index, None); } - }, + } 10 => m.put_raw(index, try!(protocol::VarInt::read_from(buf))), 11 => { if try!(bool::read_from(buf)) { @@ -98,9 +97,11 @@ impl Serializable for Metadata { } else { m.put_raw::>(index, None); } - }, + } 12 => m.put_raw(index, try!(protocol::VarInt::read_from(buf)).0 as u16), - _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, protocol::Error::Err("unknown metadata type".to_owned()))), + _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, + protocol::Error::Err("unknown metadata type" + .to_owned()))), } } Ok(m) @@ -113,46 +114,46 @@ impl Serializable for Metadata { Value::Byte(ref val) => { try!(u8::write_to(&0, buf)); try!(val.write_to(buf)); - }, + } Value::Int(ref val) => { try!(u8::write_to(&1, buf)); try!(protocol::VarInt(*val).write_to(buf)); - }, + } Value::Float(ref val) => { try!(u8::write_to(&2, buf)); try!(val.write_to(buf)); - }, + } Value::String(ref val) => { try!(u8::write_to(&3, buf)); try!(val.write_to(buf)); - }, + } Value::FormatComponent(ref val) => { try!(u8::write_to(&4, buf)); try!(val.write_to(buf)); - }, + } Value::OptionalItemStack(ref val) => { try!(u8::write_to(&5, buf)); try!(val.write_to(buf)); - }, + } Value::Bool(ref val) => { try!(u8::write_to(&6, buf)); try!(val.write_to(buf)); - }, + } Value::Vector(ref val) => { try!(u8::write_to(&7, buf)); try!(val[0].write_to(buf)); try!(val[1].write_to(buf)); try!(val[2].write_to(buf)); - }, + } Value::Position(ref val) => { try!(u8::write_to(&8, buf)); try!(val.write_to(buf)); - }, + } Value::OptionalPosition(ref val) => { try!(u8::write_to(&9, buf)); try!(val.is_some().write_to(buf)); try!(val.write_to(buf)); - }, + } Value::Direction(ref val) => { try!(u8::write_to(&10, buf)); try!(val.write_to(buf)); @@ -161,7 +162,7 @@ impl Serializable for Metadata { try!(u8::write_to(&11, buf)); try!(val.is_some().write_to(buf)); try!(val.write_to(buf)); - }, + } Value::Block(ref val) => { try!(u8::write_to(&11, buf)); try!(protocol::VarInt(*val as i32).write_to(buf)); @@ -374,9 +375,9 @@ mod test { const TEST: MetadataKey = MetadataKey { - index: 0, - ty: PhantomData, - }; + index: 0, + ty: PhantomData, + }; #[test] fn basic() { diff --git a/src/types/mod.rs b/src/types/mod.rs index 034015f..ca88128 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -18,4 +18,4 @@ pub use self::blockpos::*; mod metadata; pub use self::metadata::*; -pub mod bit; \ No newline at end of file +pub mod bit; diff --git a/src/ui/batch.rs b/src/ui/batch.rs index b6586ba..535ee8a 100644 --- a/src/ui/batch.rs +++ b/src/ui/batch.rs @@ -14,8 +14,8 @@ #[derive(Clone, Copy)] pub struct BatchRef { - index: usize, - ty: PhantomData, + index: usize, + ty: PhantomData, } ui_element!(Batch { @@ -28,83 +28,93 @@ ui_element!(Batch { impl Batch { base_impl!(); - pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch { - ui_create!(Batch { - x: x, - y: y, - width: w, - height: h, + pub fn new(x: f64, y: f64, w: f64, h: f64) -> Batch { + ui_create!(Batch { + x: x, + y: y, + width: w, + height: h, - elements: Vec::new() - }) - } + elements: Vec::new(), + }) + } - fn update(&mut self, _: &mut render::Renderer) {} + fn update(&mut self, _: &mut render::Renderer) { + } - fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec { - if self.dirty { - self.dirty = false; - self.data.clear(); + fn draw(&mut self, + renderer: &mut render::Renderer, + r: &Region, + width: f64, + height: f64, + delta: f64) + -> &Vec { + if self.dirty { + self.dirty = false; + self.data.clear(); - let sx = r.w / self.width; - let sy = r.h / self.height; + let sx = r.w / self.width; + let sy = r.h / self.height; - for e in &mut self.elements { - let reg = Container::get_draw_region_raw(e, sx, sy, r); - e.set_dirty(true); - self.data.extend(e.draw(renderer, ®, width, height, delta)); - } - } - &self.data - } + for e in &mut self.elements { + let reg = Container::get_draw_region_raw(e, sx, sy, r); + e.set_dirty(true); + self.data.extend(e.draw(renderer, ®, width, height, delta)); + } + } + &self.data + } - pub fn get_size(&self) -> (f64, f64) { - (self.width, self.height) - } + pub fn get_size(&self) -> (f64, f64) { + (self.width, self.height) + } - pub fn add(&mut self, e: T) -> BatchRef { - self.elements.push(e.wrap()); - BatchRef { index: self.elements.len() - 1, ty: PhantomData } - } + pub fn add(&mut self, e: T) -> BatchRef { + self.elements.push(e.wrap()); + BatchRef { + index: self.elements.len() - 1, + ty: PhantomData, + } + } - pub fn get(&self, r: BatchRef) -> &T { - T::unwrap_ref(&self.elements[r.index]) - } + pub fn get(&self, r: BatchRef) -> &T { + T::unwrap_ref(&self.elements[r.index]) + } - pub fn get_mut(&mut self, r: BatchRef) -> &mut T { - self.dirty = true; - T::unwrap_ref_mut(&mut self.elements[r.index]) - } + pub fn get_mut(&mut self, r: BatchRef) -> &mut T { + self.dirty = true; + T::unwrap_ref_mut(&mut self.elements[r.index]) + } - pub fn get_mut_at(&mut self, index: usize) -> &mut T { - self.dirty = true; - T::unwrap_ref_mut(&mut self.elements[index]) - } + pub fn get_mut_at(&mut self, index: usize) -> &mut T { + self.dirty = true; + T::unwrap_ref_mut(&mut self.elements[index]) + } - pub fn len(&self) -> usize { - self.elements.len() - } + pub fn len(&self) -> usize { + self.elements.len() + } lazy_field!(width, f64, get_width, set_width); lazy_field!(height, f64, get_height, set_height); } impl UIElement for Batch { - fn wrap(self) -> Element { - Element::Batch(self) - } + fn wrap(self) -> Element { + Element::Batch(self) + } - fn unwrap_ref<'a>(e: &'a Element) -> &'a Batch { - match e { - &Element::Batch(ref val) => val, - _ => panic!("Incorrect type"), - } - } + fn unwrap_ref<'a>(e: &'a Element) -> &'a Batch { + match e { + &Element::Batch(ref val) => val, + _ => panic!("Incorrect type"), + } + } - fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Batch { - match e { - &mut Element::Batch(ref mut val) => val, - _ => panic!("Incorrect type"), - } - } -} \ No newline at end of file + fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Batch { + match e { + &mut Element::Batch(ref mut val) => val, + _ => panic!("Incorrect type"), + } + } +} diff --git a/src/ui/formatted.rs b/src/ui/formatted.rs index 6fc1791..9d23604 100644 --- a/src/ui/formatted.rs +++ b/src/ui/formatted.rs @@ -27,88 +27,104 @@ ui_element!(Formatted { impl Formatted { base_impl!(); - pub fn new(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64) -> Formatted { - let mut f = ui_create!(Formatted { - val: val, - x: x, - y: y, - width: 0.0, - height: 18.0, - scale_x: 1.0, - scale_y: 1.0, + pub fn new(renderer: &mut render::Renderer, + val: format::Component, + x: f64, + y: f64) + -> Formatted { + let mut f = ui_create!(Formatted { + val: val, + x: x, + y: y, + width: 0.0, + height: 18.0, + scale_x: 1.0, + scale_y: 1.0, - text: Vec::new(), - max_width: -1.0, - lines: 0 - }); - f.init_component(renderer); - f - } + text: Vec::new(), + max_width: -1.0, + lines: 0, + }); + f.init_component(renderer); + f + } - pub fn with_width_limit(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64, max_width: f64) -> Formatted { - let mut f = ui_create!(Formatted { - val: val, - x: x, - y: y, - width: 0.0, - height: 18.0, - scale_x: 1.0, - scale_y: 1.0, + pub fn with_width_limit(renderer: &mut render::Renderer, + val: format::Component, + x: f64, + y: f64, + max_width: f64) + -> Formatted { + let mut f = ui_create!(Formatted { + val: val, + x: x, + y: y, + width: 0.0, + height: 18.0, + scale_x: 1.0, + scale_y: 1.0, - text: Vec::new(), - max_width: max_width, - lines: 0 - }); - f.init_component(renderer); - f - } - - pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) { - self.val = val; - self.init_component(renderer); - } + text: Vec::new(), + max_width: max_width, + lines: 0, + }); + f.init_component(renderer); + f + } - fn init_component(&mut self, renderer: &mut render::Renderer) { - self.text.clear(); - let mut state = FormatState { - lines: 0, - width: 0.0, - offset: 0.0, - text: Vec::new(), - max_width: self.max_width, - renderer: &renderer, - }; - state.build(&self.val, format::Color::White); - self.height = (state.lines + 1) as f64 * 18.0; - self.width = state.width; - self.lines = state.lines; - self.text = state.text; - self.dirty = true; - } + pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) { + self.val = val; + self.init_component(renderer); + } - fn update(&mut self, renderer: &mut render::Renderer) { - self.init_component(renderer); - } + fn init_component(&mut self, renderer: &mut render::Renderer) { + self.text.clear(); + let mut state = FormatState { + lines: 0, + width: 0.0, + offset: 0.0, + text: Vec::new(), + max_width: self.max_width, + renderer: &renderer, + }; + state.build(&self.val, format::Color::White); + self.height = (state.lines + 1) as f64 * 18.0; + self.width = state.width; + self.lines = state.lines; + self.text = state.text; + self.dirty = true; + } - fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec { - if self.dirty { - self.dirty = false; - self.data.clear(); - let sx = r.w / self.width; - let sy = r.h / self.height; + fn update(&mut self, renderer: &mut render::Renderer) { + self.init_component(renderer); + } - for e in &mut self.text { - let reg = Container::get_draw_region_raw(e, sx, sy, r); - e.set_dirty(true); - self.data.extend(e.draw(renderer, ®, width, height, delta)); - } - } - &self.data - } + fn draw(&mut self, + renderer: &mut render::Renderer, + r: &Region, + width: f64, + height: f64, + delta: f64) + -> &Vec { + if self.dirty { + self.dirty = false; + self.data.clear(); + let sx = r.w / self.width; + let sy = r.h / self.height; - pub fn get_size(&self) -> (f64, f64) { - ((self.width + 2.0) * self.scale_x, self.height * self.scale_y) - } + for e in &mut self.text { + let reg = Container::get_draw_region_raw(e, sx, sy, r); + e.set_dirty(true); + self.data.extend(e.draw(renderer, ®, width, height, delta)); + } + } + &self.data + } + + pub fn get_size(&self) -> (f64, f64) { + ((self.width + 2.0) * self.scale_x, + self.height * self.scale_y) + } lazy_field!(width, f64, get_width, set_width); lazy_field!(height, f64, get_height, set_height); @@ -118,87 +134,97 @@ impl Formatted { } impl UIElement for Formatted { - fn wrap(self) -> Element { - Element::Formatted(self) - } + fn wrap(self) -> Element { + Element::Formatted(self) + } - fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted { - match e { - &Element::Formatted(ref val) => val, - _ => panic!("Incorrect type"), - } - } + fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted { + match e { + &Element::Formatted(ref val) => val, + _ => panic!("Incorrect type"), + } + } - fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted { - match e { - &mut Element::Formatted(ref mut val) => val, - _ => panic!("Incorrect type"), - } - } + fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted { + match e { + &mut Element::Formatted(ref mut val) => val, + _ => panic!("Incorrect type"), + } + } } struct FormatState<'a> { - max_width: f64, - lines: usize, - offset: f64, - width: f64, - text: Vec, - renderer: &'a render::Renderer, + max_width: f64, + lines: usize, + offset: f64, + width: f64, + text: Vec, + renderer: &'a render::Renderer, } -type GetColorFn = Fn() -> format::Color; - impl <'a> FormatState<'a> { - fn build(&mut self, c: &format::Component, color: format::Color) { - match c { - &format::Component::Text(ref txt) => { - let col = FormatState::get_color(&txt.modifier, color); - self.append_text(&txt.text, col); - let modi = &txt.modifier; - if let Some(ref extra) = modi.extra { - for e in extra { - self.build(e, col); - } - } - }, - } - } + fn build(&mut self, c: &format::Component, color: format::Color) { + match c { + &format::Component::Text(ref txt) => { + let col = FormatState::get_color(&txt.modifier, color); + self.append_text(&txt.text, col); + let modi = &txt.modifier; + if let Some(ref extra) = modi.extra { + for e in extra { + self.build(e, col); + } + } + } + } + } - fn append_text(&mut self, txt: &str, color: format::Color) { - let mut width = 0.0; - let mut last = 0; - for (i, c) in txt.char_indices() { - let size = self.renderer.ui.size_of_char(c) + 2.0; - if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' { - let (rr, gg, bb) = color.to_rgb(); - let text = Text::new(self.renderer, &txt[last .. i], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb); - self.text.push(text.wrap()); - last = i; - if c == '\n' { - last += 1; - } - self.offset = 0.0; - self.lines += 1; - width = 0.0; - } - width += size; - if self.offset + width > self.width { - self.width = self.offset + width; - } - } + fn append_text(&mut self, txt: &str, color: format::Color) { + let mut width = 0.0; + let mut last = 0; + for (i, c) in txt.char_indices() { + let size = self.renderer.ui.size_of_char(c) + 2.0; + if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' { + let (rr, gg, bb) = color.to_rgb(); + let text = Text::new(self.renderer, + &txt[last..i], + self.offset, + (self.lines * 18 + 1) as f64, + rr, + gg, + bb); + self.text.push(text.wrap()); + last = i; + if c == '\n' { + last += 1; + } + self.offset = 0.0; + self.lines += 1; + width = 0.0; + } + width += size; + if self.offset + width > self.width { + self.width = self.offset + width; + } + } - if last != txt.len() { - let (rr, gg, bb) = color.to_rgb(); - let text = Text::new(self.renderer, &txt[last..], self.offset, (self.lines*18 + 1) as f64, rr, gg, bb); - self.offset += text.width + 4.0; // TODO Why is this 4 not 2? - self.text.push(text.wrap()); - if self.offset > self.width { - self.width = self.offset; - } - } - } + if last != txt.len() { + let (rr, gg, bb) = color.to_rgb(); + let text = Text::new(self.renderer, + &txt[last..], + self.offset, + (self.lines * 18 + 1) as f64, + rr, + gg, + bb); + self.offset += text.width + 4.0; // TODO Why is this 4 not 2? + self.text.push(text.wrap()); + if self.offset > self.width { + self.width = self.offset; + } + } + } - fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color { - modi.color.unwrap_or(color) - } -} \ No newline at end of file + fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color { + modi.color.unwrap_or(color) + } +} diff --git a/src/ui/image.rs b/src/ui/image.rs index 3b42605..de7b79e 100644 --- a/src/ui/image.rs +++ b/src/ui/image.rs @@ -31,55 +31,82 @@ ui_element!(Image { impl Image { base_impl!(); - 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 { - ui_create!(Image { - texture: texture, - x: x, - y: y, - width: w, - height: h, + 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 { + ui_create!(Image { + texture: texture, + x: x, + y: y, + width: w, + height: h, - t_x: t_x, - t_y: t_y, - t_width: t_width, - t_height: t_height, + t_x: t_x, + t_y: t_y, + t_width: t_width, + t_height: t_height, - r: r, - g: g, - b: b, - a: 255 - }) - } + r: r, + g: g, + b: b, + a: 255, + }) + } - fn update(&mut self, _: &mut render::Renderer) {} + fn update(&mut self, _: &mut render::Renderer) { + } - fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, _: f64) -> &Vec { - 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); - } - &self.data - } + fn draw(&mut self, + renderer: &mut render::Renderer, + r: &Region, + width: f64, + height: f64, + _: f64) + -> &Vec { + 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); + } + &self.data + } - pub fn get_size(&self) -> (f64, f64) { - (self.width, self.height) - } + pub fn get_size(&self) -> (f64, f64) { + (self.width, self.height) + } - pub fn get_texture(&self) -> render::Texture { - self.texture.clone() - } + 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; - } + pub fn set_texture(&mut self, val: render::Texture) { + self.texture = val; + self.dirty = true; + } lazy_field!(width, f64, get_width, set_width); lazy_field!(height, f64, get_height, set_height); @@ -96,21 +123,21 @@ impl Image { } impl UIElement for Image { - fn wrap(self) -> Element { - Element::Image(self) - } + 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<'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"), - } - } -} \ No newline at end of file + fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Image { + match e { + &mut Element::Image(ref mut val) => val, + _ => panic!("Incorrect type"), + } + } +} diff --git a/src/ui/logo.rs b/src/ui/logo.rs index 695f198..b9472bc 100644 --- a/src/ui/logo.rs +++ b/src/ui/logo.rs @@ -9,160 +9,175 @@ use rand; use rand::Rng; pub struct Logo { - resources: Arc>, + resources: Arc>, - shadow: ui::ElementRef, - layer0: ui::ElementRef, + shadow: ui::ElementRef, + layer0: ui::ElementRef, - text: ui::ElementRef, - text_base_scale: f64, - text_orig_x: f64, - text_index: isize, - text_strings: Vec, + text: ui::ElementRef, + text_base_scale: f64, + text_orig_x: f64, + text_index: isize, + text_strings: Vec, } impl Logo { - pub fn new(resources: Arc>, renderer: &mut render::Renderer, ui_container: &mut ui::Container) -> Logo { - let mut l = Logo { - resources: resources, - shadow: Default::default(), - layer0: Default::default(), - text: Default::default(), - text_base_scale: 0.0, - text_orig_x: 0.0, - text_index: -1, - text_strings: Vec::new(), - }; - l.init(renderer, ui_container); - l - } + pub fn new(resources: Arc>, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) + -> Logo { + let mut l = Logo { + resources: resources, + shadow: Default::default(), + layer0: Default::default(), + text: Default::default(), + text_base_scale: 0.0, + text_orig_x: 0.0, + text_index: -1, + text_strings: Vec::new(), + }; + l.init(renderer, ui_container); + l + } - fn init(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let res = self.resources.read().unwrap(); + fn init(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let res = self.resources.read().unwrap(); - let mut logo = res.open("steven", "logo/logo.txt").unwrap(); - let mut logo_str = String::new(); - logo.read_to_string(&mut logo_str).unwrap(); + let mut logo = res.open("steven", "logo/logo.txt").unwrap(); + let mut logo_str = String::new(); + logo.read_to_string(&mut logo_str).unwrap(); - let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); - let stone = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak"); + let solid = render::Renderer::get_texture(renderer.get_textures_ref(), "steven:solid"); + let stone = render::Renderer::get_texture(renderer.get_textures_ref(), "blocks/planks_oak"); - let mut shadow_batch = ui::Batch::new(0.0, 8.0, 100.0, 100.0); - let mut layer0 = ui::Batch::new(0.0, 8.0, 100.0, 100.0); + let mut shadow_batch = ui::Batch::new(0.0, 8.0, 100.0, 100.0); + let mut layer0 = ui::Batch::new(0.0, 8.0, 100.0, 100.0); - shadow_batch.set_h_attach(ui::HAttach::Center); - layer0.set_h_attach(ui::HAttach::Center); + shadow_batch.set_h_attach(ui::HAttach::Center); + layer0.set_h_attach(ui::HAttach::Center); - let mut row = 0; - for line in logo_str.lines() { - if line.is_empty() { - continue; - } - for (i, c) in line.chars().enumerate() { - if c == ' ' { - continue; - } - let x = i * 4; - let y = row * 8; - let (r, g, b) = if c == ':' { - (255, 255, 255) - } else { - (170, 170, 170) - }; - let mut shadow = ui::Image::new( - solid.clone(), - (x+2) as f64, (y+4) as f64, 4.0, 8.0, - 0.0, 0.0, 1.0, 1.0, - 0, 0, 0 - ); - shadow.set_a(100); - shadow_batch.add(shadow); + let mut row = 0; + for line in logo_str.lines() { + if line.is_empty() { + continue; + } + for (i, c) in line.chars().enumerate() { + if c == ' ' { + continue; + } + let x = i * 4; + let y = row * 8; + let (r, g, b) = if c == ':' { + (255, 255, 255) + } else { + (170, 170, 170) + }; + let mut shadow = ui::Image::new(solid.clone(), + (x + 2) as f64, + (y + 4) as f64, + 4.0, + 8.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0, + 0, + 0); + shadow.set_a(100); + shadow_batch.add(shadow); - let img = ui::Image::new( - stone.clone(), - x as f64, y as f64, 4.0, 8.0, - (x%16) as f64 / 16.0, (y%16) as f64 / 16.0, 4.0/16.0, 8.0/16.0, - r, g, b - ); - layer0.add(img); + let img = ui::Image::new(stone.clone(), + x as f64, + y as f64, + 4.0, + 8.0, + (x % 16) as f64 / 16.0, + (y % 16) as f64 / 16.0, + 4.0 / 16.0, + 8.0 / 16.0, + r, + g, + b); + layer0.add(img); - let width = (x + 4) as f64; - if shadow_batch.get_width() < width { - shadow_batch.set_width(width); - layer0.set_width(width); - } - } - row += 1; - } - { - let mut splashes = res.open_all("minecraft", "texts/splashes.txt"); - for file in &mut splashes { - let mut texts = String::new(); - file.read_to_string(&mut texts).unwrap(); - for line in texts.lines() { - self.text_strings.push(line.to_owned().replace("\r", "")); - } - } - let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]); - r.shuffle(&mut self.text_strings[..]); - } + let width = (x + 4) as f64; + if shadow_batch.get_width() < width { + shadow_batch.set_width(width); + layer0.set_width(width); + } + } + row += 1; + } + { + let mut splashes = res.open_all("minecraft", "texts/splashes.txt"); + for file in &mut splashes { + let mut texts = String::new(); + file.read_to_string(&mut texts).unwrap(); + for line in texts.lines() { + self.text_strings.push(line.to_owned().replace("\r", "")); + } + } + let mut r: rand::XorShiftRng = rand::SeedableRng::from_seed([45, 64, 32, 12]); + r.shuffle(&mut self.text_strings[..]); + } - shadow_batch.set_height(row as f64 * 8.0); - layer0.set_height(row as f64 * 8.0); + shadow_batch.set_height(row as f64 * 8.0); + layer0.set_height(row as f64 * 8.0); - self.shadow = ui_container.add(shadow_batch); - self.layer0 = ui_container.add(layer0); + self.shadow = ui_container.add(shadow_batch); + self.layer0 = ui_container.add(layer0); - let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0); - txt.set_h_attach(ui::HAttach::Right); - txt.set_v_attach(ui::VAttach::Bottom); - txt.set_parent(&self.shadow); - txt.set_rotation(-consts::PI / 8.0); - - let width = txt.get_width(); - self.text_base_scale = 300.0 / width; - if self.text_base_scale > 1.0 { - self.text_base_scale = 1.0; - } - txt.set_x((-width / 2.0) * self.text_base_scale); - self.text_orig_x = txt.get_x(); - self.text = ui_container.add(txt); - } + let mut txt = ui::Text::new(renderer, "", 0.0, -8.0, 255, 255, 0); + txt.set_h_attach(ui::HAttach::Right); + txt.set_v_attach(ui::VAttach::Bottom); + txt.set_parent(&self.shadow); + txt.set_rotation(-consts::PI / 8.0); - pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { - let now = time::now().to_timespec(); + let width = txt.get_width(); + self.text_base_scale = 300.0 / width; + if self.text_base_scale > 1.0 { + self.text_base_scale = 1.0; + } + txt.set_x((-width / 2.0) * self.text_base_scale); + self.text_orig_x = txt.get_x(); + self.text = ui_container.add(txt); + } + + pub fn tick(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let now = time::now().to_timespec(); // Splash text - let text = ui_container.get_mut(&self.text); - let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize; - if self.text_index != text_index { - self.text_index = text_index; - text.set_text(renderer, &self.text_strings[text_index as usize]); - let width = text.get_width(); - self.text_base_scale = 300.0 / width; - if self.text_base_scale > 1.0 { - self.text_base_scale = 1.0; - } - text.set_x((-width / 2.0) * self.text_base_scale); - self.text_orig_x = text.get_x(); - } + let text = ui_container.get_mut(&self.text); + let text_index = (now.sec / 15) as isize % self.text_strings.len() as isize; + if self.text_index != text_index { + self.text_index = text_index; + text.set_text(renderer, &self.text_strings[text_index as usize]); + let width = text.get_width(); + self.text_base_scale = 300.0 / width; + if self.text_base_scale > 1.0 { + self.text_base_scale = 1.0; + } + text.set_x((-width / 2.0) * self.text_base_scale); + self.text_orig_x = text.get_x(); + } - let timer = now.nsec as f64 / 1000000000.0; - let mut offset = timer / 0.5; - if offset > 1.0 { - offset = 2.0 - offset; - } - offset = ((offset * consts::PI).cos() + 1.0) / 2.0; - text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale); - text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale); - let scale = text.get_scale_x(); - text.set_x(self.text_orig_x * scale * self.text_base_scale); - } + let timer = now.nsec as f64 / 1000000000.0; + let mut offset = timer / 0.5; + if offset > 1.0 { + offset = 2.0 - offset; + } + offset = ((offset * consts::PI).cos() + 1.0) / 2.0; + text.set_scale_x((0.7 + (offset / 3.0)) * self.text_base_scale); + text.set_scale_y((0.7 + (offset / 3.0)) * self.text_base_scale); + let scale = text.get_scale_x(); + text.set_x(self.text_orig_x * scale * self.text_base_scale); + } - pub fn remove(&self, ui_container: &mut ui::Container) { - ui_container.remove(&self.shadow); - ui_container.remove(&self.layer0); - ui_container.remove(&self.text); - } -} \ No newline at end of file + pub fn remove(&self, ui_container: &mut ui::Container) { + ui_container.remove(&self.shadow); + ui_container.remove(&self.layer0); + ui_container.remove(&self.text); + } +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index fd69708..b44fb82 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -25,11 +25,11 @@ const SCALED_WIDTH: f64 = 854.0; const SCALED_HEIGHT: f64 = 480.0; pub enum Element { - Image(Image), - Batch(Batch), - Text(Text), - Formatted(Formatted), - None, + Image(Image), + Batch(Batch), + Text(Text), + Formatted(Formatted), + None, } pub type ClickFunc = Rc; @@ -44,7 +44,7 @@ impl Element { Element::$name(ref val) => val.click_funcs.clone(), )+ _ => unimplemented!(), - } + } } fn get_hover_funcs(&self) -> Vec { @@ -53,7 +53,7 @@ impl Element { Element::$name(ref val) => val.hover_funcs.clone(), )+ _ => unimplemented!(), - } + } } fn should_call_hover(&mut self, new: bool) -> bool{ @@ -93,7 +93,7 @@ impl Element { Element::$name(ref val) => (val.v_attach, val.h_attach), )+ _ => unimplemented!(), - } + } } fn get_offset(&self) -> (f64, f64) { @@ -102,7 +102,7 @@ impl Element { Element::$name(ref val) => (val.x, val.y), )+ _ => unimplemented!(), - } + } } fn get_size(&self) -> (f64, f64) { @@ -111,7 +111,7 @@ impl Element { Element::$name(ref val) => val.get_size(), )+ _ => unimplemented!(), - } + } } fn is_dirty(&self) -> bool { @@ -120,7 +120,7 @@ impl Element { Element::$name(ref val) => val.dirty, )+ _ => unimplemented!(), - } + } } fn set_dirty(&mut self, dirty: bool) { @@ -129,7 +129,7 @@ impl Element { Element::$name(ref mut val) => val.dirty = dirty, )+ _ => unimplemented!(), - } + } } fn update(&mut self, renderer: &mut render::Renderer) { @@ -138,16 +138,16 @@ impl Element { Element::$name(ref mut val) => val.update(renderer), )+ _ => unimplemented!(), - } + } } - fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec{ + fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec { match *self { $( Element::$name(ref mut val) => val.draw(renderer, r, width, height, delta), )+ _ => unimplemented!(), - } + } } } ) @@ -161,319 +161,330 @@ element_impl!( ); pub enum Mode { - Scaled, - Unscaled(f64) + Scaled, + Unscaled(f64), } #[derive(Clone, Copy, PartialEq, Eq)] pub enum VAttach { - Top, - Middle, - Bottom, + Top, + Middle, + Bottom, } #[derive(Clone, Copy, PartialEq, Eq)] pub enum HAttach { - Left, - Center, - Right, + Left, + Center, + Right, } #[derive(Clone)] struct Region { - x: f64, - y: f64, - w: f64, - h: f64, + 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) - } + 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(Copy)] pub struct ElementRef { - inner: ElementRefInner, - ty: PhantomData, + inner: ElementRefInner, + ty: PhantomData, } impl Clone for ElementRef { - fn clone(&self) -> Self { - ElementRef { - inner: self.inner, - ty: PhantomData, - } - } + fn clone(&self) -> Self { + ElementRef { + inner: self.inner, + ty: PhantomData, + } + } } #[derive(Hash, PartialEq, Eq, Clone, Copy)] struct ElementRefInner { - index: usize, + index: usize, } impl Default for ElementRef { - fn default() -> Self { - ElementRef { - inner: ElementRefInner{ index: 0 }, - ty: PhantomData, - } - } + fn default() -> Self { + ElementRef { + inner: ElementRefInner { index: 0 }, + ty: PhantomData, + } + } } /// Allows for easy cleanup pub struct Collection { - elements: Vec, + elements: Vec, } impl Collection { - pub fn new() -> Collection { - Collection { - elements: Vec::new(), - } - } + pub fn new() -> Collection { + Collection { elements: Vec::new() } + } - pub fn add(&mut self, element: ElementRef) -> ElementRef { - self.elements.push(element.inner); - element - } + pub fn add(&mut self, element: ElementRef) -> ElementRef { + self.elements.push(element.inner); + element + } - pub fn remove_all(&mut self, container: &mut Container) { - for e in &self.elements { - container.remove_raw(e); - } - self.elements.clear(); - } + pub fn remove_all(&mut self, container: &mut Container) { + for e in &self.elements { + container.remove_raw(e); + } + self.elements.clear(); + } } -const SCREEN: Region = Region{x: 0.0, y: 0.0, w: SCALED_WIDTH, h: SCALED_HEIGHT}; +const SCREEN: Region = Region { + x: 0.0, + y: 0.0, + w: SCALED_WIDTH, + h: SCALED_HEIGHT, +}; pub struct Container { - pub mode: Mode, - elements: HashMap, - // We need the order - elements_list: Vec, - version: usize, + pub mode: Mode, + elements: HashMap, + // We need the order + elements_list: Vec, + version: usize, - last_sw: f64, - last_sh: f64, - last_width: f64, - last_height: f64, + last_sw: f64, + last_sh: f64, + last_width: f64, + last_height: f64, } impl Container { - pub fn new() -> Container { - Container { - mode: Mode::Scaled, - elements: HashMap::new(), - elements_list: Vec::new(), - version: 0xFFFF, - last_sw: 0.0, - last_sh: 0.0, - last_width: 0.0, - last_height: 0.0, - } - } + pub fn new() -> Container { + Container { + mode: Mode::Scaled, + elements: HashMap::new(), + elements_list: Vec::new(), + version: 0xFFFF, + last_sw: 0.0, + last_sh: 0.0, + last_width: 0.0, + last_height: 0.0, + } + } - 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()); - self.elements_list.push(r); - ElementRef{inner: r, ty: PhantomData} - } + 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()); + self.elements_list.push(r); + ElementRef { + inner: r, + ty: PhantomData, + } + } - pub fn get(&self, r: &ElementRef) -> &T { - T::unwrap_ref(self.elements.get(&r.inner).unwrap()) - } + 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 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.remove_raw(&r.inner); - } - - fn remove_raw(&mut self, r: &ElementRefInner) { - self.elements.remove(&r); - self.elements_list.iter() - .position(|&e| e.index == r.index) - .map(|e| self.elements_list.remove(e)) - .unwrap(); - } + pub fn remove(&mut self, r: &ElementRef) { + self.remove_raw(&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), - }; + fn remove_raw(&mut self, r: &ElementRefInner) { + self.elements.remove(&r); + self.elements_list + .iter() + .position(|&e| e.index == r.index) + .map(|e| self.elements_list.remove(e)) + .unwrap(); + } - if self.last_sw != sw || self.last_sh != sh - || self.last_width != width || self.last_height != height - || self.version != renderer.ui.version { - self.last_sw = sw; - self.last_sh = sh; - self.last_width = width; - self.last_height = height; - for (_, e) in &mut self.elements { - e.set_dirty(true); - if self.version != renderer.ui.version { - e.update(renderer); - } - } - self.version = renderer.ui.version; - } + 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), + }; + + if self.last_sw != sw || self.last_sh != sh || self.last_width != width || + self.last_height != height || self.version != renderer.ui.version { + self.last_sw = sw; + self.last_sh = sh; + self.last_width = width; + self.last_height = height; + for (_, e) in &mut self.elements { + e.set_dirty(true); + if self.version != renderer.ui.version { + e.update(renderer); + } + } + self.version = renderer.ui.version; + } // 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 in &self.elements_list { - let mut e = self.elements.get_mut(re).unwrap(); - if !e.should_draw() { - continue; - } - if let Some(&(ref r, ref dirty)) = regions.get(re) { - e.set_dirty(*dirty); - let data = e.draw(renderer, r, width, height, delta); - renderer.ui.add_bytes(data); - } - } - } + let regions = self.collect_elements(sw, sh); + for re in &self.elements_list { + let mut e = self.elements.get_mut(re).unwrap(); + if !e.should_draw() { + continue; + } + if let Some(&(ref r, ref dirty)) = regions.get(re) { + e.set_dirty(*dirty); + let data = e.draw(renderer, r, width, height, delta); + renderer.ui.add_bytes(data); + } + } + } - 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 + 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 - } + 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 + } - pub fn click_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) { - let (sw, sh) = match self.mode { - Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height), - Mode::Unscaled(scale) => (scale, scale), - }; - let mx = (x / width) * SCALED_WIDTH; - let my = (y / height) * SCALED_HEIGHT; - let mut click = None; - for re in self.elements_list.iter().rev() { - let e = self.elements.get(re).unwrap(); - let funcs = e.get_click_funcs(); - if !funcs.is_empty() { - let r = self.get_draw_region(e, sw, sh); - if mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h { - click = Some(funcs); - break; - } - } - } - if let Some(click) = click { - for c in &click { - c(game, self); - } - } - } + pub fn click_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) { + let (sw, sh) = match self.mode { + Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height), + Mode::Unscaled(scale) => (scale, scale), + }; + let mx = (x / width) * SCALED_WIDTH; + let my = (y / height) * SCALED_HEIGHT; + let mut click = None; + for re in self.elements_list.iter().rev() { + let e = self.elements.get(re).unwrap(); + let funcs = e.get_click_funcs(); + if !funcs.is_empty() { + let r = self.get_draw_region(e, sw, sh); + if mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h { + click = Some(funcs); + break; + } + } + } + if let Some(click) = click { + for c in &click { + c(game, self); + } + } + } - pub fn hover_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) { - let (sw, sh) = match self.mode { - Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height), - Mode::Unscaled(scale) => (scale, scale), - }; - let mx = (x / width) * SCALED_WIDTH; - let my = (y / height) * SCALED_HEIGHT; - let mut hovers = Vec::new(); - for re in self.elements_list.iter().rev() { - let e = self.elements.get(re).unwrap(); - let funcs = e.get_hover_funcs(); - if !funcs.is_empty() { - let r = self.get_draw_region(e, sw, sh); - hovers.push((*re, funcs, mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h)); - } - } - for hover in &hovers { - let call = { - let e = self.elements.get_mut(&hover.0).unwrap(); - e.should_call_hover(hover.2) - }; - if call { - for f in &hover.1 { - f(hover.2, game, self); - } - } - } - } + pub fn hover_at(&mut self, game: &mut ::Game, x: f64, y: f64, width: f64, height: f64) { + let (sw, sh) = match self.mode { + Mode::Scaled => (SCALED_WIDTH / width, SCALED_HEIGHT / height), + Mode::Unscaled(scale) => (scale, scale), + }; + let mx = (x / width) * SCALED_WIDTH; + let my = (y / height) * SCALED_HEIGHT; + let mut hovers = Vec::new(); + for re in self.elements_list.iter().rev() { + let e = self.elements.get(re).unwrap(); + let funcs = e.get_hover_funcs(); + if !funcs.is_empty() { + let r = self.get_draw_region(e, sw, sh); + hovers.push((*re, + funcs, + mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h)); + } + } + for hover in &hovers { + let call = { + let e = self.elements.get_mut(&hover.0).unwrap(); + e.should_call_hover(hover.2) + }; + if call { + for f in &hover.1 { + f(hover.2, game, self); + } + } + } + } - 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, - }; - Container::get_draw_region_raw(e, sw, sh, &super_region) - } + 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, + }; + Container::get_draw_region_raw(e, sw, sh, &super_region) + } - fn get_draw_region_raw(e: &Element, sw: f64, sh: f64, super_region: &Region) -> Region { - 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 - } + fn get_draw_region_raw(e: &Element, sw: f64, sh: f64, super_region: &Region) -> Region { + 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(&Element) -> &Self; - fn unwrap_ref_mut(&mut Element) -> &mut Self; + fn wrap(self) -> Element; + fn unwrap_ref(&Element) -> &Self; + fn unwrap_ref_mut(&mut Element) -> &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; + self.dirty = true; } } ) @@ -487,16 +498,16 @@ macro_rules! ui_element { ),+ } ) => ( - pub struct $name { + pub struct $name { dirty: bool, - data: Vec, + data: Vec, parent: Option, should_draw: bool, layer: isize, x: f64, y: f64, v_attach: VAttach, - h_attach: HAttach, + h_attach: HAttach, click_funcs: Vec, hover_funcs: Vec, hovered: bool, @@ -532,7 +543,7 @@ macro_rules! base_impl { macro_rules! ui_create { ($name:ident { - $($field:ident: $e:expr),+ + $($field:ident: $e:expr,)+ }) => ( $name { dirty: true, @@ -553,9 +564,9 @@ macro_rules! ui_create { // Include instead of mod so we can access private parts. // Its a bit ew doing it this way but it saves us making -// fields public that should be private or having a huge +// fields public that should be private or having a huge // file. include!("image.rs"); include!("batch.rs"); include!("text.rs"); -include!("formatted.rs"); \ No newline at end of file +include!("formatted.rs"); diff --git a/src/ui/text.rs b/src/ui/text.rs index 7795b11..6f9e6d6 100644 --- a/src/ui/text.rs +++ b/src/ui/text.rs @@ -28,65 +28,94 @@ ui_element!(Text { impl Text { base_impl!(); - pub fn new(renderer: &render::Renderer, val: &str, x: f64, y: f64, r: u8, g: u8, b: u8) -> Text { - ui_create!(Text { - val: val.to_owned(), - x: x, - y: y, - width: renderer.ui.size_of_string(val), - height: 18.0, - scale_x: 1.0, - scale_y: 1.0, - rotation: 0.0, - r: r, - g: g, - b: b, - a: 255 - }) - } + pub fn new(renderer: &render::Renderer, + val: &str, + x: f64, + y: f64, + r: u8, + g: u8, + b: u8) + -> Text { + ui_create!(Text { + val: val.to_owned(), + x: x, + y: y, + width: renderer.ui.size_of_string(val), + height: 18.0, + scale_x: 1.0, + scale_y: 1.0, + rotation: 0.0, + r: r, + g: g, + b: b, + a: 255, + }) + } - fn update(&mut self, renderer: &mut render::Renderer) { - self.width = renderer.ui.size_of_string(&self.val); - } + fn update(&mut self, renderer: &mut render::Renderer) { + self.width = renderer.ui.size_of_string(&self.val); + } - fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, _: f64) -> &Vec { - if self.dirty { - self.dirty = false; - let sx = r.w / self.width; - let sy = r.h / self.height; - let mut text = if self.rotation == 0.0 { - renderer.ui.new_text_scaled(&self.val, r.x, r.y, sx*self.scale_x, sy*self.scale_y, self.r, self.g, self.b) - } else { - let c = self.rotation.cos(); - let s = self.rotation.sin(); - let tmpx = r.w / 2.0; - let tmpy = r.h / 2.0; - let w = (tmpx*c - tmpy*s).abs(); - let h = (tmpy*c + tmpx*s).abs(); - renderer.ui.new_text_rotated(&self.val, r.x+w-(r.w / 2.0), r.y+h-(r.h / 2.0), sx*self.scale_x, sy*self.scale_y, self.rotation, self.r, self.g, self.b) - }; - for e in &mut text.elements { - e.a = self.a; - e.layer = self.layer; - } - self.data = text.bytes(width, height); - } - &self.data - } + fn draw(&mut self, + renderer: &mut render::Renderer, + r: &Region, + width: f64, + height: f64, + _: f64) + -> &Vec { + if self.dirty { + self.dirty = false; + let sx = r.w / self.width; + let sy = r.h / self.height; + let mut text = if self.rotation == 0.0 { + renderer.ui.new_text_scaled(&self.val, + r.x, + r.y, + sx * self.scale_x, + sy * self.scale_y, + self.r, + self.g, + self.b) + } else { + let c = self.rotation.cos(); + let s = self.rotation.sin(); + let tmpx = r.w / 2.0; + let tmpy = r.h / 2.0; + let w = (tmpx * c - tmpy * s).abs(); + let h = (tmpy * c + tmpx * s).abs(); + renderer.ui.new_text_rotated(&self.val, + r.x + w - (r.w / 2.0), + r.y + h - (r.h / 2.0), + sx * self.scale_x, + sy * self.scale_y, + self.rotation, + self.r, + self.g, + self.b) + }; + for e in &mut text.elements { + e.a = self.a; + e.layer = self.layer; + } + self.data = text.bytes(width, height); + } + &self.data + } - pub fn get_size(&self) -> (f64, f64) { - ((self.width + 2.0) * self.scale_x, self.height * self.scale_y) - } + pub fn get_size(&self) -> (f64, f64) { + ((self.width + 2.0) * self.scale_x, + self.height * self.scale_y) + } - pub fn get_text(&self) -> &str { - &self.val - } + pub fn get_text(&self) -> &str { + &self.val + } - pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) { - self.dirty = true; - self.val = val.to_owned(); - self.width = renderer.ui.size_of_string(val); - } + pub fn set_text(&mut self, renderer: &render::Renderer, val: &str) { + self.dirty = true; + self.val = val.to_owned(); + self.width = renderer.ui.size_of_string(val); + } lazy_field!(width, f64, get_width, set_width); lazy_field!(height, f64, get_height, set_height); @@ -100,21 +129,21 @@ impl Text { } impl UIElement for Text { - fn wrap(self) -> Element { - Element::Text(self) - } + fn wrap(self) -> Element { + Element::Text(self) + } - fn unwrap_ref<'a>(e: &'a Element) -> &'a Text { - match e { - &Element::Text(ref val) => val, - _ => panic!("Incorrect type"), - } - } + fn unwrap_ref<'a>(e: &'a Element) -> &'a Text { + match e { + &Element::Text(ref val) => val, + _ => panic!("Incorrect type"), + } + } - fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text { - match e { - &mut Element::Text(ref mut val) => val, - _ => panic!("Incorrect type"), - } - } -} \ No newline at end of file + fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Text { + match e { + &mut Element::Text(ref mut val) => val, + _ => panic!("Incorrect type"), + } + } +}