Compare commits
No commits in common. "ab2e366e7f1cc13218547e6ee5e5ec4244e67b72" and "e89c1e4c3da1ceae3556cd99836d6d477c3c1383" have entirely different histories.
ab2e366e7f
...
e89c1e4c3d
|
|
@ -1,5 +1,4 @@
|
||||||
/target
|
/target
|
||||||
/proptest-regressions
|
|
||||||
*~
|
*~
|
||||||
\#*#
|
\#*#
|
||||||
.#*
|
.#*
|
||||||
|
|
@ -176,30 +176,15 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit-set"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
|
||||||
dependencies = [
|
|
||||||
"bit-vec 0.6.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec 0.8.0",
|
"bit-vec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit-vec"
|
|
||||||
version = "0.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|
@ -259,12 +244,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
|
@ -523,12 +502,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.34"
|
version = "1.0.34"
|
||||||
|
|
@ -539,12 +512,6 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
@ -884,12 +851,6 @@ version = "3.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.162"
|
version = "0.2.162"
|
||||||
|
|
@ -906,12 +867,6 @@ dependencies = [
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libm"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
|
@ -1016,7 +971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e"
|
checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set 0.8.0",
|
"bit-set",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
|
|
@ -1069,16 +1024,6 @@ dependencies = [
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"libm",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|
@ -1424,15 +1369,6 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "presser"
|
name = "presser"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -1463,26 +1399,6 @@ version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proptest"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d"
|
|
||||||
dependencies = [
|
|
||||||
"bit-set 0.5.3",
|
|
||||||
"bit-vec 0.6.3",
|
|
||||||
"bitflags 2.6.0",
|
|
||||||
"lazy_static",
|
|
||||||
"num-traits",
|
|
||||||
"rand",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_xorshift",
|
|
||||||
"regex-syntax",
|
|
||||||
"rusty-fork",
|
|
||||||
"tempfile",
|
|
||||||
"unarray",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pteropus"
|
name = "pteropus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -1494,7 +1410,6 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"log",
|
"log",
|
||||||
"proptest",
|
|
||||||
"tiff",
|
"tiff",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
|
|
@ -1504,12 +1419,6 @@ dependencies = [
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-error"
|
|
||||||
version = "1.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.36.2"
|
version = "0.36.2"
|
||||||
|
|
@ -1528,45 +1437,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_xorshift"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "range-alloc"
|
name = "range-alloc"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
|
@ -1651,18 +1521,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rusty-fork"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
|
|
||||||
dependencies = [
|
|
||||||
"fnv",
|
|
||||||
"quick-error",
|
|
||||||
"tempfile",
|
|
||||||
"wait-timeout",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
|
@ -1813,19 +1671,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"fastrand",
|
|
||||||
"once_cell",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
@ -1930,12 +1775,6 @@ version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e"
|
checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unarray"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.13"
|
version = "1.0.13"
|
||||||
|
|
@ -1972,15 +1811,6 @@ version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wait-timeout"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
@ -2257,7 +2087,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e0c68e7b6322a03ee5b83fcd92caeac5c2a932f6457818179f4652ad2a9c065"
|
checksum = "0e0c68e7b6322a03ee5b83fcd92caeac5c2a932f6457818179f4652ad2a9c065"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-vec 0.8.0",
|
"bit-vec",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"document-features",
|
"document-features",
|
||||||
|
|
@ -2284,7 +2114,7 @@ dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"ash",
|
"ash",
|
||||||
"bit-set 0.8.0",
|
"bit-set",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block",
|
"block",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -2739,7 +2569,6 @@ version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ web-sys = { version = "0.3", features = [
|
||||||
"Element",
|
"Element",
|
||||||
]}
|
]}
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
proptest = "1.5.0"
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.34"
|
wasm-bindgen-test = "0.3.34"
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::raster::Dem;
|
use super::raster::Dem;
|
||||||
use {
|
use {
|
||||||
bytemuck::{Pod, Zeroable},
|
bytemuck::{Pod, Zeroable},
|
||||||
std::{borrow::Cow, num::NonZero, rc::Rc},
|
std::{borrow::Cow, rc::Rc},
|
||||||
wgpu::util::DeviceExt,
|
wgpu::util::DeviceExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -12,8 +12,7 @@ pub struct DemRenderer {
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
index_buffer: wgpu::Buffer,
|
index_buffer: wgpu::Buffer,
|
||||||
index_count: usize,
|
index_count: usize,
|
||||||
camera: Camera,
|
uniforms: Uniforms,
|
||||||
uniforms: UniformBufferManager,
|
|
||||||
animation_start: std::time::Instant,
|
animation_start: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,36 +22,33 @@ struct Vertex {
|
||||||
position: [f32; 4],
|
position: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vertex {
|
struct Uniforms {
|
||||||
fn new(x: f32, y: f32, z: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
position: [x, y, z, 1.0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Camera {
|
|
||||||
projection_matrix: glam::Mat4,
|
projection_matrix: glam::Mat4,
|
||||||
view_matrix: glam::Mat4,
|
view_matrix: glam::Mat4,
|
||||||
|
buffer: wgpu::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera {
|
impl Uniforms {
|
||||||
fn new(viewport_aspect_ratio: f32) -> Self {
|
fn new(device: &wgpu::Device, aspect_ratio: f32) -> Self {
|
||||||
let projection_matrix = glam::Mat4::perspective_rh(
|
let projection_matrix =
|
||||||
std::f32::consts::FRAC_PI_4,
|
glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, aspect_ratio, 1.0, 10.0);
|
||||||
viewport_aspect_ratio,
|
|
||||||
1.0,
|
|
||||||
10000.0,
|
|
||||||
);
|
|
||||||
let view_matrix = glam::Mat4::look_at_rh(glam::Vec3::ZERO, glam::Vec3::ZERO, glam::Vec3::Z);
|
let view_matrix = glam::Mat4::look_at_rh(glam::Vec3::ZERO, glam::Vec3::ZERO, glam::Vec3::Z);
|
||||||
|
let camera_matrix = projection_matrix * view_matrix;
|
||||||
|
let camera_matrix_ref: &[f32; 16] = camera_matrix.as_ref();
|
||||||
|
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Uniform Buffer"),
|
||||||
|
contents: bytemuck::cast_slice(camera_matrix_ref),
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
Self {
|
Self {
|
||||||
projection_matrix,
|
projection_matrix,
|
||||||
view_matrix,
|
view_matrix,
|
||||||
|
buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&mut self, camera_position: glam::Vec3, camera_look_at: glam::Vec3) {
|
fn set_camera_position(&mut self, position: glam::Vec3) {
|
||||||
self.view_matrix = glam::Mat4::look_at_rh(camera_position, camera_look_at, glam::Vec3::Z);
|
self.view_matrix = glam::Mat4::look_at_rh(position, glam::Vec3::ZERO, glam::Vec3::Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_aspect_ratio(&mut self, ratio: f32) {
|
fn set_aspect_ratio(&mut self, ratio: f32) {
|
||||||
|
|
@ -60,63 +56,14 @@ impl Camera {
|
||||||
glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, ratio, 1.0, 10.0);
|
glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, ratio, 1.0, 10.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matrix(&self) -> glam::Mat4 {
|
|
||||||
self.projection_matrix * self.view_matrix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
|
||||||
struct UniformBufferContents {
|
|
||||||
camera_matrix: [f32; 16],
|
|
||||||
dem_texture_size: [u32; 2],
|
|
||||||
}
|
|
||||||
// This struct is 72 bytes but WGSL expects the buffer size to be be a multiple
|
|
||||||
// of the alignment of the member with the largest alignment. The mat4x4<f32>
|
|
||||||
// type has a 16-byte alignment, so we round up to 16 * 5 = 80.
|
|
||||||
const UNIFORM_BUFFER_SIZE: u64 = 80;
|
|
||||||
|
|
||||||
struct UniformBufferManager {
|
|
||||||
cpu_buffer: UniformBufferContents,
|
|
||||||
gpu_buffer: wgpu::Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UniformBufferManager {
|
|
||||||
fn new(device: &wgpu::Device) -> Self {
|
|
||||||
let cpu_buffer = UniformBufferContents::zeroed();
|
|
||||||
let gpu_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Uniform Buffer"),
|
|
||||||
contents: &[0u8; UNIFORM_BUFFER_SIZE as usize],
|
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
Self {
|
|
||||||
cpu_buffer,
|
|
||||||
gpu_buffer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_camera_matrix(&mut self, camera_matrix: glam::Mat4) {
|
|
||||||
self.cpu_buffer
|
|
||||||
.camera_matrix
|
|
||||||
.clone_from_slice(&camera_matrix.to_cols_array())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_dem_texture_size(&mut self, dem_texture_size: glam::UVec2) {
|
|
||||||
self.cpu_buffer
|
|
||||||
.dem_texture_size
|
|
||||||
.clone_from_slice(&dem_texture_size.to_array());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_binding(&self) -> wgpu::BindingResource<'_> {
|
|
||||||
wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
|
||||||
buffer: &self.gpu_buffer,
|
|
||||||
offset: 0,
|
|
||||||
size: NonZero::new(UNIFORM_BUFFER_SIZE),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_buffer(&self, queue: &wgpu::Queue) {
|
fn update_buffer(&self, queue: &wgpu::Queue) {
|
||||||
queue.write_buffer(&self.gpu_buffer, 0, bytemuck::bytes_of(&self.cpu_buffer));
|
let camera_matrix = self.projection_matrix * self.view_matrix;
|
||||||
|
let camera_matrix_ref: &[f32; 16] = camera_matrix.as_ref();
|
||||||
|
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(camera_matrix_ref))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binding(&self) -> wgpu::BindingResource<'_> {
|
||||||
|
self.buffer.as_entire_binding()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,9 +72,8 @@ impl DemRenderer {
|
||||||
source: Rc<Dem>,
|
source: Rc<Dem>,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
surface_config: &wgpu::SurfaceConfiguration,
|
surface_config: &wgpu::SurfaceConfiguration,
|
||||||
queue: &wgpu::Queue,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (vertex_data, index_data) = create_vertices(&source);
|
let (vertex_data, index_data) = create_vertices();
|
||||||
|
|
||||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("DemRenderer Vertex Buffer"),
|
label: Some("DemRenderer Vertex Buffer"),
|
||||||
|
|
@ -143,27 +89,25 @@ impl DemRenderer {
|
||||||
|
|
||||||
let index_count = index_data.len();
|
let index_count = index_data.len();
|
||||||
|
|
||||||
let (dem_texture_view, dem_texture_size) = load_dem_texture(&source, device, queue);
|
let uniforms = Uniforms::new(
|
||||||
|
device,
|
||||||
let camera = Camera::new(surface_config.width as f32 / surface_config.height as f32);
|
surface_config.width as f32 / surface_config.height as f32,
|
||||||
|
);
|
||||||
let mut uniforms = UniformBufferManager::new(device);
|
|
||||||
uniforms.set_dem_texture_size(dem_texture_size);
|
|
||||||
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
entries: &[
|
entries: &[
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
binding: 0,
|
binding: 0,
|
||||||
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
|
visibility: wgpu::ShaderStages::VERTEX,
|
||||||
ty: wgpu::BindingType::Buffer {
|
ty: wgpu::BindingType::Buffer {
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
has_dynamic_offset: false,
|
has_dynamic_offset: false,
|
||||||
min_binding_size: wgpu::BufferSize::new(UNIFORM_BUFFER_SIZE),
|
min_binding_size: wgpu::BufferSize::new(64),
|
||||||
},
|
},
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},
|
||||||
wgpu::BindGroupLayoutEntry {
|
/*wgpu::BindGroupLayoutEntry {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
ty: wgpu::BindingType::Texture {
|
ty: wgpu::BindingType::Texture {
|
||||||
|
|
@ -172,22 +116,16 @@ impl DemRenderer {
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
},
|
},
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},*/
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: &bind_group_layout,
|
layout: &bind_group_layout,
|
||||||
entries: &[
|
entries: &[wgpu::BindGroupEntry {
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
binding: 0,
|
||||||
resource: uniforms.get_binding(),
|
resource: uniforms.binding(),
|
||||||
},
|
}],
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: wgpu::BindingResource::TextureView(&dem_texture_view),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("DemRendererBindGroup"),
|
label: Some("DemRendererBindGroup"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -244,7 +182,6 @@ impl DemRenderer {
|
||||||
index_buffer,
|
index_buffer,
|
||||||
index_count,
|
index_count,
|
||||||
animation_start: std::time::Instant::now(),
|
animation_start: std::time::Instant::now(),
|
||||||
camera,
|
|
||||||
uniforms,
|
uniforms,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,14 +190,8 @@ impl DemRenderer {
|
||||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
label: Some("DemRendererCommandEncoder"),
|
label: Some("DemRendererCommandEncoder"),
|
||||||
});
|
});
|
||||||
self.camera.set_position(
|
self.uniforms
|
||||||
get_animated_camera_position(
|
.set_camera_position(get_animated_camera_position(self.animation_start.elapsed()));
|
||||||
self.animation_start.elapsed(),
|
|
||||||
self.get_max_dem_dimension(),
|
|
||||||
),
|
|
||||||
self.get_dem_centre(),
|
|
||||||
);
|
|
||||||
self.uniforms.set_camera_matrix(self.camera.get_matrix());
|
|
||||||
self.uniforms.update_buffer(queue);
|
self.uniforms.update_buffer(queue);
|
||||||
{
|
{
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
|
@ -285,61 +216,46 @@ impl DemRenderer {
|
||||||
}
|
}
|
||||||
queue.submit(Some(encoder.finish()));
|
queue.submit(Some(encoder.finish()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_max_dem_dimension(&self) -> f32 {
|
|
||||||
let dem = &self.source;
|
|
||||||
(dem.x_max - dem.x_min)
|
|
||||||
.max(dem.y_max - dem.y_min)
|
|
||||||
.max(dem.z_max - dem.x_min)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dem_centre(&self) -> glam::Vec3 {
|
fn vertex(pos: [i8; 3]) -> Vertex {
|
||||||
let dem = &self.source;
|
Vertex {
|
||||||
let min_corner = glam::Vec3::new(dem.x_min, dem.y_min, dem.z_min);
|
position: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
|
||||||
let max_corner = glam::Vec3::new(dem.x_max, dem.y_max, dem.z_max);
|
|
||||||
min_corner + (max_corner - min_corner) / 2.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_vertices(dem: &Rc<Dem>) -> (Vec<Vertex>, Vec<u16>) {
|
fn create_vertices() -> (Vec<Vertex>, Vec<u16>) {
|
||||||
let x_min = dem.x_min;
|
|
||||||
let x_max = dem.x_max;
|
|
||||||
let y_min = dem.y_min;
|
|
||||||
let y_max = dem.y_max;
|
|
||||||
let z_min = dem.z_min;
|
|
||||||
let z_max = dem.z_max;
|
|
||||||
|
|
||||||
let vertex_data = [
|
let vertex_data = [
|
||||||
// top (0, 0, 1)
|
// top (0, 0, 1)
|
||||||
Vertex::new(x_min, y_min, z_max),
|
vertex([-1, -1, 1]),
|
||||||
Vertex::new(x_max, y_min, z_max),
|
vertex([1, -1, 1]),
|
||||||
Vertex::new(x_max, y_max, z_max),
|
vertex([1, 1, 1]),
|
||||||
Vertex::new(x_min, y_max, z_max),
|
vertex([-1, 1, 1]),
|
||||||
// bottom (0, 0, -1)
|
// bottom (0, 0, -1)
|
||||||
Vertex::new(x_min, y_max, z_min),
|
vertex([-1, 1, -1]),
|
||||||
Vertex::new(x_max, y_max, z_min),
|
vertex([1, 1, -1]),
|
||||||
Vertex::new(x_max, y_min, z_min),
|
vertex([1, -1, -1]),
|
||||||
Vertex::new(x_min, y_min, z_min),
|
vertex([-1, -1, -1]),
|
||||||
// right (1, 0, 0)
|
// right (1, 0, 0)
|
||||||
Vertex::new(x_max, y_min, z_min),
|
vertex([1, -1, -1]),
|
||||||
Vertex::new(x_max, y_max, z_min),
|
vertex([1, 1, -1]),
|
||||||
Vertex::new(x_max, y_max, z_max),
|
vertex([1, 1, 1]),
|
||||||
Vertex::new(x_max, y_min, z_max),
|
vertex([1, -1, 1]),
|
||||||
// left (-1, 0, 0)
|
// left (-1, 0, 0)
|
||||||
Vertex::new(x_min, y_min, z_max),
|
vertex([-1, -1, 1]),
|
||||||
Vertex::new(x_min, y_max, z_max),
|
vertex([-1, 1, 1]),
|
||||||
Vertex::new(x_min, y_max, z_min),
|
vertex([-1, 1, -1]),
|
||||||
Vertex::new(x_min, y_min, z_min),
|
vertex([-1, -1, -1]),
|
||||||
// front (0, 1, 0)
|
// front (0, 1, 0)
|
||||||
Vertex::new(x_max, y_max, z_min),
|
vertex([1, 1, -1]),
|
||||||
Vertex::new(x_min, y_max, z_min),
|
vertex([-1, 1, -1]),
|
||||||
Vertex::new(x_min, y_max, z_max),
|
vertex([-1, 1, 1]),
|
||||||
Vertex::new(x_max, y_max, z_max),
|
vertex([1, 1, 1]),
|
||||||
// back (0, -1, 0)
|
// back (0, -1, 0)
|
||||||
Vertex::new(x_max, y_min, z_max),
|
vertex([1, -1, 1]),
|
||||||
Vertex::new(x_min, y_min, z_max),
|
vertex([-1, -1, 1]),
|
||||||
Vertex::new(x_min, y_min, z_min),
|
vertex([-1, -1, -1]),
|
||||||
Vertex::new(x_max, y_min, z_min),
|
vertex([1, -1, -1]),
|
||||||
];
|
];
|
||||||
|
|
||||||
let index_data: &[u16] = &[
|
let index_data: &[u16] = &[
|
||||||
|
|
@ -354,54 +270,11 @@ fn create_vertices(dem: &Rc<Dem>) -> (Vec<Vertex>, Vec<u16>) {
|
||||||
(vertex_data.to_vec(), index_data.to_vec())
|
(vertex_data.to_vec(), index_data.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_dem_texture(
|
fn get_animated_camera_position(animation_time: std::time::Duration) -> glam::Vec3 {
|
||||||
source: &Dem,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
) -> (wgpu::TextureView, glam::UVec2) {
|
|
||||||
let texture_size = wgpu::Extent3d {
|
|
||||||
width: source.num_cells_x,
|
|
||||||
height: source.num_cells_y,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
};
|
|
||||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
|
||||||
label: Some("Dem Texture"),
|
|
||||||
size: texture_size,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::R16Uint,
|
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
|
||||||
view_formats: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
queue.write_texture(
|
|
||||||
wgpu::ImageCopyTexture {
|
|
||||||
texture: &texture,
|
|
||||||
mip_level: 0,
|
|
||||||
origin: wgpu::Origin3d::ZERO,
|
|
||||||
aspect: wgpu::TextureAspect::All,
|
|
||||||
},
|
|
||||||
bytemuck::cast_slice(&source.grid[..]),
|
|
||||||
wgpu::ImageDataLayout {
|
|
||||||
offset: 0,
|
|
||||||
bytes_per_row: Some(std::mem::size_of::<u16>() as u32 * source.num_cells_x),
|
|
||||||
rows_per_image: Some(source.num_cells_y),
|
|
||||||
},
|
|
||||||
texture_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
|
||||||
texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
|
||||||
glam::UVec2::new(source.num_cells_x, source.num_cells_y),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_animated_camera_position(animation_time: std::time::Duration, dem_size: f32) -> glam::Vec3 {
|
|
||||||
let animation_phase = 2.0 * std::f32::consts::PI * (animation_time.as_secs_f32() % 10.0) / 10.0;
|
let animation_phase = 2.0 * std::f32::consts::PI * (animation_time.as_secs_f32() % 10.0) / 10.0;
|
||||||
glam::Vec3::new(
|
glam::Vec3::new(
|
||||||
dem_size * f32::sin(animation_phase),
|
5.0 * f32::sin(animation_phase),
|
||||||
dem_size * f32::cos(animation_phase),
|
5.0 * f32::cos(animation_phase),
|
||||||
dem_size * 0.7,
|
3.0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,21 @@
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
@location(0) test: vec2<f32>,
|
|
||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Uniforms {
|
@group(0)
|
||||||
transform: mat4x4<f32>,
|
@binding(0)
|
||||||
dem_texture_size: vec2<u32>
|
var<uniform> transform: mat4x4<f32>;
|
||||||
}
|
|
||||||
|
|
||||||
@group(0) @binding(0)
|
|
||||||
var<uniform> uniforms: Uniforms;
|
|
||||||
|
|
||||||
@group(0) @binding(1)
|
|
||||||
var dem_texture: texture_2d<u32>;
|
|
||||||
|
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
@location(0) position: vec4<f32>,
|
@location(0) position: vec4<f32>,
|
||||||
) -> VertexOutput {
|
) -> VertexOutput {
|
||||||
var result: VertexOutput;
|
var result: VertexOutput;
|
||||||
result.position = uniforms.transform * position;
|
result.position = transform * position;
|
||||||
result.test = position.xy;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_solid(vertex: VertexOutput) -> @location(0) vec4<f32> {
|
fn fs_solid(vertex: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
let texture_index = vec2<i32>(fract(abs(vertex.test)/500.0)*vec2<f32>(uniforms.dem_texture_size));
|
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||||
let v_i = textureLoad(dem_texture, texture_index, 0).r;
|
|
||||||
let v = f32(v_i) / 65535.0;
|
|
||||||
return vec4<f32>(v, v, 1.0, 1.0);
|
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +153,6 @@ impl MvuApp<Model> for App {
|
||||||
dem.clone(),
|
dem.clone(),
|
||||||
&context.device,
|
&context.device,
|
||||||
&context.config,
|
&context.config,
|
||||||
&context.queue,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,5 +199,5 @@ impl MvuApp<Model> for App {
|
||||||
|
|
||||||
fn open_test_file(file_path: PathBuf, model: Rc<Model>) -> Rc<Model> {
|
fn open_test_file(file_path: PathBuf, model: Rc<Model>) -> Rc<Model> {
|
||||||
let dem = Some(Rc::new(raster::Dem::load_from_image(&file_path)));
|
let dem = Some(Rc::new(raster::Dem::load_from_image(&file_path)));
|
||||||
Rc::new(Model { dem, ..*model })
|
Rc::new(Model { dem })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,159 +1,114 @@
|
||||||
use std::{fs::File, path::PathBuf};
|
use {
|
||||||
|
std::{fs::File, path::PathBuf},
|
||||||
|
tiff,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Dem {
|
pub struct Dem {
|
||||||
pub num_cells_x: u32,
|
pub width: u32,
|
||||||
pub num_cells_y: u32,
|
pub height: u32,
|
||||||
pub x_min: f32,
|
pub min_x: f32,
|
||||||
pub x_max: f32,
|
pub max_x: f32,
|
||||||
pub y_min: f32,
|
pub min_y: f32,
|
||||||
pub y_max: f32,
|
pub max_y: f32,
|
||||||
pub z_min: f32,
|
pub min_z: f32,
|
||||||
pub z_max: f32,
|
pub max_z: f32,
|
||||||
pub grid: Vec<u16>,
|
pub grid: Vec<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Dem {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Dem {{ dims: {} {}, x: {} {}, y: {} {}, z: {} {}, grid.len: {} }}",
|
|
||||||
self.num_cells_x,
|
|
||||||
self.num_cells_y,
|
|
||||||
self.x_min,
|
|
||||||
self.x_max,
|
|
||||||
self.y_min,
|
|
||||||
self.y_max,
|
|
||||||
self.z_min,
|
|
||||||
self.z_max,
|
|
||||||
self.grid.len()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dem {
|
impl Dem {
|
||||||
fn get(&self, i_x: u32, i_y: u32) -> u16 {
|
fn get(&self, x: u32, y: u32) -> u16 {
|
||||||
self.grid[(i_y * self.num_cells_x + i_x) as usize]
|
self.grid[(y * self.width + x) as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemBvh {
|
pub struct DemBvh {
|
||||||
|
pub dem: Dem,
|
||||||
pub layers: Vec<DemBvhLayer>,
|
pub layers: Vec<DemBvhLayer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemBvhLayer {
|
pub struct DemBvhLayer {
|
||||||
pub size: u32,
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
pub data: Vec<u16>,
|
pub data: Vec<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the smallest number that's larger then the input and that is also one
|
|
||||||
/// less than a power of two.
|
|
||||||
fn round_bound(v: u32) -> u32 {
|
|
||||||
let mut remaining = v;
|
|
||||||
let mut power_of_2 = 1;
|
|
||||||
while remaining > 0 {
|
|
||||||
remaining >>= 1;
|
|
||||||
power_of_2 <<= 1;
|
|
||||||
}
|
|
||||||
power_of_2 - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DemBvh {
|
impl DemBvh {
|
||||||
fn new(dem: &Dem) -> DemBvh {
|
fn new(dem: Dem) -> DemBvh {
|
||||||
let mut layers = vec![create_first_dembvh_layer(dem)];
|
assert!(dem.width == dem.height);
|
||||||
while layers.last().unwrap().size > 1 {
|
// width-1 must be power of two
|
||||||
layers.push(create_next_dembvh_layer(layers.last().unwrap()));
|
assert!(dem.width - 1 & (dem.width - 2) == 0);
|
||||||
|
let mut layers = vec![create_first_dembvh_layer(&dem)];
|
||||||
|
while layers.last().unwrap().width > 1 {
|
||||||
|
layers.push(create_next_dembvh_layer(&layers.last().unwrap()));
|
||||||
}
|
}
|
||||||
DemBvh { layers }
|
DemBvh { dem, layers }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DemBvhLayer {
|
impl DemBvhLayer {
|
||||||
fn get_value(&self, i_x: u32, i_y: u32) -> (u16, u16) {
|
fn get_value(&self, x: u32, y: u32) -> (u16, u16) {
|
||||||
(
|
(
|
||||||
self.data[((i_y * self.size + i_x) * 2) as usize],
|
self.data[(y * self.width * 2 + x * 2) as usize],
|
||||||
self.data[((i_y * self.size + i_x) * 2 + 1) as usize],
|
self.data[(y * self.width * 2 + x * 2 + 1) as usize],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_value(&mut self, i_x: u32, i_y: u32, min: u16, max: u16) {
|
fn set_value(&mut self, x: u32, y: u32, min: u16, max: u16) {
|
||||||
self.data[(i_y * self.size * 2 + i_x * 2) as usize] = min;
|
self.data[(y * self.width * 2 + x * 2) as usize] = min;
|
||||||
self.data[(i_y * self.size * 2 + i_x * 2 + 1) as usize] = max;
|
self.data[(y * self.width * 2 + x * 2 + 1) as usize] = max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If all the input values are zero, returns (0,0); otherwise ruturns a tuple
|
|
||||||
/// containing the minimum and maximum nonzero input values.
|
|
||||||
fn minmax_nonzero(a: u16, b: u16, c: u16, d: u16) -> (u16, u16) {
|
|
||||||
[a, b, c, d].into_iter().fold((0, 0), |(min, max), value| {
|
|
||||||
if value == 0 {
|
|
||||||
(min, max)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
if min == 0 { value } else { min.min(value) },
|
|
||||||
if max == 0 { value } else { max.max(value) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn minmax_nonzero_pairs(a: (u16, u16), b: (u16, u16), c: (u16, u16), d: (u16, u16)) -> (u16, u16) {
|
|
||||||
[a, b, c, d]
|
|
||||||
.into_iter()
|
|
||||||
.fold((0, 0), |(min, max), (elem_min, elem_max)| {
|
|
||||||
// If min is zero then max should be as well, and vice versa.
|
|
||||||
if elem_min == 0 {
|
|
||||||
(min, max)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
if min == 0 {
|
|
||||||
elem_min
|
|
||||||
} else {
|
|
||||||
min.min(elem_min)
|
|
||||||
},
|
|
||||||
max.max(elem_max),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_first_dembvh_layer(dem: &Dem) -> DemBvhLayer {
|
fn create_first_dembvh_layer(dem: &Dem) -> DemBvhLayer {
|
||||||
let size = round_bound(dem.num_cells_x.max(dem.num_cells_y));
|
let width = dem.width - 1;
|
||||||
|
let height = dem.height - 1;
|
||||||
let mut result = DemBvhLayer {
|
let mut result = DemBvhLayer {
|
||||||
size,
|
width,
|
||||||
data: vec![0; (size * size * 2) as usize],
|
height,
|
||||||
|
data: vec![0; (width * height * 2) as usize],
|
||||||
};
|
};
|
||||||
for i_y in 0..dem.num_cells_y - 1 {
|
for y in 0..height {
|
||||||
for i_x in 0..dem.num_cells_x - 1 {
|
for x in 0..width {
|
||||||
let (min, max) = minmax_nonzero(
|
let min = dem
|
||||||
dem.get(i_x, i_y),
|
.get(x, y)
|
||||||
dem.get(i_x + 1, i_y),
|
.min(dem.get(x + 1, y))
|
||||||
dem.get(i_x, i_y + 1),
|
.min(dem.get(x, y + 1))
|
||||||
dem.get(i_x + 1, i_y + 1),
|
.min(dem.get(x + 1, y + 1));
|
||||||
);
|
let max = dem
|
||||||
result.set_value(i_x, i_y, min, max);
|
.get(x, y)
|
||||||
|
.max(dem.get(x + 1, y))
|
||||||
|
.max(dem.get(x, y + 1))
|
||||||
|
.max(dem.get(x + 1, y + 1));
|
||||||
|
result.set_value(x, y, min, max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_next_dembvh_layer(prev: &DemBvhLayer) -> DemBvhLayer {
|
fn create_next_dembvh_layer(prev: &DemBvhLayer) -> DemBvhLayer {
|
||||||
let size = prev.size / 2;
|
let width = prev.width / 2;
|
||||||
|
let height = prev.height / 2;
|
||||||
let mut result = DemBvhLayer {
|
let mut result = DemBvhLayer {
|
||||||
size,
|
width,
|
||||||
data: vec![0; (size * size * 2) as usize],
|
height,
|
||||||
|
data: vec![0; (width * height * 2) as usize],
|
||||||
};
|
};
|
||||||
for i_y in 0..size {
|
for y in 0..height {
|
||||||
for i_x in 0..size {
|
for x in 0..width {
|
||||||
let prev_i_x = i_x * 2;
|
let min = prev
|
||||||
let prev_i_y = i_y * 2;
|
.get_value(x, y)
|
||||||
let (min, max) = minmax_nonzero_pairs(
|
.0
|
||||||
prev.get_value(prev_i_x, prev_i_y),
|
.min(prev.get_value(x + 1, y).0)
|
||||||
prev.get_value(prev_i_x + 1, prev_i_y),
|
.min(prev.get_value(x, y + 1).0)
|
||||||
prev.get_value(prev_i_x, prev_i_y + 1),
|
.min(prev.get_value(x + 1, y + 1).0);
|
||||||
prev.get_value(prev_i_x + 1, prev_i_y + 1),
|
let max = prev
|
||||||
);
|
.get_value(x, y)
|
||||||
result.set_value(i_x, i_y, min, max);
|
.1
|
||||||
|
.max(prev.get_value(x + 1, y).1)
|
||||||
|
.max(prev.get_value(x, y + 1).1)
|
||||||
|
.max(prev.get_value(x + 1, y + 1).1);
|
||||||
|
result.set_value(x, y, min, max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
|
@ -171,31 +126,31 @@ impl Dem {
|
||||||
pub fn load_from_image(file_path: &PathBuf) -> Dem {
|
pub fn load_from_image(file_path: &PathBuf) -> Dem {
|
||||||
let file = File::open(file_path).unwrap();
|
let file = File::open(file_path).unwrap();
|
||||||
let mut tiff = tiff::decoder::Decoder::new(file).unwrap();
|
let mut tiff = tiff::decoder::Decoder::new(file).unwrap();
|
||||||
let (num_cells_x, num_cells_y) = tiff.dimensions().unwrap();
|
let (width, height) = tiff.dimensions().unwrap();
|
||||||
match tiff.read_image().unwrap() {
|
match tiff.read_image().unwrap() {
|
||||||
tiff::decoder::DecodingResult::F32(f32_values) => {
|
tiff::decoder::DecodingResult::F32(f32_values) => {
|
||||||
let x_min = -500.0;
|
let min_x = -500.0;
|
||||||
let x_max = 500.0;
|
let max_x = 500.0;
|
||||||
let y_min = -500.0;
|
let min_y = -500.0;
|
||||||
let y_max = 500.0;
|
let max_y = 500.0;
|
||||||
let (z_min, z_max) = f32_values[1..]
|
let (min_z, max_z) = f32_values[1..]
|
||||||
.iter()
|
.iter()
|
||||||
.fold((f32_values[0], f32_values[0]), |(min, max), elem| {
|
.fold((f32_values[0], f32_values[0]), |(min, max), elem| {
|
||||||
(min.min(*elem), max.max(*elem))
|
(min.min(*elem), max.max(*elem))
|
||||||
});
|
});
|
||||||
let grid = f32_values
|
let grid = f32_values
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| normalized_f32_to_u16(normalize_f32(*v, z_min, z_max)))
|
.map(|v| normalized_f32_to_u16(normalize_f32(*v, min_z, max_z)))
|
||||||
.collect();
|
.collect();
|
||||||
Dem {
|
Dem {
|
||||||
num_cells_x,
|
width,
|
||||||
num_cells_y,
|
height,
|
||||||
x_min,
|
min_x,
|
||||||
x_max,
|
max_x,
|
||||||
y_min,
|
min_y,
|
||||||
y_max,
|
max_y,
|
||||||
z_min,
|
min_z,
|
||||||
z_max,
|
max_z,
|
||||||
grid,
|
grid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,165 +160,3 @@ impl Dem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use proptest::prelude::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_round_bound() {
|
|
||||||
for input in 2..10000 {
|
|
||||||
let result = round_bound(input);
|
|
||||||
assert!(
|
|
||||||
if result < 2 {
|
|
||||||
result == 1
|
|
||||||
} else {
|
|
||||||
(result + 1) & result == 0
|
|
||||||
},
|
|
||||||
"Result must be one less than a power of two."
|
|
||||||
);
|
|
||||||
assert!(result >= input, "Result must be greater than input");
|
|
||||||
assert!(
|
|
||||||
result / 2 < input,
|
|
||||||
"Half of result must be smaller then input."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_minmax_nonzero() {
|
|
||||||
assert_eq!((0, 0), minmax_nonzero(0, 0, 0, 0));
|
|
||||||
assert_eq!((2, 2), minmax_nonzero(2, 0, 0, 0));
|
|
||||||
assert_eq!((2, 2), minmax_nonzero(0, 2, 0, 0));
|
|
||||||
assert_eq!((2, 2), minmax_nonzero(0, 0, 2, 0));
|
|
||||||
assert_eq!((2, 2), minmax_nonzero(0, 0, 0, 2));
|
|
||||||
assert_eq!((2, 3), minmax_nonzero(2, 3, 0, 0));
|
|
||||||
assert_eq!((2, 3), minmax_nonzero(2, 0, 3, 0));
|
|
||||||
assert_eq!((2, 3), minmax_nonzero(2, 0, 0, 3));
|
|
||||||
assert_eq!((2, 3), minmax_nonzero(0, 3, 2, 0));
|
|
||||||
assert_eq!((2, 3), minmax_nonzero(0, 3, 0, 2));
|
|
||||||
assert_eq!((2, 4), minmax_nonzero(2, 3, 4, 0));
|
|
||||||
assert_eq!((2, 4), minmax_nonzero(0, 4, 3, 2));
|
|
||||||
assert_eq!((5, 10), minmax_nonzero(6, 10, 5, 9));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arbitrary_u16_vec_from_length(length: u32) -> impl Strategy<Value = Vec<u16>> {
|
|
||||||
let mut result = vec![];
|
|
||||||
for _ in 1..=length {
|
|
||||||
result.push(any::<u16>());
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arbitrary_dem(max_size: u32) -> BoxedStrategy<Dem> {
|
|
||||||
(1..max_size, 1..max_size)
|
|
||||||
.prop_flat_map(|(num_cells_x, num_cells_y)| {
|
|
||||||
(
|
|
||||||
Just(num_cells_x),
|
|
||||||
Just(num_cells_y),
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
proptest::num::f32::NORMAL,
|
|
||||||
arbitrary_u16_vec_from_length(num_cells_x * num_cells_y),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.prop_map(
|
|
||||||
|(num_cells_x, num_cells_y, x1, x2, y1, y2, z1, z2, grid)| Dem {
|
|
||||||
num_cells_x,
|
|
||||||
num_cells_y,
|
|
||||||
x_min: x1.min(x2),
|
|
||||||
x_max: x1.max(x2),
|
|
||||||
y_min: y1.min(y2),
|
|
||||||
y_max: y1.max(y2),
|
|
||||||
z_min: z1.min(z2),
|
|
||||||
z_max: z1.max(z2),
|
|
||||||
grid,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
proptest! {
|
|
||||||
//#![proptest_config(ProptestConfig {cases: 30, .. ProptestConfig::default() })]
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dembvh_is_zero_outside_source_bounds(dem in arbitrary_dem(50)) {
|
|
||||||
let target = DemBvh::new(&dem);
|
|
||||||
assert!(target.layers.len() > 0);
|
|
||||||
let first_layer = target.layers.first().unwrap();
|
|
||||||
assert!(first_layer.size >= dem.num_cells_x-1);
|
|
||||||
assert!(first_layer.size >= dem.num_cells_y-1);
|
|
||||||
for i_y in dem.num_cells_y..first_layer.size {
|
|
||||||
for i_x in 0..dem.num_cells_x {
|
|
||||||
assert_eq!((0,0), first_layer.get_value(i_x, i_y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i_y in 0..dem.num_cells_y {
|
|
||||||
for i_x in dem.num_cells_x..first_layer.size {
|
|
||||||
assert_eq!((0,0), first_layer.get_value(i_x, i_y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i_y in dem.num_cells_y..first_layer.size {
|
|
||||||
for i_x in dem.num_cells_x..first_layer.size {
|
|
||||||
assert_eq!((0,0), first_layer.get_value(i_x, i_y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dembvh_first_layer_has_correct_values(dem in arbitrary_dem(50)) {
|
|
||||||
let target = DemBvh::new(&dem);
|
|
||||||
assert!(target.layers.len() > 0);
|
|
||||||
let first_layer = target.layers.first().unwrap();
|
|
||||||
assert!(first_layer.size >= dem.num_cells_x-1);
|
|
||||||
assert!(first_layer.size >= dem.num_cells_y-1);
|
|
||||||
for i_y in 0..dem.num_cells_y-1 {
|
|
||||||
for i_x in 0..dem.num_cells_x-1 {
|
|
||||||
let corners:Vec<_> = [
|
|
||||||
dem.get(i_x, i_y),
|
|
||||||
dem.get(i_x, i_y+1),
|
|
||||||
dem.get(i_x+1, i_y),
|
|
||||||
dem.get(i_x+1, i_y+1)
|
|
||||||
].into_iter().filter(|v| *v!=0).collect();
|
|
||||||
let (found_min, found_max) = first_layer.get_value(i_x, i_y);
|
|
||||||
assert_eq!(corners.iter().min(), Some(&found_min));
|
|
||||||
assert_eq!(corners.iter().max(), Some(&found_max));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dembvh_check_rest_of_layers(dem in arbitrary_dem(50)) {
|
|
||||||
let target = DemBvh::new(&dem);
|
|
||||||
assert!(target.layers.first().unwrap().size >= dem.num_cells_x-1);
|
|
||||||
assert!(target.layers.first().unwrap().size >= dem.num_cells_y-1);
|
|
||||||
for (prev_layer, layer) in target.layers.iter().zip(target.layers.iter().skip(1)){
|
|
||||||
assert_eq!(layer.size, prev_layer.size/2);
|
|
||||||
for i_y in 0..layer.size {
|
|
||||||
for i_x in 0..layer.size {
|
|
||||||
let corners:Vec<_> = [
|
|
||||||
prev_layer.get_value(i_x * 2, i_y * 2),
|
|
||||||
prev_layer.get_value(i_x * 2, i_y * 2 + 1),
|
|
||||||
prev_layer.get_value(i_x * 2 + 1, i_y * 2),
|
|
||||||
prev_layer.get_value(i_x * 2 + 1, i_y * 2 + 1)
|
|
||||||
].into_iter().filter(|v| *v!=(0,0)).collect();
|
|
||||||
let corner_mins: Vec<_> = corners.iter().map(|&(min, _)| min).collect();
|
|
||||||
let corner_maxs: Vec<_> = corners.iter().map(|&(_, max)| max).collect();
|
|
||||||
let (found_min, found_max) = layer.get_value(i_x, i_y);
|
|
||||||
let found_min = if found_min == 0 { None } else { Some(&found_min) };
|
|
||||||
let found_max = if found_max == 0 { None } else { Some(&found_max) };
|
|
||||||
assert_eq!(corner_mins.iter().min(), found_min);
|
|
||||||
assert_eq!(corner_maxs.iter().max(), found_max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(1, target.layers.last().unwrap().size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,12 @@ mod native;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use native::run;
|
pub use native::run;
|
||||||
|
|
||||||
mod app;
|
|
||||||
mod mvu;
|
mod mvu;
|
||||||
|
mod app;
|
||||||
use app::{App,Model};
|
use app::{App,Model};
|
||||||
|
|
||||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
run(App::new(), Rc::new(Model::new()));
|
run(App::new(), Rc::new(Model::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ pub struct Size2i {
|
||||||
|
|
||||||
#[allow(async_fn_in_trait)]
|
#[allow(async_fn_in_trait)]
|
||||||
// https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#where-the-gaps-lie
|
// https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#where-the-gaps-lie
|
||||||
pub trait MvuApp<M> {
|
pub trait MvuApp<M>
|
||||||
|
{
|
||||||
async fn init(&mut self, instance: &Instance, surface: Surface<'static>, new_size: Size2i);
|
async fn init(&mut self, instance: &Instance, surface: Surface<'static>, new_size: Size2i);
|
||||||
async fn resize(&mut self, size: Size2i);
|
async fn resize(&mut self, size: Size2i);
|
||||||
async fn update(&self, model: Rc<M>, event: Event) -> Rc<M>;
|
async fn update(&self, model: Rc<M>, event: Event) -> Rc<M>;
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ where
|
||||||
block_on(self.app.init(&instance, surface, Size2i { width, height }));
|
block_on(self.app.init(&instance, surface, Size2i { width, height }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: The idea with these `block_on()` calls is that eventually I'll
|
// TODO: The idea with these `block_on()` calls is that eventually I'll
|
||||||
// write an async executor that runs on top of the winit even loop and then
|
// write an async executor that runs on top of the winit even loop and then
|
||||||
// this stuff can be properly async.
|
// this stuff can be properly async.
|
||||||
|
|
@ -61,7 +62,7 @@ where
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
block_on(self.app.view(self.model.clone())).unwrap();
|
block_on(self.app.view(self.model.clone())).unwrap();
|
||||||
self.window.as_ref().unwrap().request_redraw();
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
}
|
},
|
||||||
WindowEvent::DroppedFile(file_path) => {
|
WindowEvent::DroppedFile(file_path) => {
|
||||||
self.model = block_on(
|
self.model = block_on(
|
||||||
self.app
|
self.app
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue