Base of ui complete
This commit is contained in:
parent
ab2336ffca
commit
5aef272d43
|
@ -1 +1,3 @@
|
|||
target/
|
||||
.rust/
|
||||
working/
|
||||
|
|
|
@ -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)",
|
||||
]
|
||||
|
||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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)",
|
||||
]
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -5,3 +5,4 @@ authors = [ "Thinkofdeath <thinkofdeath@spigotmc.org>" ]
|
|||
|
||||
[dependencies]
|
||||
libc = "*"
|
||||
openssl-sys = "0.6.5"
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
extern crate serde_json;
|
||||
|
||||
use serde_json;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
484
src/gl/mod.rs
484
src/gl/mod.rs
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
|
@ -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();
|
|
@ -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 {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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"));
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue