Base of ui complete

This commit is contained in:
Thinkofdeath 2015-09-17 16:04:25 +01:00
parent ab2336ffca
commit 5aef272d43
26 changed files with 2176 additions and 40 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
target/
.rust/
working/

117
Cargo.lock generated
View File

@ -6,11 +6,14 @@ dependencies = [
"flate2 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"glfw 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"steven_gl 0.0.1",
"steven_openssl 0.0.1",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -18,7 +21,7 @@ name = "advapi32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -32,6 +35,29 @@ name = "byteorder"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bzip2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bzip2-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bzip2-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color_quant"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cookie"
version = "0.1.21"
@ -43,6 +69,14 @@ dependencies = [
"url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum_primitive"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum_primitive"
version = "0.1.0"
@ -66,7 +100,16 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gif"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -94,7 +137,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glfw-sys 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
@ -102,8 +144,8 @@ dependencies = [
]
[[package]]
name = "glfw-sys"
version = "3.1.3"
name = "glob"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -140,12 +182,25 @@ dependencies = [
"url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "image"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"enum_primitive 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gif 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -185,6 +240,11 @@ dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzw"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "matches"
version = "0.1.2"
@ -207,6 +267,16 @@ dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "msdos_time"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.27"
@ -259,6 +329,22 @@ dependencies = [
"tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "png"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "podio"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.11"
@ -266,7 +352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -320,6 +406,7 @@ name = "steven_openssl"
version = "0.0.1"
dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -337,7 +424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -366,7 +453,7 @@ dependencies = [
[[package]]
name = "winapi"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -382,3 +469,15 @@ dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "zip"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bzip2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"msdos_time 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"podio 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -11,6 +11,9 @@ hyper = "0.6.13"
serde = "0.6.0"
serde_json = "0.6.0"
flate2 = "0.2.9"
zip = "0.1.12"
image = "0.3.12"
time = "0.1.32"
[dependencies.steven_gl]
path = "./gl"
@ -20,5 +23,12 @@ version = "0"
path = "./openssl"
version = "0"
[[bin]]
name = "steven"
[target.x86_64-pc-windows-gnu.dependencies]
glfw = { version = "0.1.0", default-features = false }
[target.x86_64-pc-windows-msvc.dependencies]
glfw = { version = "0.1.0", default-features = false }
[target.i686-pc-windows-gnu.dependencies]
glfw = { version = "0.1.0", default-features = false }

59
gl/Cargo.lock generated Normal file
View File

@ -0,0 +1,59 @@
[root]
name = "steven_gl"
version = "0.0.1"
dependencies = [
"gl_common 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"gl_generator 0.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gl_common"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gl_generator"
version = "0.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"khronos_api 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "khronos_api"
version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xml-rs"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]

79
openssl/Cargo.lock generated
View File

@ -3,6 +3,25 @@ name = "steven_openssl"
version = "0.0.1"
dependencies = [
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "advapi32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -10,3 +29,63 @@ name = "libc"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libressl-pnacl-sys"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pnacl-build-helper"
version = "1.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempdir"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

View File

@ -5,3 +5,4 @@ authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>" ]
[dependencies]
libc = "*"
openssl-sys = "0.6.5"

View File

@ -31,7 +31,6 @@ struct ENGINE;
const RSA_PKCS1_PADDING : libc::c_int = 1;
#[link(name = "crypto")]
extern {
fn SHA1_Init(c: *mut SHA_CTX) -> libc::c_int;
fn SHA1_Update(c: *mut SHA_CTX, data: *const u8, len: libc::size_t) -> libc::c_int;

View File

@ -1,5 +1,5 @@
extern crate serde_json;
use serde_json;
use std::fmt;
#[derive(Debug)]

View File

@ -2,17 +2,53 @@ extern crate steven_gl as gl;
extern crate glfw;
use std::ops::BitOr;
use std::ffi;
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
/// Inits the gl library. This should be called once a context is ready.
pub fn init(window: &mut glfw::Window) {
gl::load_with(|s| window.get_proc_address(s));
}
/// Dsed to specify how the vertices will be handled
/// to draw.
pub type DrawType = u32;
/// Treats each set of 3 vertices as a triangle
pub const TRIANGLES: DrawType = gl::TRIANGLES;
/// Means the previous vertex connects to the next
/// one in a continuous strip.
pub const LINE_STRIP: DrawType = gl::LINE_STRIP;
/// Treats each set of 2 vertices as a line
pub const LINES: DrawType = gl::LINES;
/// Treats each vertex as a point
pub const POINTS: DrawType = gl::POINTS;
pub fn draw_elements(ty: DrawType, count: usize, dty: Type, offset: usize) {
unsafe {
gl::DrawElements(ty, count as i32, dty, offset as *const gl::types::GLvoid);
}
}
/// 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); }
}
/// 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); }
}
/// ClearFlags is a set of flags to mark what should be cleared during
/// a Clear call.
pub enum ClearFlags {
/// Marks the color buffer to be cleared
Color,
/// Marks the depth buffer to be cleared
Depth,
Internal(u32)
}
@ -35,6 +71,454 @@ impl BitOr for ClearFlags {
}
}
/// Clears the buffers specified by the passed flags.
pub fn clear(flags: ClearFlags) {
unsafe { gl::Clear(flags.internal()) }
}
/// Func is a function to be preformed on two values.
pub type Func = u32;
pub const NEVER: Func = gl::NEVER;
pub const LESS: Func = gl::LESS;
pub const LESS_OR_EQUAL: Func = gl::LEQUAL;
pub const GREATER: Func = gl::GREATER;
pub const ALWAYS: Func = gl::ALWAYS;
pub const EQUAL: Func = gl::EQUAL;
pub fn depth_func(f: Func) {
unsafe { gl::DepthFunc(f); }
}
/// Flag is a setting that can be enabled or disabled on the context.
pub type Flag = u32;
pub const DEPTH_TEST: Flag = gl::DEPTH_TEST;
pub const CULL_FACE_FLAG: Flag = gl::CULL_FACE;
pub const STENCIL_TEST: Flag = gl::STENCIL_TEST;
pub const BLEND: Flag = gl::BLEND;
pub const MULTISAMPLE: Flag = gl::MULTISAMPLE;
/// Enables the passed flag.
pub fn enable(f: Flag) {
unsafe { gl::Enable(f); }
}
/// Disables the passed flag.
pub fn disable(f: Flag) {
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); }
}
/// Type is a type of data used by various operations.
pub type Type = u32;
pub const UNSIGNED_BYTE: Type = gl::UNSIGNED_BYTE;
pub const UNSIGNED_SHORT: Type = gl::UNSIGNED_SHORT;
pub const UNSIGNED_INT: Type = gl::UNSIGNED_INT;
pub const SHORT: Type = gl::SHORT;
pub const FLOAT: Type = gl::FLOAT;
/// TextureTarget is a target were a texture can be bound to
pub type TextureTarget = u32;
pub const TEXTURE_2D: TextureTarget = gl::TEXTURE_2D;
pub const TEXTURE_2D_MULTISAMPLE: TextureTarget = gl::TEXTURE_2D_MULTISAMPLE;
pub const TEXTURE_2D_ARRAY: TextureTarget = gl::TEXTURE_2D_ARRAY;
pub const TEXTURE_3D: TextureTarget = gl::TEXTURE_3D;
/// TextureFormat is the format of a texture either internally or
/// to be uploaded.
pub type TextureFormat = u32;
pub const RED: TextureFormat = gl::RED;
pub const RGB: TextureFormat = gl::RGB;
pub const RGBA: TextureFormat = gl::RGBA;
pub const RGBA8: TextureFormat = gl::RGBA8;
pub const RGBA16F: TextureFormat = gl::RGBA16F;
pub const R16F: TextureFormat = gl::R16F;
pub const DEPTH_COMPONENT24: TextureFormat = gl::DEPTH_COMPONENT24;
pub const DEPTH_COMPONENT: TextureFormat = gl::DEPTH_COMPONENT;
/// TextureParameter is a parameter that can be read or set on a texture.
pub type TextureParameter = u32;
pub const TEXTURE_MIN_FILTER: TextureParameter = gl::TEXTURE_MIN_FILTER;
pub const TEXTURE_MAG_FILTER: TextureParameter = gl::TEXTURE_MAG_FILTER;
pub const TEXTURE_WRAP_S: TextureParameter = gl::TEXTURE_WRAP_S;
pub const TEXTURE_WRAP_T: TextureParameter = gl::TEXTURE_WRAP_T;
pub const TEXTURE_MAX_LEVEL: TextureParameter = gl::TEXTURE_MAX_LEVEL;
/// TextureValue is a value that be set on a texture's parameter.
pub type TextureValue = i32;
pub const NEAREST: TextureValue = gl::NEAREST as TextureValue;
pub const LINEAR: TextureValue = gl::LINEAR as TextureValue;
pub const LINEAR_MIPMAP_LINEAR: TextureValue = gl::LINEAR_MIPMAP_LINEAR as TextureValue;
pub const LINEAR_MIPMAP_NEAREST: TextureValue = gl::LINEAR_MIPMAP_NEAREST as TextureValue;
pub const NEAREST_MIPMAP_NEAREST: TextureValue = gl::NEAREST_MIPMAP_NEAREST as TextureValue;
pub const NEAREST_MIPMAP_LINEAR: TextureValue = gl::NEAREST_MIPMAP_LINEAR as TextureValue;
pub const CLAMP_TO_EDGE: TextureValue = gl::CLAMP_TO_EDGE as TextureValue;
/// Texture is a buffer of data used by fragment shaders.
pub struct Texture {
internal: u32,
}
impl Texture {
// Allocates a new texture.
pub fn new() -> Texture {
let mut t = Texture{ internal: 0 };
unsafe { gl::GenTextures(1, &mut t.internal); }
t
}
/// Binds the texture to the passed target.
pub fn bind(&self, target: TextureTarget) {
unsafe {
gl::BindTexture(target, self.internal);
}
}
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);
}
}
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);
}
}
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);
}
}
pub fn set_parameter(&self, target: TextureTarget, param: TextureParameter, value: TextureValue) {
unsafe {
gl::TexParameteri(target, param, value);
}
}
}
impl Drop for Texture {
fn drop(&mut self) {
unsafe { gl::DeleteTextures(1, &self.internal); }
}
}
pub type ShaderType = u32;
pub const VERTEX_SHADER: ShaderType = gl::VERTEX_SHADER;
pub const FRAGMENT_SHADER: ShaderType = gl::FRAGMENT_SHADER;
pub const GEOMETRY_SHADER: ShaderType = gl::GEOMETRY_SHADER;
pub type ShaderParameter = u32;
pub const COMPILE_STATUS: ShaderParameter = gl::COMPILE_STATUS;
pub const INFO_LOG_LENGTH: ShaderParameter = gl::INFO_LOG_LENGTH;
pub struct Program {
internal: u32,
}
impl Program {
pub fn new() -> Program {
Program {
internal: unsafe { gl::CreateProgram() }
}
}
pub fn attach_shader(&self, shader: Shader) {
unsafe {
gl::AttachShader(self.internal, shader.internal);
}
}
pub fn link(&self) {
unsafe {
gl::LinkProgram(self.internal);
}
}
pub fn use_program(&self) {
unsafe {
gl::UseProgram(self.internal);
}
}
pub fn uniform_location(&self, name: &str) -> Uniform {
Uniform {
internal: unsafe { gl::GetUniformLocation(self.internal, ffi::CString::new(name).unwrap().as_ptr()) }
}
}
pub fn attribute_location(&self, name: &str) -> Attribute {
Attribute {
internal: unsafe { gl::GetAttribLocation(self.internal, ffi::CString::new(name).unwrap().as_ptr()) }
}
}
}
impl Drop for Program {
fn drop(&mut self) {
unsafe { gl::DeleteProgram(self.internal); }
}
}
pub struct Shader {
internal: u32,
}
impl Shader {
pub fn new(ty: ShaderType) -> Shader {
Shader {
internal: unsafe { gl::CreateShader(ty) }
}
}
pub fn set_source(&self, src: &str) {
unsafe {
gl::ShaderSource(self.internal, 1, &ffi::CString::new(src).unwrap().as_ptr(), ptr::null());
}
}
pub fn compile(&self) {
unsafe {
gl::CompileShader(self.internal);
}
}
pub fn get_parameter(&self, param: ShaderParameter) -> i32 {
let mut ret : i32 = 0;
unsafe { gl::GetShaderiv(self.internal, param, &mut ret); }
return ret;
}
pub fn get_info_log(&self) -> String {
let len = self.get_parameter(INFO_LOG_LENGTH);
let mut data = Vec::<u8>::with_capacity(len as usize);
unsafe {
data.set_len(len as usize);
gl::GetShaderInfoLog(self.internal, len, ptr::null_mut(), data.as_mut_ptr() as *mut i8);
}
String::from_utf8(data).unwrap()
}
}
pub struct Uniform {
internal: i32,
}
impl Uniform {
pub fn set_int(&self, val: i32) {
unsafe {
gl::Uniform1i(self.internal, val);
}
}
pub fn set_int3(&self, x: i32, y: i32, z: i32) {
unsafe {
gl::Uniform3i(self.internal, x, y, z);
}
}
pub fn set_float(&self, val: f32) {
unsafe {
gl::Uniform1f(self.internal, val);
}
}
pub fn set_float2(&self, x: f32, y: f32) {
unsafe {
gl::Uniform2f(self.internal, x, y);
}
}
pub fn set_float3(&self, x: f32, y: f32, z: f32) {
unsafe {
gl::Uniform3f(self.internal, x, y, z);
}
}
pub fn set_float4(&self, x: f32, y: f32, z: f32, w: f32) {
unsafe {
gl::Uniform4f(self.internal, x, y, z, w);
}
}
}
pub struct Attribute {
internal: i32,
}
impl Attribute {
pub fn enable(&self) {
unsafe {
gl::EnableVertexAttribArray(self.internal as u32);
}
}
pub fn disable(&self) {
unsafe {
gl::DisableVertexAttribArray(self.internal as u32);
}
}
pub fn vertex_pointer(&self, size: i32, ty: Type, normalized: bool, stride: i32, offset: i32) {
unsafe {
gl::VertexAttribPointer(self.internal as u32, size, ty, if normalized { 1 } else { 0 }, 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.internal as u32, size, ty, stride, offset as *const gl::types::GLvoid);
}
}
}
// VertexArray is used to store state needed to render vertices.
// This includes buffers, the format of the buffers and enabled
// attributes.
pub struct VertexArray {
internal: u32,
}
impl VertexArray {
/// Allocates a new VertexArray.
pub fn new() -> VertexArray {
let mut va = VertexArray {
internal: 0,
};
unsafe { gl::GenVertexArrays(1, &mut va.internal); }
va
}
/// Marks the VertexArray as the currently active one, this
/// means buffers/the format of the buffers etc will be bound to
/// this VertexArray.
pub fn bind(&self) {
unsafe { gl::BindVertexArray(self.internal); }
}
}
impl Drop for VertexArray {
fn drop(&mut self) {
unsafe { gl::DeleteVertexArrays(1, &self.internal); }
self.internal = 0;
}
}
/// BufferTarget is a target for a buffer to be bound to.
pub type BufferTarget = u32;
pub const ARRAY_BUFFER: BufferTarget = gl::ARRAY_BUFFER;
pub const ELEMENT_ARRAY_BUFFER: BufferTarget = gl::ELEMENT_ARRAY_BUFFER;
/// BufferUsage states how a buffer is going to be used by the program.
pub type BufferUsage = u32;
/// Marks the buffer as 'not going to change' after the
/// initial data upload to be rendered by the gpu.
pub const STATIC_DRAW: BufferUsage = gl::STATIC_DRAW;
/// Marks the buffer as 'changed frequently' during the
/// course of the program whilst being rendered by the gpu.
pub const DYNAMIC_DRAW: BufferUsage = gl::DYNAMIC_DRAW;
/// Marks the buffer as 'changed every frame' whilst being
/// rendered by the gpu.
pub const STREAM_DRAW: BufferUsage = gl::STREAM_DRAW;
/// Access states how a value will be accesed by the program.
pub type Access = u32;
/// States that the returned value will only be read.
pub const READ_ONLY: Access = gl::READ_ONLY;
/// States that the returned value will only be written
/// to.
pub const WRITE_ONLY: Access = gl::WRITE_ONLY;
/// Buffer is a storage for vertex data.
pub struct Buffer {
internal: u32,
}
impl Buffer {
/// Allocates a new Buffer.
pub fn new() -> Buffer {
let mut b = Buffer {
internal: 0,
};
unsafe { gl::GenBuffers(1, &mut b.internal); }
b
}
/// Makes the buffer the currently active one for the given target.
/// 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.internal); }
}
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);
}
}
/// Maps the memory in the buffer on the gpu to memory which the program
/// can access. The access flag will specify how the program plans to use the
/// returned data. It'll unmap itself once the returned value is dropped.
///
/// Warning: the passed length value is not checked in anyway so it is
/// possible to overrun the memory. It is up to the program to ensure this
/// 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}
}
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe {
gl::DeleteBuffers(1, &self.internal);
}
}
}
pub struct MappedBuffer {
inner: Vec<u8>,
target: BufferTarget,
}
impl Deref for MappedBuffer {
type Target = Vec<u8>;
fn deref<'a>(&'a self) -> &'a Self::Target {
&self.inner
}
}
impl DerefMut for MappedBuffer {
fn deref_mut<'a>(&'a mut self) -> &'a mut Self::Target {
&mut self.inner
}
}
impl Drop for MappedBuffer {
fn drop(&mut self) {
unsafe { gl::UnmapBuffer(self.target); }
mem::forget(mem::replace(&mut self.inner, Vec::new()));
}
}

View File

@ -1,10 +1,9 @@
extern crate byteorder;
use nbt;
use protocol::{Serializable};
use std::io;
use std::io::{Read, Write};
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
#[derive(Debug)]
pub struct Stack {

View File

@ -1,8 +0,0 @@
#![cfg_attr(test, allow(dead_code))]
pub mod bit;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;

View File

@ -1,10 +1,29 @@
extern crate glfw;
extern crate steven;
pub mod bit;
pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
use steven::*;
extern crate glfw;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
use std::sync::{Arc, RwLock};
use glfw::{Action, Context, Key};
fn main() {
let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
{ resource_manager.write().unwrap().tick(); }
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
@ -22,9 +41,20 @@ fn main() {
window.make_current();
glfw.set_swap_interval(1);
let mut renderer = render::Renderer::new(resource_manager.clone());
let mut last_frame = time::now();
let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;
while !window.should_close() {
gl::clear_color(1.0, 0.0, 0.0, 1.0);
gl::clear(gl::ClearFlags::Color | gl::ClearFlags::Depth);
{ resource_manager.write().unwrap().tick(); }
let now = time::now();
let diff = now - last_frame;
last_frame = now;
let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
let (width, height) = window.get_framebuffer_size();
renderer.tick(delta, width as u32, height as u32);
window.swap_buffers();
glfw.poll_events();

View File

@ -1,4 +1,3 @@
extern crate byteorder;
use std::collections::HashMap;
use std::io;
@ -6,7 +5,7 @@ use std::io::{Read, Write};
use super::protocol::{Serializable};
use super::protocol;
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
#[derive(Debug)]
pub enum Tag {

View File

@ -1,9 +1,7 @@
#![allow(dead_code)]
extern crate byteorder;
extern crate hyper;
extern crate steven_openssl as openssl;
extern crate flate2;
extern crate serde_json;
use openssl;
use serde_json;
pub mod mojang;
@ -15,8 +13,9 @@ use std::net::TcpStream;
use std::io;
use std::io::{Write, Read};
use std::convert;
use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use self::flate2::read::{ZlibDecoder, ZlibEncoder};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use flate2::read::{ZlibDecoder, ZlibEncoder};
use flate2;
/// Helper macro for defining packets
#[macro_export]

View File

@ -1,6 +1,8 @@
extern crate steven_openssl as openssl;
extern crate serde_json;
extern crate hyper;
use openssl;
use serde_json;
use hyper;
pub struct Profile {
pub username: String,

85
src/render/atlas.rs Normal file
View File

@ -0,0 +1,85 @@
pub struct Atlas {
width: usize,
height: usize,
free_space: Vec<Rect>,
}
#[derive(Debug, Clone, Copy)]
pub struct Rect {
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 {
width: width,
height: height,
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<Rect> {
let mut priority = usize::max_value();
let mut target: Option<Rect> = None;
let mut index = 0;
let mut target_index = 0;
// Search through and find the best fit for this texture
for free in &self.free_space {
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;
}
}
index += 1;
}
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 {
// Remove empty sections
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;
}
Some(ret)
}
}

51
src/render/glsl.rs Normal file
View File

@ -0,0 +1,51 @@
use std::collections::HashMap;
pub struct Registry {
shaders: HashMap<String, String>,
}
impl Registry {
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 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
}
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");
}
}
}

536
src/render/mod.rs Normal file
View File

@ -0,0 +1,536 @@
mod atlas;
pub mod glsl;
pub mod ui;
mod shaders;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use resources;
use gl;
use image;
use image::{GenericImage};
use byteorder::{WriteBytesExt, NativeEndian};
use serde_json;
const ATLAS_SIZE: usize = 1024;
pub struct Renderer {
resource_version: usize,
resources: Arc<RwLock<resources::Manager>>,
textures: Arc<RwLock<TextureManager>>,
glsl: glsl::Registry,
ui: ui::UIState,
gl_texture: gl::Texture,
texture_layers: usize,
last_width: u32,
last_height: u32,
temp_rot: f64,
}
impl Renderer {
pub fn new(res: Arc<RwLock<resources::Manager>>) -> 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*1*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 mut greg = glsl::Registry::new();
shaders::add_shaders(&mut greg);
let ui = ui::UIState::new(&greg, textures.clone(), res.clone());
Renderer {
resource_version: version,
textures: textures,
glsl: greg,
ui: ui,
resources: res,
gl_texture: tex,
texture_layers: 1,
last_width: 0,
last_height: 0,
temp_rot: 0.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);
}
}
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);
}
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(gl::ClearFlags::Color | gl::ClearFlags::Depth);
let test = self.ui.new_text("Hello world", 10.0, 10.0, 255, 255, 255);
let data = test.bytes(width as f64, height as f64);
self.ui.add_bytes(&data);
let test = self.ui.new_text("Font rendering is complete! (ish)", 10.0, 30.0, 0, 255, 0);
let data = test.bytes(width as f64, height as f64);
self.ui.add_bytes(&data);
self.temp_rot += delta * 0.05;
let test = self.ui.new_text_rotated("Yay! Progress!", 150.0, 150.0, 1.0, 1.0, self.temp_rot, 255, 0, 0);
let data = test.bytes(width as f64, height as f64);
self.ui.add_bytes(&data);
self.ui.tick(width, height);
}
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 self.textures.write().unwrap().animated_textures.iter_mut() {
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<RwLock<TextureManager>> {
self.textures.clone()
}
pub fn get_textures_ref(&self) -> &RwLock<TextureManager> {
&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 get_texture(textures: &RwLock<TextureManager>, 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()
}
}
}
}
}
pub struct TextureManager {
textures: HashMap<String, Texture>,
version: usize,
resources: Arc<RwLock<resources::Manager>>,
atlases: Vec<atlas::Atlas>,
animated_textures: Vec<AnimatedTexture>,
pending_uploads: Vec<(i32, atlas::Rect, Vec<u8>)>,
}
impl TextureManager {
fn new(res: Arc<RwLock<resources::Manager>>) -> TextureManager {
let mut tm = TextureManager {
textures: HashMap::new(),
version: 0xFFFF,
resources: res,
atlases: Vec::new(),
animated_textures: Vec::new(),
pending_uploads: Vec::new(),
};
tm.add_defaults();
tm
}
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![
255, 255, 255, 255,
]);
}
fn update_textures(&mut self, version: usize) {
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();
for name in map.keys() {
self.load_texture(name);
}
}
fn get_texture(&self, name: &str) -> Option<Texture> {
self.textures.get(name).map(|v| v.clone())
}
// TODO: Animated textures
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(name);
}
fn load_animation(&mut self, plugin: &str, name: &str, img: &image::DynamicImage, data: Vec<u8>) -> Option<AnimatedTexture> {
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
};
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<u8>) -> 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 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 self.atlases.iter_mut() {
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, name: &str) -> Texture {
let missing = self.get_texture("steven:missing_texture").unwrap();
let t = Texture {
name: 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(name.to_owned(), t.clone());
t
}
}
struct AnimatedTexture {
frames: Vec<AnimationFrame>,
data: Vec<u8>,
interpolate: bool,
current_frame: usize,
remaining_time: f64,
texture: Texture,
}
struct AnimationFrame {
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,
}
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_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_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 create_program(vertex: &str, fragment: &str) -> gl::Program {
let program = gl::Program::new();
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.len() > 0 {
println!("{}", log);
}
}
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.len() > 0 {
println!("{}", log);
}
}
program.attach_shader(v);
program.attach_shader(f);
program.link();
program.use_program();
program
}
#[allow(unused_must_use)]
pub fn generate_element_buffer(size: usize) -> (Vec<u8>, 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;
let data = Vec::with_capacity(size*4);
data
} else {
let data = Vec::with_capacity(size*2);
data
};
for i in 0 .. size/6 {
for val in &[0, 1, 2, 2, 1, 3] {
if ty == gl::UNSIGNED_INT {
data.write_u32::<NativeEndian>((i as u32) * 4 + val);
} else {
data.write_u16::<NativeEndian>((i as u16) * 4 + (*val as u16));
}
}
}
(data, ty)
}

10
src/render/shaders.rs Normal file
View File

@ -0,0 +1,10 @@
use render::glsl;
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("ui_vertex", include_str!("shaders/ui_vertex.glsl"));
reg.register("ui_frag", include_str!("shaders/ui_frag.glsl"));
}

View File

@ -0,0 +1,28 @@
vec3 getLight(vec2 light) {
vec2 li = pow(vec2(lightLevel), 15.0 - light);
float skyTint = skyOffset * 0.95 + 0.05;
float bl = li.x;
float sk = li.y * skyTint;
float skyRed = sk * (skyOffset * 0.65 + 0.35);
float skyGreen = sk * (skyOffset * 0.65 + 0.35);
float blockGreen = bl * ((bl * 0.6 + 0.4) * 0.6 + 0.4);
float blockBlue = bl * (bl * bl * 0.6 + 0.4);
vec3 col = vec3(
skyRed + bl,
skyGreen + blockGreen,
sk + blockBlue
);
col = col * 0.96 + 0.03;
float gamma = 0.0;
vec3 invCol = 1.0 - col;
invCol = 1.0 - invCol * invCol * invCol * invCol;
col = col * (1.0 - gamma) + invCol * gamma;
col = col * 0.96 + 0.03;
return clamp(col, 0.0, 1.0);
}

