mirror of
https://github.com/scurest/apicula.git
synced 2025-06-18 14:45:37 -04:00
It works! Commit it
This commit is contained in:
commit
a9295e7d37
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target
|
728
Cargo.lock
generated
Normal file
728
Cargo.lock
generated
Normal file
@ -0,0 +1,728 @@
|
||||
[root]
|
||||
name = "demense"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cgmath 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glium 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_glue"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cgl"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gleam 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cgmath"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dbghelp-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "dlib"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libloading 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dwmapi-sys"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "env_logger"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gdi32-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xml-rs 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gleam"
|
||||
version = "0.2.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glium"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glutin 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glutin"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cocoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x11-dl 2.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "khronos_api"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target_build_utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fs2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "osmesa-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"phf_shared 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"phf_generator 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_shared 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"phf_shared 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_library"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell32-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "smallvec"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "target_build_utils"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "2.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "user32-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dlib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-scanner 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-sys 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-kbd"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dlib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"xml-rs 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dlib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-window"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "x11-dl"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||
"checksum android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e2b80445d331077679dfc6f3014f3e9ab7083e588423d35041d3fc017198189"
|
||||
"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
|
||||
"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
|
||||
"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
|
||||
"checksum backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3602e8d8c43336088a8505fa55cae2b3884a9be29440863a11528a42f46f6bb7"
|
||||
"checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||
"checksum cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10"
|
||||
"checksum cgmath 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "232472604dbad61c384edfc4d833315d487894826856836b7227b37fe3abe02b"
|
||||
"checksum cocoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3afe4613f57a171039a98db1773f5840b5743cf85aaf03afb65ddfade4f4a9db"
|
||||
"checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
|
||||
"checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
|
||||
"checksum core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0c56c6022ba22aedbaa7d231be545778becbe1c7aceda4c82ba2f2084dd4c723"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||
"checksum dlib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "148bce4ce1c36c4509f29cb54e62c2bd265551a9b00b38070fad551a851866ec"
|
||||
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
||||
"checksum dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07c4c7cc7b396419bc0a4d90371d0cee16cb5053b53647d287c0b728000c41fe"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cd681735364a04cd5d69f01a4f6768e70473941f8d86d8c224faf6955a75799"
|
||||
"checksum fs2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bcd414e5a1a979b931bb92f41b7a54106d3f6d2e6c253e9ce943b7cd468251ef"
|
||||
"checksum gcc 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)" = "771e4a97ff6f237cf0f7d5f5102f6e28bb9743814b6198d684da5c58b76c11e0"
|
||||
"checksum gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "65256ec4dc2592e6f05bfc1ca3b956a4e0698aa90b1dff1f5687d55a5a3fd59a"
|
||||
"checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55"
|
||||
"checksum gleam 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "b0b10e85c0e5fc984464336007e592a9072dcd976aa0687d2b67966bc83322d8"
|
||||
"checksum glium 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30bfe6ac8600d25f7f2a1e3203566b156d66e7c2f358f6bb79b5419ddaecd671"
|
||||
"checksum glutin 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "06786fae66e7aa8464b3d8d3fb7a7c470f89d62ae511f9613ea7fbbeef61d680"
|
||||
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c9d3760673c427d46f91a0350f0a84a52e6bc5a84adf26dc610b6c52436630"
|
||||
"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
|
||||
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
||||
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
|
||||
"checksum libloading 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "84816a8c6ed8163dfe0dbdd2b09d35c6723270ea77a4c7afa4bedf038a36cb99"
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum memmap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f20f72ed93291a72e22e8b16bb18762183bb4943f0f483da5b8be1a9e8192752"
|
||||
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
|
||||
"checksum objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "877f30f37acef6749b1841cceab289707f211aecfc756553cd63976190e6cc2e"
|
||||
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
|
||||
"checksum phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0c6afb2057bb5f846a7b75703f90bc1cef4970c35209f712925db7768e999202"
|
||||
"checksum phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "6b63f121bf9a128f2172a65d8313a8e0e79d63874eeb4b4b7d82e6dda6b62f7c"
|
||||
"checksum phf_generator 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "50ffbd7970f75afa083c5dd7b6830c97b72b81579c7a92d8134ef2ee6c0c7eb0"
|
||||
"checksum phf_shared 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "286385a0e50d4147bce15b2c19f0cf84c395b0e061aaf840898a7bf664c2cfb7"
|
||||
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
|
||||
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||
"checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc"
|
||||
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
|
||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
||||
"checksum serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0e0732aa8ec4267f61815a396a942ba3525062e3bd5520aa8419927cfc0a92"
|
||||
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5"
|
||||
"checksum serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7d3c184d35801fb8b32b46a7d58d57dbcc150b0eb2b46a1eb79645e8ecfd5b"
|
||||
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
|
||||
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
|
||||
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
|
||||
"checksum target_build_utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54c550e226618cd35334b75e92bfa5437c61474bdb75c38bf330ab5a8037b77c"
|
||||
"checksum tempfile 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9270837a93bad1b1dac18fe67e786b3c960513af86231f6f4f57fddd594ff0c8"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
|
||||
"checksum user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6717129de5ac253f5642fc78a51d0c7de6f9f53d617fc94e9bae7f6e71cf5504"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ced3094c157b5cc0a08d40530e1a627d9f88b9a436971338d2646439128a559e"
|
||||
"checksum wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "73bc10e84c1da90777beffecd24742baea17564ffc2a9918af41871c748eb050"
|
||||
"checksum wayland-scanner 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5a1869370d6bafcbabae8724511d803f4e209a70e94ad94a4249269534364f66"
|
||||
"checksum wayland-sys 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9633f7fe5de56544215f82eaf1b76bf1b584becf7f08b58cbef4c2c7d10e803a"
|
||||
"checksum wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "309b69d3a863c9c21422d889fb7d98cf02f8a2ca054960a49243ce5b67ad884c"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum x11-dl 2.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4c7f0a7fb861a1bde4aa23bbda9509bda6b87de4d47c322f86e4c88241ebdd"
|
||||
"checksum xml-rs 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b15eed12692bd59d15e98ee7f8dc8408465b992d8ddb4d1672c24865132ec7"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "demense"
|
||||
version = "0.1.0"
|
||||
authors = ["scurest <scurest@users.noreply.github.com>"]
|
||||
license = "CC0-1.0"
|
||||
|
||||
[dependencies]
|
||||
cgmath = "0.12.0"
|
||||
env_logger = "0.3.5"
|
||||
error-chain = "0.7.1"
|
||||
glium = "0.15.0"
|
||||
log = "0.3.6"
|
||||
time = "0.1.35"
|
10
src/errors.rs
Normal file
10
src/errors.rs
Normal file
@ -0,0 +1,10 @@
|
||||
error_chain! {}
|
||||
|
||||
macro_rules! check {
|
||||
($b:expr) => {
|
||||
if !$b {
|
||||
error!("expected: {})", stringify!($b));
|
||||
return Err("sanity check failed".into());
|
||||
}
|
||||
};
|
||||
}
|
156
src/geometry.rs
Normal file
156
src/geometry.rs
Normal file
@ -0,0 +1,156 @@
|
||||
use cgmath::Point2;
|
||||
use cgmath::Point3;
|
||||
use gfx;
|
||||
use std::default::Default;
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Vertex {
|
||||
pub position: [f32; 3],
|
||||
pub texcoord: [f32; 2],
|
||||
pub color: [f32; 3],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshRange {
|
||||
pub vertex_range: Range<u16>,
|
||||
pub index_range: Range<usize>,
|
||||
pub mat_id: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GeometryData {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u16>,
|
||||
pub mesh_ranges: Vec<MeshRange>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Sink {
|
||||
pub data: GeometryData,
|
||||
pub cur_texture_dim: (u32, u32),
|
||||
cur_mesh_range: MeshRange,
|
||||
cur_prim_type: u32,
|
||||
next_texcoord: Point2<f64>,
|
||||
next_color: Point3<f32>,
|
||||
}
|
||||
|
||||
impl Sink {
|
||||
pub fn new() -> Sink {
|
||||
Sink {
|
||||
data: Default::default(),
|
||||
cur_mesh_range: MeshRange {
|
||||
vertex_range: 0..0,
|
||||
index_range: 0..0,
|
||||
mat_id: 0,
|
||||
},
|
||||
cur_prim_type: 0,
|
||||
cur_texture_dim: (1,1),
|
||||
next_texcoord: Point2::new(0.0, 0.0),
|
||||
next_color: Point3::new(1.0, 1.0, 1.0),
|
||||
}
|
||||
}
|
||||
pub fn begin_mesh(&mut self, mat_id: u8) {
|
||||
let len = self.data.indices.len();
|
||||
self.cur_mesh_range.index_range = len .. len;
|
||||
self.cur_mesh_range.mat_id = mat_id;
|
||||
self.next_texcoord = Point2::new(0.0, 0.0);
|
||||
self.next_color = Point3::new(1.0, 1.0, 1.0);
|
||||
}
|
||||
pub fn end_mesh(&mut self) {
|
||||
self.data.mesh_ranges.push(self.cur_mesh_range.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl gfx::Sink for Sink {
|
||||
fn begin(&mut self, prim_type: u32) {
|
||||
self.cur_prim_type = prim_type;
|
||||
let len = self.data.vertices.len() as u16;
|
||||
self.cur_mesh_range.vertex_range = len .. len;
|
||||
}
|
||||
fn end(&mut self) {
|
||||
let r = self.cur_mesh_range.vertex_range.clone();
|
||||
match self.cur_prim_type {
|
||||
0 => {
|
||||
// Seperate triangles
|
||||
let mut i = r.start;
|
||||
while i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i+1, i+2,
|
||||
]);
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
// Seperate quads
|
||||
let mut i = r.start;
|
||||
while i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i+1, i+2,
|
||||
i+2, i+3, i,
|
||||
]);
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
// Triangle strip
|
||||
let mut i = r.start;
|
||||
if i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i+1, i+2,
|
||||
]);
|
||||
i += 3;
|
||||
}
|
||||
while i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i-1, i-2,
|
||||
]);
|
||||
i += 1;
|
||||
if i == r.end { break; }
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i-2, i-1,
|
||||
]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
// Quad strip
|
||||
let mut i = r.start;
|
||||
if i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i, i+1, i+2,
|
||||
i+2, i+1, i+3,
|
||||
]);
|
||||
i += 4;
|
||||
}
|
||||
while i != r.end {
|
||||
self.data.indices.extend_from_slice(&[
|
||||
i-2, i-1, i,
|
||||
i, i-1, i+1,
|
||||
]);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.cur_mesh_range.index_range.end = self.data.indices.len();
|
||||
}
|
||||
fn texcoord(&mut self, texcoord: Point2<f64>) {
|
||||
self.next_texcoord = Point2::new(
|
||||
texcoord.x / self.cur_texture_dim.0 as f64,
|
||||
// TODO: t coordinate seems to be wrong for mirrored textures
|
||||
1.0 - texcoord.y / self.cur_texture_dim.1 as f64,
|
||||
);
|
||||
}
|
||||
fn color(&mut self, color: Point3<f32>) {
|
||||
self.next_color = color;
|
||||
}
|
||||
fn vertex(&mut self, v: Point3<f64>) {
|
||||
self.data.vertices.push(Vertex {
|
||||
position: [v.x as f32, v.y as f32, v.z as f32],
|
||||
texcoord: [self.next_texcoord.x as f32, self.next_texcoord.y as f32],
|
||||
color: [self.next_color.x, self.next_color.y, self.next_color.z],
|
||||
});
|
||||
self.cur_mesh_range.vertex_range.end += 1;
|
||||
}
|
||||
}
|
185
src/gfx.rs
Normal file
185
src/gfx.rs
Normal file
@ -0,0 +1,185 @@
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::Point2;
|
||||
use cgmath::Point3;
|
||||
use cgmath::Transform;
|
||||
use cgmath::vec3;
|
||||
use cgmath::vec4;
|
||||
use errors::Result;
|
||||
use util::bits::BitField;
|
||||
use util::fixed::fix16;
|
||||
use util::fixed::fix32;
|
||||
use util::view::View;
|
||||
|
||||
pub trait Sink {
|
||||
fn begin(&mut self, prim_type: u32);
|
||||
fn end(&mut self);
|
||||
fn vertex(&mut self, v: Point3<f64>);
|
||||
fn texcoord(&mut self, tc: Point2<f64>);
|
||||
fn color(&mut self, color: Point3<f32>);
|
||||
}
|
||||
|
||||
pub struct GfxState {
|
||||
pub vertex: Point3<f64>,
|
||||
pub cur_mat: Matrix4<f64>,
|
||||
pub mat_stack: Vec<Matrix4<f64>>,
|
||||
pub texture_mat: Matrix4<f64>,
|
||||
}
|
||||
|
||||
impl GfxState {
|
||||
pub fn new() -> GfxState {
|
||||
GfxState {
|
||||
vertex: Point3::new(0.0, 0.0, 0.0),
|
||||
cur_mat: Matrix4::from_scale(1.0),
|
||||
mat_stack: vec![Matrix4::from_scale(1.0); 32],
|
||||
texture_mat: Matrix4::from_scale(1.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, id: u32) {
|
||||
self.cur_mat = self.mat_stack[id as usize];
|
||||
}
|
||||
|
||||
pub fn run_commands<S: Sink>(&mut self, sink: &mut S, mut cmds: &[u8]) -> Result<()> {
|
||||
let mut fifo = &cmds[0..0];
|
||||
while cmds.len() != 0 {
|
||||
if fifo.len() == 0 {
|
||||
fifo = &cmds[0..4];
|
||||
cmds = &cmds[4..];
|
||||
}
|
||||
let opcode = fifo[0];
|
||||
fifo = &fifo[1..];
|
||||
let size = gfx_cmd_size(opcode)?;
|
||||
let params = View::from_buf(&cmds[0..4*size]);
|
||||
cmds = &cmds[4*size..];
|
||||
self.run_command(sink, opcode, params);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_command<S: Sink>(&mut self, sink: &mut S, opcode: u8, params: View<u32>) {
|
||||
match opcode {
|
||||
0x00 => {
|
||||
// NOP
|
||||
}
|
||||
0x14 => {
|
||||
// MTX_RESTORE - Restore Current Matrix from Stack
|
||||
let restore_id = params.get(0);
|
||||
self.restore(restore_id);
|
||||
}
|
||||
0x1b => {
|
||||
// MTX_SCALE - Multiply Current Matrix by Scale Matrix
|
||||
let sx = fix32(params.get(0), 1, 19, 12);
|
||||
let sy = fix32(params.get(1), 1, 19, 12);
|
||||
let sz = fix32(params.get(2), 1, 19, 12);
|
||||
self.cur_mat = self.cur_mat * Matrix4::from_nonuniform_scale(sx, sy, sz);
|
||||
}
|
||||
0x40 => {
|
||||
// BEGIN_VTXS - Start of Vertex List
|
||||
let prim_type = params.get(0);
|
||||
sink.begin(prim_type);
|
||||
}
|
||||
0x41 => {
|
||||
// END_VTXS - End of Vertex List
|
||||
sink.end();
|
||||
}
|
||||
0x23 => {
|
||||
// VTX_16 - Set Vertex XYZ Coordinates
|
||||
let p0 = params.get(0);
|
||||
let p1 = params.get(1);
|
||||
let x = fix16(p0.bits(0,16) as u16, 1, 3, 12);
|
||||
let y = fix16(p0.bits(16,32) as u16, 1, 3, 12);
|
||||
let z = fix16(p1.bits(0,16) as u16, 1, 3, 12);
|
||||
let v = Point3::new(x, y, z);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x24 => {
|
||||
// VTX_10 - Set Vertex XYZ Coordinates
|
||||
let p = params.get(0);
|
||||
let x = fix16(p.bits(0,10) as u16, 1, 3, 6);
|
||||
let y = fix16(p.bits(10,20) as u16, 1, 3, 6);
|
||||
let z = fix16(p.bits(20,30) as u16, 1, 3, 6);
|
||||
let v = Point3::new(x, y, z);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x25 => {
|
||||
// VTX_XY - Set Vertex XY Coordinates
|
||||
let p = params.get(0);
|
||||
let x = fix16(p.bits(0,16) as u16, 1, 3, 12);
|
||||
let y = fix16(p.bits(16,32) as u16, 1, 3, 12);
|
||||
let v = Point3::new(x, y, self.vertex.z);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x26 => {
|
||||
// VTX_XZ - Set Vertex XZ Coordinates
|
||||
let p = params.get(0);
|
||||
let x = fix16(p.bits(0,16) as u16, 1, 3, 12);
|
||||
let z = fix16(p.bits(16,32) as u16, 1, 3, 12);
|
||||
let v = Point3::new(x, self.vertex.y, z);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x27 => {
|
||||
// VTX_YZ - Set Vertex YZ Coordinates
|
||||
let p = params.get(0);
|
||||
let y = fix16(p.bits(0,16) as u16, 1, 3, 12);
|
||||
let z = fix16(p.bits(16,32) as u16, 1, 3, 12);
|
||||
let v = Point3::new(self.vertex.x, y, z);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x28 => {
|
||||
// VTX_DIFF - Set Relative Vertex Coordinates
|
||||
let p = params.get(0);
|
||||
// Differences are 10-bit numbers, scaled by 1/2^3 to put them
|
||||
// in the same 1,3,12 format as the others VTX commands.
|
||||
let scale = 0.5f64.powi(3);
|
||||
let dx = scale * fix16(p.bits(0,10) as u16, 1, 0, 9);
|
||||
let dy = scale * fix16(p.bits(10,20) as u16, 1, 0, 9);
|
||||
let dz = scale * fix16(p.bits(20,30) as u16, 1, 0, 9);
|
||||
let v = self.vertex + vec3(dx, dy, dz);
|
||||
self.push_vertex(sink, v);
|
||||
}
|
||||
0x22 => {
|
||||
// TEXCOORD - Set Texture Coordinates
|
||||
let p = params.get(0);
|
||||
let s = fix16(p.bits(0,16) as u16, 1, 11, 4);
|
||||
let t = fix16(p.bits(16,32) as u16, 1, 11, 4);
|
||||
let tc = self.texture_mat * vec4(s,t,0.0,0.0);
|
||||
let texcoord = Point2::new(tc.x, tc.y);
|
||||
sink.texcoord(texcoord);
|
||||
}
|
||||
0x20 => {
|
||||
let p = params.get(0);
|
||||
let r = p.bits(0,5) as f32 / 31.0;
|
||||
let g = p.bits(5,10) as f32 / 31.0;
|
||||
let b = p.bits(10,15) as f32 / 31.0;
|
||||
let color = Point3::new(r,g,b);
|
||||
sink.color(color);
|
||||
}
|
||||
0x21 => {
|
||||
// normal
|
||||
}
|
||||
_ => { panic!("unknown opcode {:#x}", opcode); }
|
||||
}
|
||||
}
|
||||
|
||||
fn push_vertex<S: Sink>(&mut self, sink: &mut S, vertex: Point3<f64>) {
|
||||
self.vertex = vertex;
|
||||
sink.vertex(self.cur_mat.transform_point(vertex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn gfx_cmd_size(opcode: u8) -> Result<usize> {
|
||||
static SIZES: [i8; 66] = [
|
||||
0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 1, 0, 1, 1, 1, 0,
|
||||
16, 12, 16, 12, 9, 3, 3, -1, -1, -1, 1,
|
||||
1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
-1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0,
|
||||
];
|
||||
let opcode = opcode as usize;
|
||||
if opcode >= SIZES.len() || SIZES[opcode] == -1 {
|
||||
return Err(format!("unknown geometry opcode: {:#x}", opcode).into());
|
||||
}
|
||||
Ok(SIZES[opcode] as usize)
|
||||
}
|
45
src/main.rs
Normal file
45
src/main.rs
Normal file
@ -0,0 +1,45 @@
|
||||
#![recursion_limit = "1024"] // for error_chain
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
extern crate cgmath;
|
||||
extern crate env_logger;
|
||||
#[macro_use]
|
||||
extern crate glium;
|
||||
extern crate time;
|
||||
|
||||
#[macro_use]
|
||||
mod errors;
|
||||
#[macro_use]
|
||||
mod util;
|
||||
mod nitro;
|
||||
mod gfx;
|
||||
mod viewer;
|
||||
mod geometry;
|
||||
mod render;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use util::cur::Cur;
|
||||
|
||||
fn main() {
|
||||
env_logger::init().unwrap();
|
||||
|
||||
let arg = std::env::args().nth(1).unwrap();
|
||||
let mut f = File::open(&arg).unwrap();
|
||||
let mut v: Vec<u8> = vec![];
|
||||
f.read_to_end(&mut v).unwrap();
|
||||
|
||||
let cur = Cur::new(&v[..]);
|
||||
let res = nitro::read_bmd(cur);
|
||||
|
||||
match res {
|
||||
Ok(bmd) => {
|
||||
let model = &bmd.mdl.models[0];
|
||||
viewer::viewer(model, &bmd.tex).unwrap();
|
||||
}
|
||||
Err(e) => error!("err {:#?}", e),
|
||||
}
|
||||
}
|
36
src/nitro/info_block.rs
Normal file
36
src/nitro/info_block.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use errors::Result;
|
||||
use std::fmt::Debug;
|
||||
use std::iter::Zip;
|
||||
use util::cur::Cur;
|
||||
use util::name::Name;
|
||||
use util::view::View;
|
||||
use util::view::Viewable;
|
||||
|
||||
pub type Iterator<'a, T> = Zip<View<'a, T>, View<'a, Name>>;
|
||||
|
||||
/// Returns an iterator over the offset/name pairs in an info block.
|
||||
pub fn read<T>(cur: Cur) -> Result<Iterator<T>> where
|
||||
T: Viewable + Debug
|
||||
{
|
||||
fields!(cur, info_block {
|
||||
dummy: u8,
|
||||
count: u8,
|
||||
header_size: u16,
|
||||
|
||||
unknown_subheader_size: u16,
|
||||
unknown_section_size: u16,
|
||||
unknown_constant: u32,
|
||||
unknown_data: [u32; count],
|
||||
|
||||
size_of_datum: u16,
|
||||
data_section_size: u16,
|
||||
data: [T; count],
|
||||
|
||||
names: [Name; count],
|
||||
});
|
||||
|
||||
check!(dummy == 0);
|
||||
check!(size_of_datum as usize == <T as Viewable>::size());
|
||||
|
||||
Ok(data.zip(names))
|
||||
}
|
46
src/nitro/mdl/mod.rs
Normal file
46
src/nitro/mdl/mod.rs
Normal file
@ -0,0 +1,46 @@
|
||||
mod model;
|
||||
mod xform;
|
||||
|
||||
use cgmath::Matrix4;
|
||||
use nitro::tex::TextureParameters;
|
||||
use util::cur::Cur;
|
||||
use util::name::Name;
|
||||
|
||||
pub use self::model::read_mdl;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mdl<'a> {
|
||||
pub models: Vec<Model<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Model<'a> {
|
||||
pub name: Name,
|
||||
pub materials: Vec<Material>,
|
||||
pub meshes: Vec<Mesh<'a>>,
|
||||
pub objects: Vec<Object>,
|
||||
pub render_cmds_cur: Cur<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Material {
|
||||
pub name: Name,
|
||||
pub texture_name: Option<Name>,
|
||||
pub palette_name: Option<Name>,
|
||||
pub params: TextureParameters,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub texture_mat: Matrix4<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mesh<'a> {
|
||||
pub name: Name,
|
||||
pub commands: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Object {
|
||||
pub name: Name,
|
||||
pub xform: Matrix4<f64>,
|
||||
}
|
229
src/nitro/mdl/model.rs
Normal file
229
src/nitro/mdl/model.rs
Normal file
@ -0,0 +1,229 @@
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::One;
|
||||
use errors::Result;
|
||||
use nitro::info_block;
|
||||
use nitro::mdl::Material;
|
||||
use nitro::mdl::Mdl;
|
||||
use nitro::mdl::Mesh;
|
||||
use nitro::mdl::Model;
|
||||
use nitro::mdl::Object;
|
||||
use nitro::mdl::xform;
|
||||
use nitro::tex::TextureParameters;
|
||||
use util::bits::BitField;
|
||||
use util::cur::Cur;
|
||||
use util::name::Name;
|
||||
|
||||
pub fn read_mdl(cur: Cur) -> Result<Mdl> {
|
||||
fields!(cur, MDL0 {
|
||||
stamp: [u8; 4],
|
||||
section_size: u32,
|
||||
end: Cur,
|
||||
});
|
||||
check!(stamp == b"MDL0");
|
||||
|
||||
let models = info_block::read::<u32>(end)?
|
||||
.map(|(off, name)| read_model((cur + off as usize)?, name))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
Ok(Mdl { models: models })
|
||||
}
|
||||
|
||||
fn read_model<'a>(cur: Cur<'a>, name: Name) -> Result<Model<'a>> {
|
||||
trace!("model: {}", name);
|
||||
fields!(cur, model {
|
||||
section_size: u32,
|
||||
render_cmds_off: u32,
|
||||
materials_off: u32,
|
||||
mesh_off: u32,
|
||||
unknown_off: u32,
|
||||
unknown1: [u8; 3],
|
||||
num_objects: u8,
|
||||
num_materials: u8,
|
||||
num_meshes: u8,
|
||||
unknown2: [u8; 2],
|
||||
scale: (fix32(1,19,12)),
|
||||
bounding_box_scale: (fix32(1,19,12)),
|
||||
num_verts: u16,
|
||||
num_surfs: u16,
|
||||
num_tris: u16,
|
||||
num_quads: u16,
|
||||
bounding_box_x_min: (fix16(1,3,12)),
|
||||
bounding_box_y_min: (fix16(1,3,12)),
|
||||
bounding_box_z_min: (fix16(1,3,12)),
|
||||
bounding_box_x_max: (fix16(1,3,12)),
|
||||
bounding_box_y_max: (fix16(1,3,12)),
|
||||
bounding_box_z_max: (fix16(1,3,12)),
|
||||
unknown3: [u8; 8],
|
||||
end: Cur,
|
||||
});
|
||||
|
||||
let render_cmds_cur = (cur + render_cmds_off as usize)?;
|
||||
let objects = read_objects(end)?;
|
||||
let materials = read_materials((cur + materials_off as usize)?)?;
|
||||
let meshes = read_meshes((cur + mesh_off as usize)?)?;
|
||||
|
||||
Ok(Model {
|
||||
name: name,
|
||||
materials: materials,
|
||||
meshes: meshes,
|
||||
objects: objects,
|
||||
render_cmds_cur: render_cmds_cur,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_meshes(cur: Cur) -> Result<Vec<Mesh>> {
|
||||
info_block::read::<u32>(cur)?
|
||||
.map(|(off, name)| read_mesh((cur + off as usize)?, name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn read_mesh(cur: Cur, name: Name) -> Result<Mesh> {
|
||||
trace!("mesh: {}", name);
|
||||
fields!(cur, mesh {
|
||||
dummy: u16,
|
||||
section_size: u16,
|
||||
unknown: u32,
|
||||
commands_off: u32,
|
||||
commands_len: u32,
|
||||
});
|
||||
check!(section_size == 16);
|
||||
check!(commands_len % 4 == 0);
|
||||
|
||||
let commands = (cur + commands_off as usize)?
|
||||
.next_n_u8s(commands_len as usize)?;
|
||||
|
||||
Ok(Mesh {
|
||||
name: name,
|
||||
commands: commands,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_materials(cur: Cur) -> Result<Vec<Material>> {
|
||||
fields!(cur, materials {
|
||||
texture_pairing_off: u16,
|
||||
palette_pairing_off: u16,
|
||||
end: Cur,
|
||||
});
|
||||
|
||||
let mut materials = info_block::read::<u32>(end)?
|
||||
.map(|(off, name)| read_material((cur + off as usize)?, name))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// Pair each texture with materials.
|
||||
let tex_cur = (cur + texture_pairing_off as usize)?;
|
||||
for ((off, num, _), name) in info_block::read::<(u16, u8, u8)>(tex_cur)? {
|
||||
trace!("texture pairing: {}", name);
|
||||
fields!((cur + off as usize)?, texture_pairings {
|
||||
material_ids: [u8; num],
|
||||
});
|
||||
for &mat_id in material_ids {
|
||||
materials[mat_id as usize].texture_name = Some(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Pair each palette with materials.
|
||||
let pal_cur = (cur + palette_pairing_off as usize)?;
|
||||
for ((off, num, _), name) in info_block::read::<(u16, u8, u8)>(pal_cur)? {
|
||||
trace!("palette pairing: {}", name);
|
||||
fields!((cur + off as usize)?, palette_pairings {
|
||||
material_ids: [u8; num],
|
||||
});
|
||||
for &mat_id in material_ids {
|
||||
materials[mat_id as usize].palette_name = Some(name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(materials)
|
||||
}
|
||||
|
||||
fn read_material(cur: Cur, name: Name) -> Result<Material> {
|
||||
trace!("material: {:?}", name);
|
||||
fields!(cur, material {
|
||||
dummy: u16,
|
||||
section_size: u16,
|
||||
dif_amb: u32,
|
||||
spe_emi: u32,
|
||||
polygon_attr: u32,
|
||||
unknown2: u32,
|
||||
params: u32,
|
||||
unknown3: [u32; 2],
|
||||
width: u16,
|
||||
height: u16,
|
||||
end: Cur,
|
||||
});
|
||||
|
||||
let params = TextureParameters(params);
|
||||
|
||||
let texture_mat = match params.texcoord_transform_mode() {
|
||||
0 => Matrix4::from_scale(1.0),
|
||||
1 => {
|
||||
// This is probably wrong. It might also be 8 fix16s.
|
||||
// But it handles the common case with a3=a4=2 for
|
||||
// mirrored textures.
|
||||
fields!(end, texcoord_matrix {
|
||||
a1: (fix32(1,19,12)), // always 1?
|
||||
a2: (fix32(1,19,12)), // always 1?
|
||||
a3: (fix32(1,19,12)),
|
||||
a4: (fix32(1,19,12)),
|
||||
});
|
||||
Matrix4::from_nonuniform_scale(a3, a4, 1.0)
|
||||
}
|
||||
2 | 3 => unimplemented!(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(Material {
|
||||
name: name,
|
||||
texture_name: None,
|
||||
palette_name: None,
|
||||
params: params,
|
||||
width: width,
|
||||
height: height,
|
||||
texture_mat: texture_mat,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_objects(cur: Cur) -> Result<Vec<Object>> {
|
||||
info_block::read::<u32>(cur)?
|
||||
.map(|(off, name)| read_object((cur + off as usize)?, name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn read_object(cur: Cur, name: Name) -> Result<Object> {
|
||||
trace!("object: {}", name);
|
||||
fields!(cur, object_transform {
|
||||
flags: u16,
|
||||
m0: (fix16(1,3,12)),
|
||||
end: Cur,
|
||||
});
|
||||
|
||||
let t = flags.bits(0,1);
|
||||
let r = flags.bits(1,2);
|
||||
let s = flags.bits(2,3);
|
||||
let p = flags.bits(3,4);
|
||||
|
||||
let mut cur = end;
|
||||
let mut xform = Matrix4::one();
|
||||
|
||||
if t == 0 {
|
||||
let translation = xform::read_translation(&mut cur)?;
|
||||
xform = translation;
|
||||
}
|
||||
if p == 1 {
|
||||
let rotation = xform::read_rotation(&mut cur, flags)?;
|
||||
xform = xform * rotation;
|
||||
}
|
||||
if p == 0 && r == 0 {
|
||||
let matrix = xform::read_matrix(&mut cur, m0)?;
|
||||
xform = xform * matrix;
|
||||
}
|
||||
if s == 0 {
|
||||
let scale = xform::read_scale(&mut cur)?;
|
||||
xform = xform * scale;
|
||||
}
|
||||
|
||||
Ok(Object {
|
||||
name: name,
|
||||
xform: xform,
|
||||
})
|
||||
}
|
141
src/nitro/mdl/xform.rs
Normal file
141
src/nitro/mdl/xform.rs
Normal file
@ -0,0 +1,141 @@
|
||||
use cgmath::Matrix;
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::vec3;
|
||||
use cgmath::Vector4;
|
||||
use errors::Result;
|
||||
use util::bits::BitField;
|
||||
use util::cur::Cur;
|
||||
|
||||
pub fn read_translation(cur: &mut Cur) -> Result<Matrix4<f64>> {
|
||||
fields!(*cur, tranlation {
|
||||
x: (fix32(1,19,12)),
|
||||
y: (fix32(1,19,12)),
|
||||
z: (fix32(1,19,12)),
|
||||
end: Cur,
|
||||
});
|
||||
*cur = end;
|
||||
Ok(Matrix4::from_translation(vec3(x, y, z)))
|
||||
}
|
||||
|
||||
pub fn read_rotation(cur: &mut Cur, flags: u16) -> Result<Matrix4<f64>> {
|
||||
fields!(*cur, rot {
|
||||
a: (fix16(1,3,12)),
|
||||
b: (fix16(1,3,12)),
|
||||
end: Cur,
|
||||
});
|
||||
*cur = end;
|
||||
let select = flags.bits(4,8);
|
||||
let neg = flags.bits(8,12);
|
||||
pivot_mat(select, neg, a, b)
|
||||
}
|
||||
|
||||
pub fn read_matrix(cur: &mut Cur, m0: f64) -> Result<Matrix4<f64>> {
|
||||
fields!(*cur, rot {
|
||||
m1: (fix16(1,3,12)),
|
||||
m2: (fix16(1,3,12)),
|
||||
m3: (fix16(1,3,12)),
|
||||
m4: (fix16(1,3,12)),
|
||||
m5: (fix16(1,3,12)),
|
||||
m6: (fix16(1,3,12)),
|
||||
m7: (fix16(1,3,12)),
|
||||
m8: (fix16(1,3,12)),
|
||||
end: Cur,
|
||||
});
|
||||
*cur = end;
|
||||
Ok(Matrix4::new(
|
||||
m0, m1, m2, 0.0,
|
||||
m3, m4, m5, 0.0,
|
||||
m6, m7, m8, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn read_scale(cur: &mut Cur) -> Result<Matrix4<f64>> {
|
||||
fields!(*cur, scale {
|
||||
sx: (fix32(1,19,12)),
|
||||
sy: (fix32(1,19,12)),
|
||||
sz: (fix32(1,19,12)),
|
||||
end: Cur,
|
||||
});
|
||||
*cur = end;
|
||||
Ok(Matrix4::from_nonuniform_scale(sx,sy,sz))
|
||||
}
|
||||
|
||||
fn pivot_mat(select: u16, neg: u16, a: f64, b: f64) -> Result<Matrix4<f64>> {
|
||||
if select > 9 {
|
||||
return Err(format!("unknown pivot select: {}", select).into());
|
||||
}
|
||||
|
||||
if select == 9 {
|
||||
// Does this actually happen?
|
||||
return Ok(Matrix4::new(
|
||||
-a, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
));
|
||||
}
|
||||
|
||||
let o = if neg.bits(0,1) == 0 { 1.0 } else { -1.0 };
|
||||
let c = if neg.bits(1,2) == 0 { b } else { -b };
|
||||
let d = if neg.bits(2,3) == 0 { a } else { -a };
|
||||
|
||||
// `select` chooses the result in the following way
|
||||
//
|
||||
// o.. .o. ..o
|
||||
// 0=.ac 3=a.c 6=ac.
|
||||
// .bd b.d bd.
|
||||
//
|
||||
// .ac a.c ac.
|
||||
// 1=o.. 4=.o. 7=..o
|
||||
// .bd b.d bd.
|
||||
//
|
||||
// .ac a.c ac.
|
||||
// 2=.bd 5=b.d 8=bd.
|
||||
// o.. .o. ..o
|
||||
//
|
||||
// Note that they are all permutations of the rows
|
||||
// and columns of the first matrix.
|
||||
let mat = Matrix4::new(
|
||||
o, 0.0, 0.0, 0.0,
|
||||
0.0, a, b, 0.0,
|
||||
0.0, c, d, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
);
|
||||
let pi_cols = match select / 3 {
|
||||
0 => pi(1,2,3,4),
|
||||
1 => pi(2,1,3,4),
|
||||
2 => pi(2,3,1,4),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let pi_rows = match select % 3 {
|
||||
0 => pi(1,2,3,4),
|
||||
1 => pi(2,1,3,4),
|
||||
2 => pi(2,3,1,4),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(pi_rows.transpose() * mat * pi_cols)
|
||||
}
|
||||
|
||||
/// The permutation matrix corresponding to the permutation of {1,2,3,4} sending
|
||||
/// 1 to a, 2 to b, etc.
|
||||
///
|
||||
/// The matrix is the image of the permutation regarded as a map {1,2,3,4} -> {1,2,3,4}
|
||||
/// under the free vector space functor. That is, it is the identity matrix with the
|
||||
/// columns permuted according to the given permutation.
|
||||
///
|
||||
/// The upshot is m * pi(...) permutes the columns of m and pi(...)^T * m permutes
|
||||
/// the rows.
|
||||
fn pi(a: usize, b: usize, c: usize, d: usize) -> Matrix4<f64> {
|
||||
assert_eq!(
|
||||
[1,2,3,4],
|
||||
{ let mut arr = [a,b,c,d]; arr.sort(); arr }
|
||||
);
|
||||
let basis = [
|
||||
Vector4::unit_x(),
|
||||
Vector4::unit_y(),
|
||||
Vector4::unit_z(),
|
||||
Vector4::unit_w(),
|
||||
];
|
||||
Matrix4::from_cols(basis[a-1], basis[b-1], basis[c-1], basis[d-1])
|
||||
}
|
43
src/nitro/mod.rs
Normal file
43
src/nitro/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
pub mod mdl;
|
||||
pub mod tex;
|
||||
mod info_block;
|
||||
|
||||
use nitro::mdl::Mdl;
|
||||
use nitro::mdl::read_mdl;
|
||||
use nitro::tex::Tex;
|
||||
use nitro::tex::read_tex;
|
||||
use util::cur::Cur;
|
||||
use errors::Result;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bmd<'a> {
|
||||
pub mdl: Mdl<'a>,
|
||||
pub tex: Tex<'a>,
|
||||
}
|
||||
|
||||
pub fn read_bmd(cur: Cur) -> Result<Bmd> {
|
||||
fields!(cur, BMD0 {
|
||||
stamp: [u8; 4],
|
||||
bom: u16,
|
||||
version: u16,
|
||||
file_size: u32,
|
||||
header_size: u16,
|
||||
num_sections: u16,
|
||||
section_offs: [u32; num_sections],
|
||||
});
|
||||
check!(stamp == b"BMD0");
|
||||
check!(bom == 0xfeff);
|
||||
check!(header_size == 16);
|
||||
check!(num_sections > 0);
|
||||
|
||||
let mdl_cur = (cur + section_offs.get(0) as usize)?;
|
||||
let tex_cur = (cur + section_offs.get(1) as usize)?;
|
||||
|
||||
let mdl = read_mdl(mdl_cur)?;
|
||||
let tex = read_tex(tex_cur)?;
|
||||
|
||||
Ok(Bmd {
|
||||
mdl: mdl,
|
||||
tex: tex,
|
||||
})
|
||||
}
|
235
src/nitro/tex/image.rs
Normal file
235
src/nitro/tex/image.rs
Normal file
@ -0,0 +1,235 @@
|
||||
use nitro::tex::PaletteInfo;
|
||||
use nitro::tex::Tex;
|
||||
use nitro::tex::TextureInfo;
|
||||
use errors::Result;
|
||||
use util::bits::BitField;
|
||||
use util::view::View;
|
||||
|
||||
pub fn gen_image(
|
||||
tex: &Tex,
|
||||
tex_info: &TextureInfo,
|
||||
pal_info: Option<&PaletteInfo>,
|
||||
) -> Result<Vec<u8>>
|
||||
{
|
||||
match tex_info.params.format() {
|
||||
2 | 3 | 4 | 1 | 6 => {
|
||||
match pal_info {
|
||||
Some(pal_info) => Ok(gen_palette_image(tex, tex_info, pal_info)),
|
||||
None => Err("texture with palette format was not paired with a palette".into()),
|
||||
}
|
||||
}
|
||||
5 => {
|
||||
match pal_info {
|
||||
Some(pal_info) => Ok(gen_compressed_image(tex, tex_info, pal_info)),
|
||||
None => Err("texture with palette format was not paired with a palette".into()),
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_palette_image(tex: &Tex, tex_info: &TextureInfo, pal_info: &PaletteInfo) -> Vec<u8>
|
||||
{
|
||||
let texture_off = tex_info.params.offset();
|
||||
let width = tex_info.params.width() as usize;
|
||||
let height = tex_info.params.height() as usize;
|
||||
let format = tex_info.params.format();
|
||||
let color0_is_transparent = tex_info.params.is_color0_transparent();
|
||||
let palette_off = pal_info.off;
|
||||
|
||||
let bpps = [0u8, 8, 2, 4, 8, 0, 8];
|
||||
let bpp = bpps[format as usize] as usize;
|
||||
|
||||
let palette_bytes = &tex.palette_data[palette_off ..];
|
||||
let palette: View<u16> = View::from_buf(palette_bytes);
|
||||
|
||||
let texture_size = width * height * bpp / 8;
|
||||
let texture = &tex.texture_data[texture_off .. texture_off + texture_size];
|
||||
|
||||
let mut pixels = vec![0u8; 4 * width * height]; // 4 bytes (RGBA) for every texel
|
||||
let mut i = 0;
|
||||
|
||||
match format {
|
||||
2 => {
|
||||
// 4-Color Palette Texture
|
||||
for &x in texture {
|
||||
for &v in &[x.bits(0,2), x.bits(2,4), x.bits(4,6), x.bits(6,8)] {
|
||||
let transparent = v == 0 && color0_is_transparent;
|
||||
write_pixel(&mut pixels, &mut i, rgb555a5(
|
||||
palette.get(v as usize),
|
||||
if transparent { 0 } else { 31 },
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
// 16-Color Palette Texture
|
||||
for &x in texture {
|
||||
for &v in &[x.bits(0,4), x.bits(4,8)] {
|
||||
let transparent = v == 0 && color0_is_transparent;
|
||||
write_pixel(&mut pixels, &mut i, rgb555a5(
|
||||
palette.get(v as usize),
|
||||
if transparent { 0 } else { 31 },
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
// 256-Color Palette Texture
|
||||
for &v in texture {
|
||||
let transparent = v == 0 && color0_is_transparent;
|
||||
write_pixel(&mut pixels, &mut i, rgb555a5(
|
||||
palette.get(v as usize),
|
||||
if transparent { 0 } else { 31 },
|
||||
));
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
// A3I5 Translucent Texture (3-bit Alpha, 5-bit Color Index)
|
||||
for &x in texture {
|
||||
write_pixel(&mut pixels, &mut i, rgb555a5(
|
||||
palette.get(x.bits(0,5) as usize),
|
||||
a3_to_a5(x.bits(5,8)),
|
||||
));
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
// A5I3 Translucent Texture (5-bit Alpha, 3-bit Color Index)
|
||||
for &x in texture {
|
||||
write_pixel(&mut pixels, &mut i, rgb555a5(
|
||||
palette.get(x.bits(0,3) as usize),
|
||||
x.bits(3,8),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
pixels
|
||||
}
|
||||
|
||||
pub fn gen_compressed_image(tex: &Tex, tex_info: &TextureInfo, pal_info: &PaletteInfo) -> Vec<u8> {
|
||||
let texture_off = tex_info.params.offset();
|
||||
let width = tex_info.params.width() as usize;
|
||||
let height = tex_info.params.height() as usize;
|
||||
let palette_off = pal_info.off;
|
||||
let num_blocks_x = width / 4;
|
||||
let palette: View<u16> = View::from_buf(&tex.palette_data[palette_off..]);
|
||||
let block_data: View<u32> = View::from_buf(&tex.compressed_texture_data[texture_off..]);
|
||||
let extra_data: View<u16> = View::from_buf(&tex.compressed_texture_extra_data[texture_off / 2..]);
|
||||
|
||||
let mut pixels = vec![0u8; 4*width*height];
|
||||
let mut i = 0;
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let idx = num_blocks_x * (y/4) + (x/4);
|
||||
let block = block_data.get(idx);
|
||||
let extra = extra_data.get(idx);
|
||||
|
||||
let texel_off = 2 * (4 * (y%4) + (x%4)) as u32;
|
||||
let texel = block.bits(texel_off, texel_off+2);
|
||||
|
||||
let pal_addr = (extra.bits(0,14) as usize) << 1;
|
||||
let colors = [
|
||||
rgb555a5(palette.get(pal_addr+0), 31),
|
||||
rgb555a5(palette.get(pal_addr+1), 31),
|
||||
rgb555a5(palette.get(pal_addr+2), 31),
|
||||
rgb555a5(palette.get(pal_addr+3), 31),
|
||||
];
|
||||
|
||||
let mode = extra.bits(14,16);
|
||||
|
||||
let color = match mode {
|
||||
0 => {
|
||||
match texel {
|
||||
0 => colors[0],
|
||||
1 => colors[1],
|
||||
2 => colors[2],
|
||||
3 => [0, 0, 0, 0],
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
match texel {
|
||||
0 => colors[0],
|
||||
1 => colors[1],
|
||||
2 => avg(colors[0], colors[1]),
|
||||
3 => [0, 0, 0, 0],
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
match texel {
|
||||
0 => colors[0],
|
||||
1 => colors[1],
|
||||
2 => colors[2],
|
||||
3 => colors[3],
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
match texel {
|
||||
0 => colors[0],
|
||||
1 => colors[1],
|
||||
2 => avg358(colors[1], colors[0]),
|
||||
3 => avg358(colors[0], colors[1]),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write_pixel(&mut pixels, &mut i, color);
|
||||
}
|
||||
}
|
||||
|
||||
pixels
|
||||
}
|
||||
|
||||
fn write_pixel(pixels: &mut [u8], i: &mut usize, pixel: [u8; 4]) {
|
||||
pixels[*i+0] = pixel[0];
|
||||
pixels[*i+1] = pixel[1];
|
||||
pixels[*i+2] = pixel[2];
|
||||
pixels[*i+3] = pixel[3];
|
||||
*i += 4;
|
||||
}
|
||||
|
||||
/// Converts RGB555 color and A5 alpha into RGBA8888.
|
||||
fn rgb555a5(rgb555: u16, a5: u8) -> [u8; 4] {
|
||||
let r5 = rgb555.bits(0,5) as u8;
|
||||
let g5 = rgb555.bits(5,10) as u8;
|
||||
let b5 = rgb555.bits(10,15) as u8;
|
||||
let r8 = extend_5bit_to_8bit(r5);
|
||||
let g8 = extend_5bit_to_8bit(g5);
|
||||
let b8 = extend_5bit_to_8bit(b5);
|
||||
let a8 = extend_5bit_to_8bit(a5);
|
||||
[r8, g8, b8, a8]
|
||||
}
|
||||
|
||||
fn a3_to_a5(x: u8) -> u8 {
|
||||
(x << 2) | (x >> 1)
|
||||
}
|
||||
|
||||
fn extend_5bit_to_8bit(x: u8) -> u8 {
|
||||
(x << 3) | (x >> 2)
|
||||
}
|
||||
|
||||
/// (c1 + c2) / 2
|
||||
fn avg(c1: [u8; 4], c2: [u8; 4]) -> [u8; 4] {
|
||||
[
|
||||
((c1[0] as u32 + c2[0] as u32) / 2) as u8,
|
||||
((c1[1] as u32 + c2[1] as u32) / 2) as u8,
|
||||
((c1[2] as u32 + c2[2] as u32) / 2) as u8,
|
||||
((c1[3] as u32 + c2[3] as u32) / 2) as u8,
|
||||
]
|
||||
}
|
||||
|
||||
/// (3*c1 + 5*c2) / 8
|
||||
fn avg358(c1: [u8; 4], c2: [u8; 4]) -> [u8; 4] {
|
||||
[
|
||||
((3*c1[0] as u32 + 5*c2[0] as u32) / 8) as u8,
|
||||
((3*c1[1] as u32 + 5*c2[1] as u32) / 8) as u8,
|
||||
((3*c1[2] as u32 + 5*c2[2] as u32) / 8) as u8,
|
||||
((3*c1[3] as u32 + 5*c2[3] as u32) / 8) as u8,
|
||||
]
|
||||
}
|
45
src/nitro/tex/mod.rs
Normal file
45
src/nitro/tex/mod.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use util::bits::BitField;
|
||||
use util::name::Name;
|
||||
|
||||
pub mod image;
|
||||
mod texture;
|
||||
|
||||
pub use self::texture::read_tex;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Tex<'a> {
|
||||
pub texinfo: Vec<TextureInfo>,
|
||||
pub palinfo: Vec<PaletteInfo>,
|
||||
pub texture_data: &'a [u8],
|
||||
pub compressed_texture_data: &'a [u8],
|
||||
pub compressed_texture_extra_data: &'a [u8],
|
||||
pub palette_data: &'a [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TextureInfo {
|
||||
pub name: Name,
|
||||
pub params: TextureParameters,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PaletteInfo {
|
||||
pub name: Name,
|
||||
pub off: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TextureParameters(pub u32);
|
||||
|
||||
impl TextureParameters {
|
||||
pub fn offset(self) -> usize { (self.0.bits(0,16) as usize) << 3 }
|
||||
pub fn repeat_s(self) -> bool { self.0.bits(16,17) != 0 }
|
||||
pub fn repeat_t(self) -> bool { self.0.bits(17,18) != 0 }
|
||||
pub fn mirror_s(self) -> bool { self.0.bits(18,19) != 0 }
|
||||
pub fn mirror_t(self) -> bool { self.0.bits(19,20) != 0 }
|
||||
pub fn width(self) -> u32 { 8 << self.0.bits(20,23) }
|
||||
pub fn height(self) -> u32 { 8 << self.0.bits(23,26) }
|
||||
pub fn format(self) -> u32 { self.0.bits(26,29) }
|
||||
pub fn is_color0_transparent(self) -> bool { self.0.bits(29,30) != 0 }
|
||||
pub fn texcoord_transform_mode(self) -> u32 { self.0.bits(30,32) }
|
||||
}
|
81
src/nitro/tex/texture.rs
Normal file
81
src/nitro/tex/texture.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use errors::Result;
|
||||
use nitro::info_block;
|
||||
use nitro::tex::PaletteInfo;
|
||||
use nitro::tex::Tex;
|
||||
use nitro::tex::TextureInfo;
|
||||
use nitro::tex::TextureParameters;
|
||||
use util::cur::Cur;
|
||||
|
||||
pub fn read_tex(cur: Cur) -> Result<Tex> {
|
||||
fields!(cur, tex0 {
|
||||
stamp: [u8; 4],
|
||||
section_size: u32,
|
||||
padding: u32,
|
||||
texture_data_size_shr_3: u16,
|
||||
texture_info_off: u16,
|
||||
padding: u32,
|
||||
texture_data_off: u32,
|
||||
padding: u32,
|
||||
compressed_texture_data_size_shr_3: u16,
|
||||
compressed_texture_info_off: u16,
|
||||
padding: u32,
|
||||
compressed_texture_data_off: u32,
|
||||
compressed_texture_extra_off: u32,
|
||||
padding: u32,
|
||||
palette_data_size_shr_3: u16,
|
||||
unknown: u16,
|
||||
palette_info_off: u32,
|
||||
palette_data_off: u32,
|
||||
});
|
||||
check!(stamp == &b"TEX0"[..]);
|
||||
|
||||
let texture_data_size = (texture_data_size_shr_3 as usize) << 3;
|
||||
let compressed_texture_data_size = (compressed_texture_data_size_shr_3 as usize) << 3;
|
||||
let compressed_texture_extra_size = compressed_texture_data_size / 2;
|
||||
let palette_data_size = (palette_data_size_shr_3 as usize) << 3;
|
||||
|
||||
let texinfo = read_tex_info((cur + texture_info_off as usize)?)?;
|
||||
let palinfo = read_pal_info((cur + palette_info_off as usize)?)?;
|
||||
|
||||
let texture_data = (cur + texture_data_off as usize)?
|
||||
.next_n_u8s(texture_data_size)?;
|
||||
let compressed_texture_data = (cur + compressed_texture_data_off as usize)?
|
||||
.next_n_u8s(compressed_texture_data_size)?;
|
||||
let compressed_texture_extra_data = (cur + compressed_texture_extra_off as usize)?
|
||||
.next_n_u8s(compressed_texture_extra_size)?;
|
||||
let palette_data = (cur + palette_data_off as usize)?
|
||||
.next_n_u8s(palette_data_size)?;
|
||||
|
||||
Ok(Tex {
|
||||
texinfo: texinfo,
|
||||
palinfo: palinfo,
|
||||
texture_data: texture_data,
|
||||
compressed_texture_data: compressed_texture_data,
|
||||
compressed_texture_extra_data: compressed_texture_extra_data,
|
||||
palette_data: palette_data,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_pal_info(cur: Cur) -> Result<Vec<PaletteInfo>> {
|
||||
Ok(info_block::read::<(u16, u16)>(cur)?
|
||||
.map(|((off_shr_3, _), name)| {
|
||||
PaletteInfo {
|
||||
name: name,
|
||||
off: (off_shr_3 as usize) << 3,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
fn read_tex_info(cur: Cur) -> Result<Vec<TextureInfo>> {
|
||||
Ok(info_block::read::<(u32, u32)>(cur)?
|
||||
.map(|((params, _), name)| {
|
||||
TextureInfo {
|
||||
name: name,
|
||||
params: TextureParameters(params),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
)
|
||||
}
|
107
src/render.rs
Normal file
107
src/render.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use errors::Result;
|
||||
use gfx::GfxState;
|
||||
use nitro::mdl::Object;
|
||||
use util::cur::Cur;
|
||||
|
||||
pub trait Sink {
|
||||
fn draw(&mut self, gs: &mut GfxState, mesh_id: u8, material_id: u8) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct Renderer {
|
||||
pub gfx_state: GfxState,
|
||||
pub cur_material: u8,
|
||||
pub cur_stack_ptr: u8,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new() -> Renderer {
|
||||
Renderer {
|
||||
gfx_state: GfxState::new(),
|
||||
cur_material: 0,
|
||||
cur_stack_ptr: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_render_cmds<S: Sink>(&mut self, sink: &mut S, objects: &[Object], mut cur: Cur) -> Result<()> {
|
||||
loop {
|
||||
let opcode = cur.next::<u8>()?;
|
||||
let num_params = cmd_size(opcode, cur)?;
|
||||
let params = cur.next_n_u8s(num_params)?;
|
||||
trace!("{:#2x} {:?}", opcode, params);
|
||||
match opcode {
|
||||
0x00 => { /* NOP */ }
|
||||
0x01 => { return Ok(()) }
|
||||
0x02 => {
|
||||
// unknown
|
||||
}
|
||||
0x03 => {
|
||||
self.gfx_state.restore(params[0] as u32);
|
||||
}
|
||||
0x04 | 0x24 | 0x44 => {
|
||||
self.cur_material = params[0];
|
||||
}
|
||||
0x05 => {
|
||||
sink.draw(&mut self.gfx_state, params[0], self.cur_material)?;
|
||||
}
|
||||
0x06 | 0x26 | 0x46 | 0x66 => {
|
||||
let object_id = params[0];
|
||||
let _parent_id = params[1];
|
||||
let _dummy = params[2];
|
||||
let (stack_id, restore_id) = match opcode {
|
||||
0x06 => (None, None),
|
||||
0x26 => (Some(params[3]), None),
|
||||
0x46 => (None, Some(params[3])),
|
||||
0x66 => (Some(params[3]), Some(params[4])),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if let Some(restore_id) = restore_id {
|
||||
self.gfx_state.restore(restore_id as u32);
|
||||
}
|
||||
self.gfx_state.cur_mat = self.gfx_state.cur_mat * objects[object_id as usize].xform;
|
||||
if let Some(stack_id) = stack_id {
|
||||
self.cur_stack_ptr = stack_id;
|
||||
}
|
||||
self.gfx_state.mat_stack[self.cur_stack_ptr as usize] = self.gfx_state.cur_mat;
|
||||
self.cur_stack_ptr += 1;
|
||||
}
|
||||
0x09 => {
|
||||
// unknown
|
||||
}
|
||||
_ => {
|
||||
trace!("unknown render command: {:#x} {:?}", opcode, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_size(opcode: u8, cur: Cur) -> Result<usize> {
|
||||
let len = match opcode {
|
||||
0x00 => 0,
|
||||
0x01 => 0,
|
||||
0x02 => 2,
|
||||
0x03 => 1,
|
||||
0x04 => 1,
|
||||
0x05 => 1,
|
||||
0x06 => 3,
|
||||
0x07 => 1,
|
||||
0x08 => 1,
|
||||
0x09 => {
|
||||
// The only variable-length command.
|
||||
// 1 byte + 1 byte (count) + count u8[3]s
|
||||
2 + 3 * cur.clone().next_n_u8s(2)?[1] as usize
|
||||
}
|
||||
0x0b => 0,
|
||||
0x24 => 1,
|
||||
0x26 => 4,
|
||||
0x2b => 0,
|
||||
0x40 => 0,
|
||||
0x44 => 1,
|
||||
0x46 => 4,
|
||||
0x66 => 5,
|
||||
0x80 => 0,
|
||||
_ => return Err(format!("unknown render command opcode: {:#x}", opcode).into()),
|
||||
};
|
||||
Ok(len)
|
||||
}
|
20
src/util/bits.rs
Normal file
20
src/util/bits.rs
Normal file
@ -0,0 +1,20 @@
|
||||
pub trait BitField {
|
||||
fn bits(self, lo: u32, hi: u32) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! def_bitfield {
|
||||
($t:ty, $bitwidth:expr) => {
|
||||
impl BitField for $t {
|
||||
#[inline(always)]
|
||||
fn bits(self, lo: u32, hi: u32) -> $t {
|
||||
assert!(lo <= hi);
|
||||
assert!(hi <= $bitwidth);
|
||||
(self >> lo) & (!0 >> ($bitwidth - (hi - lo) as $t))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_bitfield!(u8, 8);
|
||||
def_bitfield!(u16, 16);
|
||||
def_bitfield!(u32, 32);
|
71
src/util/cur.rs
Normal file
71
src/util/cur.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use errors::Result;
|
||||
use std::fmt;
|
||||
use std::ops::Add;
|
||||
use util::view::{View, Viewable};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cur<'a> {
|
||||
buf_: &'a [u8],
|
||||
pos_: usize,
|
||||
}
|
||||
|
||||
impl<'a> Cur<'a> {
|
||||
pub fn new(buf: &[u8]) -> Cur {
|
||||
Cur { buf_: buf, pos_: 0 }
|
||||
}
|
||||
|
||||
pub fn pos(&self) -> usize {
|
||||
self.pos_
|
||||
}
|
||||
|
||||
pub fn next<T: Viewable>(&mut self) -> Result<T> {
|
||||
Ok(self.next_n::<T>(1)?.get(0))
|
||||
}
|
||||
|
||||
pub fn next_n<T: Viewable>(&mut self, n: usize) -> Result<View<'a, T>> {
|
||||
let size = <T as Viewable>::size();
|
||||
let buf = self.next_n_u8s(size * n)?;
|
||||
Ok(View::from_buf(buf))
|
||||
}
|
||||
|
||||
pub fn next_n_u8s(&mut self, n: usize) -> Result<&'a [u8]> {
|
||||
let end_pos = self.pos_ + n;
|
||||
if end_pos > self.buf_.len() {
|
||||
return Err("buffer was too short".into());
|
||||
}
|
||||
let res = &self.buf_[self.pos_ .. self.pos_ + n];
|
||||
self.pos_ += n;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn jump_forward(&mut self, amt: usize) -> Result<()> {
|
||||
let pos = self.pos_;
|
||||
self.jump_to(pos + amt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn jump_to(&mut self, pos: usize) -> Result<()> {
|
||||
if pos > self.buf_.len() {
|
||||
return Err("jumped past end".into());
|
||||
}
|
||||
self.pos_ = pos;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<usize> for Cur<'a> {
|
||||
type Output = Result<Cur<'a>>;
|
||||
|
||||
fn add(self, amt: usize) -> Result<Cur<'a>> {
|
||||
let mut cur = self;
|
||||
cur.jump_forward(amt)?;
|
||||
Ok(cur)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Cur<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Cur {{ pos: {} }}", self.pos())
|
||||
}
|
||||
}
|
||||
|
44
src/util/fields.rs
Normal file
44
src/util/fields.rs
Normal file
@ -0,0 +1,44 @@
|
||||
macro_rules! field_helper2 {
|
||||
($cur:ident, [u8; $n:expr]) => { $cur.next_n_u8s($n as usize)? };
|
||||
($cur:ident, [$t:ty; $n:expr]) => { $cur.next_n::<$t>($n as usize)? };
|
||||
($cur:ident, (fix16($s:expr,$i:expr,$f:expr))) => {
|
||||
{
|
||||
let x = $cur.next::<u16>()?;
|
||||
::util::fixed::fix16(x, $s, $i, $f)
|
||||
}
|
||||
};
|
||||
($cur:ident, (fix32($s:expr,$i:expr,$f:expr))) => {
|
||||
{
|
||||
let x = $cur.next::<u32>()?;
|
||||
::util::fixed::fix32(x, $s, $i, $f)
|
||||
}
|
||||
};
|
||||
($cur:ident, Cur) => { $cur.clone() };
|
||||
($cur:ident, $t:ty) => { $cur.next::<$t>()? };
|
||||
}
|
||||
|
||||
macro_rules! field_helper {
|
||||
($c:ident, $name:ident, $field:ident, Cur) => {
|
||||
let $field = field_helper2!($c, Cur);
|
||||
};
|
||||
($c:ident, $name:ident, $field:ident, $ty:tt) => {
|
||||
let pos = $c.pos();
|
||||
let $field = field_helper2!($c, $ty);
|
||||
trace!("{}.{}@{:#x}: {:?}",
|
||||
stringify!($name),
|
||||
stringify!($field),
|
||||
pos,
|
||||
$field,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! fields {
|
||||
($cur:expr, $name:ident { $($field:ident : $ty:tt,)* }) => {
|
||||
let mut c = $cur;
|
||||
$(field_helper!(c, $name, $field, $ty);)*
|
||||
};
|
||||
($cur:ident, $name:ident { $($field:ident : $ty:tt),* }) => {
|
||||
fields!($cur, $name { $($field : $ty,)* });
|
||||
};
|
||||
}
|
25
src/util/fixed.rs
Normal file
25
src/util/fixed.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use util::bits::BitField;
|
||||
|
||||
pub fn fix16(x: u16, sign_bits: u32, int_bits: u32, frac_bits: u32) -> f64 {
|
||||
assert!(sign_bits + int_bits + frac_bits <= 16);
|
||||
fix32(x as u32, sign_bits, int_bits, frac_bits)
|
||||
}
|
||||
|
||||
pub fn fix32(x: u32, sign_bits: u32, int_bits: u32, frac_bits: u32) -> f64 {
|
||||
assert!(sign_bits <= 1);
|
||||
assert!(int_bits + frac_bits > 0);
|
||||
assert!(sign_bits + int_bits + frac_bits <= 32);
|
||||
let x = x.bits(0, sign_bits + int_bits + frac_bits);
|
||||
let y = if sign_bits == 0 {
|
||||
x as f64
|
||||
} else {
|
||||
// sign extend
|
||||
let sign_mask = (1 << (int_bits + frac_bits)) as u32;
|
||||
if x & sign_mask != 0 {
|
||||
(x | !(sign_mask - 1)) as i32 as f64
|
||||
} else {
|
||||
x as f64
|
||||
}
|
||||
};
|
||||
y * 0.5f64.powi(frac_bits as i32)
|
||||
}
|
7
src/util/mod.rs
Normal file
7
src/util/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
pub mod bits;
|
||||
pub mod cur;
|
||||
#[macro_use]
|
||||
pub mod fields;
|
||||
pub mod fixed;
|
||||
pub mod name;
|
||||
pub mod view;
|
51
src/util/name.rs
Normal file
51
src/util/name.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use util::view::Viewable;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Name(pub [u8; 16]);
|
||||
|
||||
impl Name {
|
||||
pub fn from_bytes(buf: &[u8]) -> Name {
|
||||
let mut arr = [0; 16];
|
||||
for (i, &b) in buf.iter().enumerate() {
|
||||
arr[i] = b;
|
||||
}
|
||||
Name(arr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Viewable for Name {
|
||||
fn size() -> usize { 16 }
|
||||
fn view(buf: &[u8]) -> Name {
|
||||
Name::from_bytes(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for &b in trim_trailing_nul(&self.0[..]) {
|
||||
f.write_char(if b < 0x20 { '.' } else { b as char })?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_char('"')?;
|
||||
for &b in trim_trailing_nul(&self.0[..]) {
|
||||
for c in (b as char).escape_default() {
|
||||
f.write_char(c)?;
|
||||
}
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_trailing_nul(mut buf: &[u8]) -> &[u8] {
|
||||
while let Some((&0, rest)) = buf.split_last() {
|
||||
buf = rest;
|
||||
}
|
||||
buf
|
||||
}
|
136
src/util/view.rs
Normal file
136
src/util/view.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Formatter;
|
||||
use std::fmt::Write;
|
||||
use std::iter::Iterator;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Types that can be viewed as a fixed-length byte sequence.
|
||||
pub trait Viewable: Sized {
|
||||
fn size() -> usize;
|
||||
fn view(buf: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
impl Viewable for u8 {
|
||||
fn size() -> usize { 1 }
|
||||
fn view(buf: &[u8]) -> u8 { buf[0] }
|
||||
}
|
||||
|
||||
impl Viewable for u16 {
|
||||
fn size() -> usize { 2 }
|
||||
fn view(buf: &[u8]) -> u16 {
|
||||
buf[0] as u16 | (buf[1] as u16) << 8
|
||||
}
|
||||
}
|
||||
|
||||
impl Viewable for u32 {
|
||||
fn size() -> usize { 4 }
|
||||
fn view(buf: &[u8]) -> u32 {
|
||||
buf[0] as u32 | (buf[1] as u32) << 8 | (buf[2] as u32) << 16 | (buf[3] as u32) << 24
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,S> Viewable for (T,S) where
|
||||
T: Viewable,
|
||||
S: Viewable
|
||||
{
|
||||
fn size() -> usize { <T as Viewable>::size() + <S as Viewable>::size() }
|
||||
fn view(buf: &[u8]) -> (T,S) {
|
||||
let split = <T as Viewable>::size();
|
||||
let t = <T as Viewable>::view(&buf[..split]);
|
||||
let s = <S as Viewable>::view(&buf[split..]);
|
||||
(t,s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,S,P> Viewable for (T,S,P) where
|
||||
T: Viewable,
|
||||
S: Viewable,
|
||||
P: Viewable,
|
||||
{
|
||||
fn size() -> usize { <(T,(S,P)) as Viewable>::size() }
|
||||
fn view(buf: &[u8]) -> (T,S,P) {
|
||||
let (t,(s,p)) = <(T,(S,P)) as Viewable>::view(buf);
|
||||
(t,s,p)
|
||||
}
|
||||
}
|
||||
|
||||
/// An byte buffer interpreted as an array of Viewable elements.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct View<'a, T> {
|
||||
buf: &'a [u8],
|
||||
_marker: PhantomData<*const T>, // TODO: Is this the right type?
|
||||
}
|
||||
|
||||
impl<'a, T: Viewable> View<'a, T> {
|
||||
pub fn from_buf(buf: &[u8]) -> View<T> {
|
||||
let size = <T as Viewable>::size();
|
||||
assert!(size == 0 || buf.len() % size == 0);
|
||||
View { buf: buf, _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
let size = <T as Viewable>::size();
|
||||
self.buf.len() / size
|
||||
}
|
||||
|
||||
pub fn get(&self, pos: usize) -> T {
|
||||
let size = <T as Viewable>::size();
|
||||
let begin = size * pos;
|
||||
let end = begin + size;
|
||||
if end > self.buf.len() {
|
||||
panic!("index {} out of range for view of length {}", pos, self.buf.len());
|
||||
}
|
||||
let bytes = &self.buf[begin..end];
|
||||
<T as Viewable>::view(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Viewable + Debug> Debug for View<'a, T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "View [")?;
|
||||
if self.len() != 0 {
|
||||
write!(f, "{:?}", self.get(0))?;
|
||||
for i in 1..self.len() {
|
||||
write!(f, ", {:?}", self.get(i))?;
|
||||
}
|
||||
}
|
||||
f.write_char(']')
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Viewable> Iterator for View<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.buf.len() == 0 {
|
||||
None
|
||||
} else {
|
||||
let size = <T as Viewable>::size();
|
||||
let item = <T as Viewable>::view(&self.buf[0..size]);
|
||||
self.buf = &self.buf[size..];
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len();
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Viewable> DoubleEndedIterator for View<'a, T> {
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
if self.buf.len() == 0 {
|
||||
None
|
||||
} else {
|
||||
let size = <T as Viewable>::size();
|
||||
let idx = self.buf.len() - size;
|
||||
let item = <T as Viewable>::view(&self.buf[idx..]);
|
||||
self.buf = &self.buf[..idx];
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Viewable> ExactSizeIterator for View<'a, T> {}
|
308
src/viewer.rs
Normal file
308
src/viewer.rs
Normal file
@ -0,0 +1,308 @@
|
||||
use cgmath::EuclideanSpace;
|
||||
use cgmath::InnerSpace;
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::PerspectiveFov;
|
||||
use cgmath::Point3;
|
||||
use cgmath::Rad;
|
||||
use cgmath::Transform;
|
||||
use cgmath::vec3;
|
||||
use errors::Result;
|
||||
use geometry;
|
||||
use geometry::Vertex;
|
||||
use gfx::GfxState;
|
||||
use glium;
|
||||
use nitro::mdl::Model;
|
||||
use nitro::tex::image::gen_image;
|
||||
use nitro::tex::Tex;
|
||||
use render;
|
||||
use std::f32::consts::PI;
|
||||
use time;
|
||||
|
||||
implement_vertex!(Vertex, position, texcoord, color);
|
||||
|
||||
struct Sink<'a, 'b: 'a> {
|
||||
geosink: geometry::Sink,
|
||||
model: &'a Model<'b>,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> render::Sink for Sink<'a, 'b> {
|
||||
fn draw(&mut self, gs: &mut GfxState, mesh_id: u8, material_id: u8) -> Result<()> {
|
||||
let material = &self.model.materials[material_id as usize];
|
||||
gs.texture_mat = material.texture_mat;
|
||||
self.geosink.begin_mesh(material_id);
|
||||
self.geosink.cur_texture_dim = (material.width as u32, material.height as u32);
|
||||
gs.run_commands(&mut self.geosink, self.model.meshes[mesh_id as usize].commands)?;
|
||||
self.geosink.end_mesh();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct Eye {
|
||||
position: Point3<f32>,
|
||||
azimuth: f32,
|
||||
altitude: f32,
|
||||
}
|
||||
|
||||
struct MouseState {
|
||||
pos: (i32, i32),
|
||||
grabbed: GrabState,
|
||||
}
|
||||
|
||||
enum GrabState {
|
||||
NotGrabbed,
|
||||
Grabbed { saved_pos: (i32, i32) },
|
||||
}
|
||||
|
||||
pub fn viewer(model: &Model, tex: &Tex) -> Result<()> {
|
||||
use glium::{DisplayBuild, Surface};
|
||||
let display = glium::glutin::WindowBuilder::new()
|
||||
.with_dimensions(512,384)
|
||||
.with_depth_buffer(24)
|
||||
.build_glium()
|
||||
.unwrap();
|
||||
|
||||
let mut s = Sink {
|
||||
geosink: geometry::Sink::new(),
|
||||
model: model,
|
||||
};
|
||||
let mut r = render::Renderer::new();
|
||||
r.run_render_cmds(&mut s, &model.objects[..], model.render_cmds_cur)?;
|
||||
let geom = s.geosink.data;
|
||||
//println!("{:#?}", geom.vertices);
|
||||
let vertex_buffer = glium::VertexBuffer::new(
|
||||
&display,
|
||||
&geom.vertices
|
||||
).unwrap();
|
||||
let indices = glium::IndexBuffer::new(
|
||||
&display,
|
||||
glium::index::PrimitiveType::TrianglesList,
|
||||
&geom.indices
|
||||
).unwrap();
|
||||
|
||||
// Build textures
|
||||
let textures = model.materials.iter()
|
||||
.map(|material| {
|
||||
let palinfo = material.palette_name
|
||||
.and_then(|name| tex.palinfo.iter().find(|info| info.name == name));
|
||||
let texinfo = material.texture_name
|
||||
.and_then(|name| tex.texinfo.iter().find(|info| info.name == name));
|
||||
texinfo.map(|texinfo| {
|
||||
let rgba = gen_image(tex, texinfo, palinfo).unwrap();
|
||||
let dim = (texinfo.params.width(), texinfo.params.height());
|
||||
let image = glium::texture::RawImage2d::from_raw_rgba_reversed(rgba, dim);
|
||||
glium::texture::Texture2d::new(&display, image).unwrap()
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
// The default image is just a 1x1 white texture. Or it should be. For some reason
|
||||
// I don't understand, on the Windows box I'm testing on, 1x1 textures don't seem
|
||||
// to work. The work-around is just to make it 2x1. :(
|
||||
let default_image = glium::texture::RawImage2d::from_raw_rgba(
|
||||
vec![255u8,255,255,255,255u8,255,255,255],
|
||||
(2,1)
|
||||
);
|
||||
let default_texture = glium::texture::Texture2d::new(&display, default_image).unwrap();
|
||||
|
||||
let vertex_shader_src = r#"
|
||||
#version 140
|
||||
in vec3 position;
|
||||
in vec2 texcoord;
|
||||
in vec3 color;
|
||||
out vec2 v_texcoord;
|
||||
out vec3 v_color;
|
||||
uniform mat4 matrix;
|
||||
void main() {
|
||||
v_texcoord = texcoord;
|
||||
v_color = color;
|
||||
gl_Position = matrix * vec4(position, 1.0);
|
||||
}
|
||||
"#;
|
||||
|
||||
let fragment_shader_src = r#"
|
||||
#version 140
|
||||
in vec2 v_texcoord;
|
||||
in vec3 v_color;
|
||||
out vec4 color;
|
||||
uniform sampler2D tex;
|
||||
void main() {
|
||||
vec4 sample = texture(tex, v_texcoord);
|
||||
if (sample.w == 0.0) discard;
|
||||
color = sample * vec4(v_color, 1.0);
|
||||
}
|
||||
"#;
|
||||
|
||||
let program = glium::Program::new(&display,
|
||||
glium::program::ProgramCreationInput::SourceCode {
|
||||
vertex_shader: vertex_shader_src,
|
||||
fragment_shader: fragment_shader_src,
|
||||
geometry_shader: None,
|
||||
tessellation_control_shader: None,
|
||||
tessellation_evaluation_shader: None,
|
||||
transform_feedback_varyings: None,
|
||||
outputs_srgb: true,
|
||||
uses_point_size: false,
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
let mut eye = Eye {
|
||||
position: Point3::new(0.0, 0.0, 0.0),
|
||||
azimuth: 0.0,
|
||||
altitude: 0.0,
|
||||
};
|
||||
|
||||
let mut mouse = MouseState {
|
||||
pos: (0,0),
|
||||
grabbed: GrabState::NotGrabbed,
|
||||
};
|
||||
|
||||
let mut t = vec3(0.0, 0.0, 0.0);
|
||||
let mut last_time = time::precise_time_s() as f32;
|
||||
loop {
|
||||
let (w, h) = display.get_window().unwrap()
|
||||
.get_inner_size_pixels().unwrap();
|
||||
let (w,h) = (w as i32, h as i32);
|
||||
let asp = w as f32 / h as f32;
|
||||
|
||||
let mut target = display.draw();
|
||||
|
||||
let middle_grey = (0.4666, 0.4666, 0.4666, 1.0);
|
||||
target.clear_color_srgb_and_depth(middle_grey, 1.0);
|
||||
|
||||
let drawparams = glium::DrawParameters {
|
||||
depth: glium::Depth {
|
||||
test: glium::draw_parameters::DepthTest::IfLess,
|
||||
write: true,
|
||||
.. Default::default()
|
||||
},
|
||||
backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
|
||||
.. Default::default()
|
||||
};
|
||||
|
||||
let persp = PerspectiveFov {
|
||||
fovy: Rad(1.1),
|
||||
aspect: asp,
|
||||
near: 0.01,
|
||||
far: 100.0,
|
||||
};
|
||||
let mat =
|
||||
Matrix4::from(persp) *
|
||||
Matrix4::from_angle_x(Rad(-eye.altitude)) *
|
||||
Matrix4::from_angle_y(Rad(-eye.azimuth)) *
|
||||
Matrix4::from_translation(-eye.position.to_vec());
|
||||
|
||||
for range in geom.mesh_ranges.iter() {
|
||||
let tx = textures[range.mat_id as usize].as_ref()
|
||||
.unwrap_or(&default_texture);
|
||||
let mut sampler = glium::uniforms::Sampler::new(tx)
|
||||
.magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
|
||||
.minify_filter(glium::uniforms::MinifySamplerFilter::Nearest);
|
||||
let wrap_fn = |repeat, mirror| {
|
||||
use glium::uniforms::SamplerWrapFunction as Wrap;
|
||||
match (repeat, mirror) {
|
||||
(false, _) => Wrap::Clamp,
|
||||
(true, false) => Wrap::Repeat,
|
||||
(true, true) => Wrap::Mirror,
|
||||
}
|
||||
};
|
||||
let params = model.materials[range.mat_id as usize].params;
|
||||
sampler.1.wrap_function.0 = wrap_fn(params.repeat_s(), params.mirror_s());
|
||||
sampler.1.wrap_function.1 = wrap_fn(params.repeat_t(), params.mirror_t());
|
||||
|
||||
let uniforms = uniform! {
|
||||
matrix: [
|
||||
[mat.x.x, mat.x.y, mat.x.z, mat.x.w],
|
||||
[mat.y.x, mat.y.y, mat.y.z, mat.y.w],
|
||||
[mat.z.x, mat.z.y, mat.z.z, mat.z.w],
|
||||
[mat.w.x, mat.w.y, mat.w.z, mat.w.w],
|
||||
],
|
||||
tex: sampler,
|
||||
};
|
||||
target.draw(
|
||||
&vertex_buffer,
|
||||
&indices.slice(range.index_range.clone()).unwrap(),
|
||||
&program,
|
||||
&uniforms,
|
||||
&drawparams,
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
target.finish().unwrap();
|
||||
|
||||
let xform =
|
||||
Matrix4::from_angle_y(Rad(eye.azimuth));
|
||||
|
||||
let forward = xform.transform_vector(vec3(0.0, 0.0, -1.0));
|
||||
let side = xform.transform_vector(vec3(1.0, 0.0, 0.0));
|
||||
let up = xform.transform_vector(vec3(0.0, 1.0, 0.0));
|
||||
|
||||
for ev in display.poll_events() {
|
||||
use glium::glutin::Event as Ev;
|
||||
use glium::glutin::ElementState as State;
|
||||
use glium::glutin::VirtualKeyCode as Key;
|
||||
match ev {
|
||||
Ev::Closed => return Ok(()),
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::S)) => t.x = -1.0,
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::W)) => t.x = 1.0,
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::A)) => t.y = -1.0,
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::D)) => t.y = 1.0,
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::F)) => t.z = -1.0,
|
||||
Ev::KeyboardInput(State::Pressed, _, Some(Key::R)) => t.z = 1.0,
|
||||
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::S)) => t.x = 0.0,
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::W)) => t.x = 0.0,
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::A)) => t.y = 0.0,
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::D)) => t.y = 0.0,
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::F)) => t.z = 0.0,
|
||||
Ev::KeyboardInput(State::Released, _, Some(Key::R)) => t.z = 0.0,
|
||||
|
||||
Ev::MouseInput(State::Pressed, glium::glutin::MouseButton::Left) => {
|
||||
mouse.grabbed = GrabState::Grabbed { saved_pos: mouse.pos };
|
||||
display.get_window().unwrap().set_cursor_position(w/2, h/2);
|
||||
display.get_window().unwrap().set_cursor_state(glium::glutin::CursorState::Hide)?;
|
||||
}
|
||||
Ev::MouseInput(State::Released, glium::glutin::MouseButton::Left) => {
|
||||
if let GrabState::Grabbed { saved_pos } = mouse.grabbed {
|
||||
display.get_window().unwrap().set_cursor_state(glium::glutin::CursorState::Normal)?;
|
||||
display.get_window().unwrap().set_cursor_position(saved_pos.0, saved_pos.1);
|
||||
}
|
||||
mouse.grabbed = GrabState::NotGrabbed;
|
||||
}
|
||||
Ev::Focused(false) => {
|
||||
display.get_window().unwrap().set_cursor_state(glium::glutin::CursorState::Normal)?;
|
||||
mouse.grabbed = GrabState::NotGrabbed;
|
||||
t = vec3(0.0, 0.0, 0.0);
|
||||
}
|
||||
Ev::MouseMoved(x,y) => {
|
||||
mouse.pos = (x,y);
|
||||
if let GrabState::Grabbed { .. } = mouse.grabbed {
|
||||
let (dx, dy) = (x - w/2, y - h/2);
|
||||
eye.azimuth -= 0.01 * dx as f32;
|
||||
eye.altitude -= 0.01 * dy as f32;
|
||||
if eye.azimuth >= 2.0 * PI {
|
||||
eye.azimuth -= 2.0*PI;
|
||||
} else if eye.azimuth < 0.0 {
|
||||
eye.azimuth += 2.0*PI;
|
||||
}
|
||||
if eye.altitude > 0.498*PI {
|
||||
eye.altitude = 0.498*PI;
|
||||
}
|
||||
if eye.altitude < -0.498*PI {
|
||||
eye.altitude = -0.498*PI;
|
||||
}
|
||||
display.get_window().unwrap().set_cursor_position(w/2, h/2);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
let cur_time = time::precise_time_s() as f32;
|
||||
let dt = cur_time - last_time;
|
||||
last_time = cur_time;
|
||||
|
||||
let mag = t.magnitude();
|
||||
if mag != 0.0 {
|
||||
let tt = t / mag;
|
||||
eye.position += &(&forward * tt.x + &side * tt.y + &up * tt.z) * dt;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user