It works! Commit it

This commit is contained in:
scurest 2016-12-11 15:14:07 -06:00
commit a9295e7d37
24 changed files with 2763 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target

728
Cargo.lock generated Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}
}
}