View File

@ -0,0 +1,8 @@
const float invAtlasSize = 1.0 / 1024;
vec4 atlasTexture() {
vec2 tPos = vTextureOffset;
tPos = mod(tPos, vTextureInfo.zw);
tPos += vTextureInfo.xy;
tPos *= invAtlasSize;
return texture(textures, vec3(tPos, vAtlas));
}

View File

@ -0,0 +1,17 @@
uniform sampler2DArray textures;
in vec4 vColor;
in vec4 vTextureInfo;
in vec2 vTextureOffset;
in float vAtlas;
out vec4 fragColor;
#include lookup_texture
void main() {
vec4 col = atlasTexture();
col *= vColor;
if (col.a == 0.0) discard;
fragColor = col;
}

View File

@ -0,0 +1,20 @@
in ivec3 aPosition;
in vec4 aTextureInfo;
in ivec3 aTextureOffset;
in vec4 aColor;
out vec4 vColor;
out vec4 vTextureInfo;
out vec2 vTextureOffset;
out float vAtlas;
uniform vec2 screenSize;
void main() {
vec2 pos = aPosition.xy / screenSize;
gl_Position = vec4((pos.x-0.5)*2.0, -(pos.y-0.5)*2.0, float(-aPosition.z) / float(0xFFFF-1), 1.0);
vColor = aColor;
vTextureInfo = aTextureInfo;
vTextureOffset = aTextureOffset.xy / 16.0;
vAtlas = aTextureOffset.z;
}

456
src/render/ui.rs Normal file
View File

@ -0,0 +1,456 @@
use std::sync::{Arc, RwLock};
use std::io::Write;
use std::collections::HashMap;
use resources;
use gl;
use render;
use byteorder::{WriteBytesExt, NativeEndian};
use image;
use image::{GenericImage};
const UI_WIDTH: f64 = 854.0;
const UI_HEIGHT: f64 = 480.0;
pub struct UIState {
textures: Arc<RwLock<render::TextureManager>>,
resources: Arc<RwLock<resources::Manager>>,
version: usize,
data: Vec<u8>,
prev_size: usize,
count: usize,
array: gl::VertexArray,
buffer: gl::Buffer,
index_buffer: gl::Buffer,
index_type: gl::Type,
max_index: usize,
shader: gl::Program,
s_position: gl::Attribute,
s_texture_info: gl::Attribute,
s_texture_offset: gl::Attribute,
s_color: gl::Attribute,
s_texture: gl::Uniform,
s_screensize: gl::Uniform,
// Font
font_pages: Vec<Option<render::Texture>>,
font_character_info: [(i32,i32); 0x10000],
char_map: HashMap<char, char>,
page_width: f64,
page_height: f64,
}
impl UIState {
pub fn new(glsl: &super::glsl::Registry, textures: Arc<RwLock<render::TextureManager>>, res: Arc<RwLock<resources::Manager>>) -> UIState {
let v = glsl.get("ui_vertex");
let f = glsl.get("ui_frag");
let shader = super::create_program(&v, &f);
let s_position = shader.attribute_location("aPosition");
let s_texture_info = shader.attribute_location("aTextureInfo");
let s_texture_offset = shader.attribute_location("aTextureOffset");
let s_color = shader.attribute_location("aColor");
let s_texture = shader.uniform_location("textures");
let s_screensize = shader.uniform_location("screenSize");
let array = gl::VertexArray::new();
array.bind();
let buffer = gl::Buffer::new();
buffer.bind(gl::ARRAY_BUFFER);
s_position.enable();
s_texture_info.enable();
s_texture_offset.enable();
s_color.enable();
s_position.vertex_pointer_int(3, gl::SHORT, 28, 0);
s_texture_info.vertex_pointer(4, gl::UNSIGNED_SHORT, false, 28, 8);
s_texture_offset.vertex_pointer_int(3, gl::SHORT, 28, 16);
s_color.vertex_pointer(4, gl::UNSIGNED_BYTE, true, 28, 24);
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 char_map = HashMap::new();
let ascii_chars = "ÀÁÂÈÊËÍÓÔÕÚßãõğİıŒœŞşŴŵžȇ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αβΓπΣσμτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■";
let mut pos = 0u32;
for c in ascii_chars.chars() {
char_map.insert(c, ::std::char::from_u32(pos).unwrap());
pos += 1;
}
UIState {
textures: textures,
resources: res,
version: 0xFFFF,
data: Vec::new(),
count: 0,
prev_size: 0,
index_type: gl::UNSIGNED_BYTE,
array: array,
buffer: buffer,
index_buffer: index_buffer,
max_index: 0,
shader: shader,
s_position: s_position,
s_texture_info: s_texture_info,
s_texture_offset: s_texture_offset,
s_color: s_color,
s_texture: s_texture,
s_screensize: s_screensize,
// Font
font_pages: pages,
font_character_info: [(0, 0); 0x10000],
char_map: char_map,
page_width: 0.0,
page_height: 0.0,
}
}
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);
self.shader.use_program();
self.s_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.s_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);
}
gl::disable(gl::BLEND);
self.data.clear();
self.count = 0;
}
pub fn add_bytes(&mut self, data: &Vec<u8>) {
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;
// 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();
let raw = if page == 0 {
self.char_map[&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)
)
}
return 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_char(&self, c: char) -> f64 {
if c == ' ' {
return 4.0;
}
let r = c as u32;
if r >> 8 == 0 {
let r = self.char_map[&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];
return (info.1 - info.0) as f64;
}
fn load_font(&mut self) {
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 in 0 .. self.font_character_info.len() {
// Top nibble - start position
// Bottom nibble - end position
self.font_character_info[i].0 = (data[i] >> 4) as i32;
self.font_character_info[i].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_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)
}
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 mut raw = ch as u32;
let page = raw >> 8;
if page == 0 {
raw = self.char_map[&ch] as u32;
}
let info = self.font_character_info[raw as usize];
let w = if page == 0 {
let sw = self.page_width / 16.0;
((info.1 - info.0) as f64 / sw) * 16.0
} else {
(info.1 - info.0) as f64
};
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 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<UIElement>,
pub width: f64,
}
impl UIText {
pub fn bytes(&self, width: f64, height: f64) -> Vec<u8> {
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,
}
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 bytes(&self, width: f64, height: f64) -> Vec<u8> {
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<u8>, 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::<NativeEndian>((dx*width+0.5).floor() as i16);
buf.write_i16::<NativeEndian>((dy*height+0.5).floor() as i16);
buf.write_i16::<NativeEndian>((self.layer * 256) as i16);
buf.write_i16::<NativeEndian>(0);
buf.write_u16::<NativeEndian>(self.t_x);
buf.write_u16::<NativeEndian>(self.t_y);
buf.write_u16::<NativeEndian>(self.t_w);
buf.write_u16::<NativeEndian>(self.t_h);
buf.write_i16::<NativeEndian>(tx);
buf.write_i16::<NativeEndian>(ty);
buf.write_i16::<NativeEndian>(self.t_atlas);
buf.write_i16::<NativeEndian>(0);
buf.write_u8(self.r);
buf.write_u8(self.g);
buf.write_u8(self.b);
buf.write_u8(self.a);
}
}

170
src/resources.rs Normal file
View File

@ -0,0 +1,170 @@
extern crate hyper;
extern crate zip;
use std::thread;
use std::path;
use std::io;
use std::fs;
use std::sync::mpsc;
const RESOURCES_VERSION: &'static str = "15w37a";
pub trait Pack {
fn open(&self, name: &str) -> Option<Box<io::Read>>;
}
pub struct Manager {
packs: Vec<Box<Pack>>,
version: usize,
vanilla_chan: Option<mpsc::Receiver<bool>>,
}
impl Manager {
pub fn new() -> Manager {
let mut m = Manager {
packs: Vec::new(),
version: 0,
vanilla_chan: None,
};
m.download_vanilla();
m
}
/// Returns the 'version' of the manager. The version is
/// increase everytime a pack is added or removed.
pub fn version(&self) -> usize {
self.version
}
pub fn open(&self, plugin: &str, name: &str) -> Option<Box<io::Read>> {
for pack in self.packs.iter().rev() {
let path = format!("assets/{}/{}", plugin, name);
match pack.open(&path) {
Some(val) => return Some(val),
None => {},
}
}
None
}
pub fn open_all(&self, plugin: &str, name: &str) -> Vec<Box<io::Read>> {
let mut ret = Vec::new();
for pack in self.packs.iter().rev() {
let path = format!("assets/{}/{}", plugin, name);
match pack.open(&path) {
Some(val) => ret.push(val),
None => {},
}
}
ret
}
pub fn tick(&mut self) {
// 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 {
if let Ok(_) = recv.try_recv() {
done = true;
}
}
if done {
self.vanilla_chan = None;
self.load_vanilla();
}
}
fn add_pack(&mut self, pck: Box<Pack>) {
self.packs.push(pck);
self.version += 1;
}
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(),
}))
}
fn download_vanilla(&mut self) {
let loc = format!("./resources-{}", RESOURCES_VERSION);
let location = path::Path::new(&loc);
if fs::metadata(location.join("steven.assets")).is_ok() {
self.load_vanilla();
return;
}
let (send, recv) = mpsc::channel();
self.vanilla_chan = Some(recv);
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 res = client.get(&url)
.send().unwrap();
let mut file = fs::File::create(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
let length = *res.headers.get::<hyper::header::ContentLength>().unwrap();
let mut progress = ProgressRead {
read: res,
progress: 0,
total: *length,
};
io::copy(&mut progress, &mut file).unwrap();
// Copy the resources from the zip
let file = fs::File::open(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
let mut zip = zip::ZipArchive::new(file).unwrap();
let loc = format!("./resources-{}", RESOURCES_VERSION);
let location = path::Path::new(&loc);
let count = zip.len();
for i in 0 .. count {
let mut file = zip.by_index(i).unwrap();
if !file.name().starts_with("assets/") {
continue;
}
let path = location.join(file.name());
fs::create_dir_all(path.parent().unwrap()).unwrap();
let mut out = fs::File::create(path).unwrap();
io::copy(&mut file, &mut out).unwrap();
}
fs::File::create(location.join("steven.assets")).unwrap(); // Marker file
println!("Done");
send.send(true).unwrap();
fs::remove_file(format!("{}.tmp", RESOURCES_VERSION)).unwrap();
});
}
}
struct DirPack {
root: path::PathBuf,
}
impl Pack for DirPack {
fn open(&self, name: &str) -> Option<Box<io::Read>> {
match fs::File::open(self.root.join(name)) {
Ok(val) => Some(Box::new(val)),
Err(_) => None,
}
}
}
struct ProgressRead<T> {
read: T,
total: u64,
progress: u64,
}
impl <T: io::Read> io::Read for ProgressRead<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let size = try!(self.read.read(buf));
self.progress += size as u64;
println!("Progress: {:.2}", (self.progress as f64) / (self.total as f64));
Ok(size)
}
}

View File

@ -15,6 +15,7 @@ pub struct MetadataKey<T: MetaValue> {
}
impl <T: MetaValue> MetadataKey<T> {
#[allow(dead_code)]
// TODO: Make const later when possible
/*const*/ fn new(index: i32) -> MetadataKey<T> {
MetadataKey {