From db89b19eb4ff13c492b5fba2ae27c0bfd43f08bf Mon Sep 17 00:00:00 2001 From: Tsuki Date: Thu, 18 Jul 2024 20:52:15 +0800 Subject: [PATCH] sync --- Cargo.lock | 443 +++++++++++++++++++++- Cargo.toml | 11 + shaders/agg-fast-path.frag | 4 +- shaders/agg-fast-path.vert | 4 +- shaders/colormap.glsl | 19 + shaders/hello.frag | 19 + shaders/hello.vert | 29 ++ shaders/ppi.frag | 32 ++ shaders/ppi.geom | 61 +++ shaders/ppi.vert | 8 + src/components/program.rs | 85 +++-- src/components/shader.rs | 51 ++- src/data_loader/error.rs | 14 + src/data_loader/mod.rs | 260 +++++++++++++ src/data_loader/parser.rs | 388 +++++++++++++++++++ src/errors.rs | 9 + src/final_pg.rs | 76 ++-- src/graphics/collections/agg_fast_path.rs | 206 +++++++--- src/graphics/colormap/linear.rs | 129 +++++++ src/graphics/colormap/mod.rs | 15 + src/graphics/hello.rs | 241 ++++++++++++ src/graphics/mod.rs | 18 +- src/graphics/ppi.rs | 251 ++++++++++++ src/graphics/transforms/mod.rs | 54 ++- src/graphics/transforms/polar.rs | 11 +- src/graphics/transforms/position.rs | 11 +- src/graphics/transforms/trackball.rs | 228 ++++++++++- src/graphics/transforms/viewport.rs | 71 +++- src/main.rs | 32 +- src/support/supporter.rs | 138 +++---- src/utils/geo_tools.rs | 17 + src/utils/mod.rs | 1 + src/utils/parser.rs | 412 +++++++++++++------- 33 files changed, 2919 insertions(+), 429 deletions(-) create mode 100644 shaders/colormap.glsl create mode 100644 shaders/hello.frag create mode 100644 shaders/hello.vert create mode 100644 shaders/ppi.frag create mode 100644 shaders/ppi.geom create mode 100644 shaders/ppi.vert create mode 100644 src/data_loader/error.rs create mode 100644 src/data_loader/mod.rs create mode 100644 src/data_loader/parser.rs create mode 100644 src/graphics/colormap/linear.rs create mode 100644 src/graphics/colormap/mod.rs create mode 100644 src/graphics/hello.rs create mode 100644 src/graphics/ppi.rs create mode 100644 src/utils/geo_tools.rs diff --git a/Cargo.lock b/Cargo.lock index 80097bf..c65155a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.8.11" @@ -40,6 +46,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d3b756e34402640015c5fec93cfdb93a4d22740996674392aa7ab8b996e8b4" +dependencies = [ + "equator", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-activity" version = "0.5.2" @@ -67,6 +88,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.14" @@ -116,6 +152,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "approx" version = "0.4.0" @@ -224,9 +266,15 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.6.0" @@ -313,6 +361,20 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1d389c4b5c60ebf7955904cd19f5a225f53f42e03d4459a2d57463ed62c6a8" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.5", +] + [[package]] name = "clipboard-win" version = "3.1.1" @@ -402,6 +464,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -435,6 +506,22 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "earcutr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" +dependencies = [ + "itertools", + "num-traits", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "env_filter" version = "0.1.0" @@ -458,6 +545,26 @@ dependencies = [ "log", ] +[[package]] +name = "equator" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -474,6 +581,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + [[package]] name = "foreign-types" version = "0.5.0" @@ -492,7 +615,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] [[package]] @@ -501,6 +624,44 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "geo" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f811f663912a69249fa620dcd2a005db7254529da2d8a0b23942e81f47084501" +dependencies = [ + "earcutr", + "float_next_after", + "geo-types", + "geographiclib-rs", + "log", + "num-traits", + "robust", + "rstar", + "spade", +] + +[[package]] +name = "geo-types" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" +dependencies = [ + "approx 0.5.1", + "num-traits", + "rstar", + "serde", +] + +[[package]] +name = "geographiclib-rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e5ed84f8089c70234b0a8e0aedb6dc733671612ddc0d37c6066052f9781960" +dependencies = [ + "libm", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -610,11 +771,34 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] [[package]] name = "hermit-abi" @@ -628,6 +812,29 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icrate" version = "0.0.4" @@ -720,6 +927,21 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "jni" version = "0.21.1" @@ -788,6 +1010,12 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.2" @@ -870,6 +1098,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + [[package]] name = "mint" version = "0.5.9" @@ -887,7 +1124,23 @@ dependencies = [ "num-complex", "num-rational", "num-traits", - "simba", + "simba 0.8.1", + "typenum", +] + +[[package]] +name = "nalgebra" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c4b5f057b303842cf3262c27e465f4c303572e7f6b0648f60e16248ac3397f4" +dependencies = [ + "approx 0.5.1", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba 0.9.0", "typenum", ] @@ -898,9 +1151,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e68879ff227a94627e63bbd518b4f82b8f0cc56bb01a498251507de6d1c412d6" dependencies = [ "approx 0.5.1", - "nalgebra", + "nalgebra 0.32.5", "num-traits", - "simba", + "simba 0.8.1", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", ] [[package]] @@ -944,6 +1221,38 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff943d68b88d0b87a6e0d58615e8fa07f9fd5a1319fa0a72efc1f62275c79a7" +dependencies = [ + "nom", + "nom-derive-impl", + "rustversion", +] + +[[package]] +name = "nom-derive-impl" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b9a93a84b0d3ec3e70e02d332dc33ac6dfac9cde63e17fcb77172dededa62" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -968,6 +1277,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ + "num-bigint", "num-integer", "num-traits", ] @@ -979,6 +1289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -999,7 +1310,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] [[package]] @@ -1179,10 +1490,16 @@ dependencies = [ name = "radar-g" version = "0.1.0" dependencies = [ + "aligned-vec", + "anyhow", "bytemuck", + "byteorder", "cgmath", + "chrono", "copypasta", "env_logger", + "flate2", + "geo", "glow", "glutin", "glutin-winit", @@ -1191,11 +1508,16 @@ dependencies = [ "imgui-winit-support", "include_dir", "log", + "nalgebra 0.33.0", "nalgebra-glm", + "ndarray", "nom", + "nom-derive", "once_cell", "raw-window-handle 0.5.2", "regex", + "serde", + "serde_json", "thiserror", "winit", ] @@ -1274,6 +1596,23 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "robust" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30" + +[[package]] +name = "rstar" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133315eb94c7b1e8d0cb097e5a710d850263372fd028fff18969de708afc7008" +dependencies = [ + "heapless", + "num-traits", + "smallvec", +] + [[package]] name = "rustix" version = "0.38.34" @@ -1287,6 +1626,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "safe_arch" version = "0.7.1" @@ -1332,22 +1683,33 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", ] [[package]] @@ -1363,6 +1725,19 @@ dependencies = [ "wide", ] +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx 0.5.1", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "slab" version = "0.4.9" @@ -1432,12 +1807,41 @@ dependencies = [ "serde", ] +[[package]] +name = "spade" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f4ec45f91925e2c9ab3b6a857ee9ed36916990df76a1c475d783a328e247cc8" +dependencies = [ + "hashbrown", + "num-traits", + "robust", + "smallvec", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.66" @@ -1466,7 +1870,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] [[package]] @@ -1600,7 +2004,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -1634,7 +2038,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1815,6 +2219,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -2168,5 +2581,5 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.66", ] diff --git a/Cargo.toml b/Cargo.toml index dc84542..4a59cbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,14 @@ thiserror = "1.0.61" log = "0.4.22" env_logger = "0.11.3" bytemuck = { version = "1.16.1", features = ["derive"] } +nalgebra = "0.33.0" +nom-derive = "0.10.1" +serde = { version = "1.0.204", features = ["derive"] } +byteorder = "1.5.0" +chrono = "0.4.38" +flate2 = "1.0.30" +anyhow = "1.0.86" +serde_json = "1.0.120" +geo = "0.28.0" +ndarray = "0.15.6" +aligned-vec = "0.6.0" diff --git a/shaders/agg-fast-path.frag b/shaders/agg-fast-path.frag index 4386958..ebfa685 100644 --- a/shaders/agg-fast-path.frag +++ b/shaders/agg-fast-path.frag @@ -11,6 +11,8 @@ in float v_distance; in float v_linewidth; in float v_antialias; +out vec4 FragColor; + // Main // ------------------------------------ void main() @@ -18,5 +20,5 @@ void main() ; if (v_color.a == 0) { discard; } - gl_FragColor = stroke(v_distance, v_linewidth, v_antialias, v_color); + FragColor = stroke(v_distance, v_linewidth, v_antialias, v_color); } \ No newline at end of file diff --git a/shaders/agg-fast-path.vert b/shaders/agg-fast-path.vert index dd703aa..9326a31 100644 --- a/shaders/agg-fast-path.vert +++ b/shaders/agg-fast-path.vert @@ -31,7 +31,9 @@ out vec4 v_color; void main () { // This function is externally generated - fetch_uniforms(); + // fetch_uniforms(); + + float id = gl_VertexID; v_linewidth = linewidth; v_antialias = antialias; v_color = color; diff --git a/shaders/colormap.glsl b/shaders/colormap.glsl new file mode 100644 index 0000000..73593eb --- /dev/null +++ b/shaders/colormap.glsl @@ -0,0 +1,19 @@ +uniform sampler1D colormap; +uniform vec4 conf; + +vec4 linear_colormap(float value) +{ + float vmin = conf.x; + float vmax = conf.y; + float count = conf.z - 1.0; + + float invalid = conf.w; + + if (value == invalid) { + return vec4(0.0, 0.0, 0.0, 0.0); + } + + float v = clamp((value - vmin), vmin, vmax) / (vmax - vmin); + vec4 result = texture(colormap, v); + return result; +} diff --git a/shaders/hello.frag b/shaders/hello.frag new file mode 100644 index 0000000..1695750 --- /dev/null +++ b/shaders/hello.frag @@ -0,0 +1,19 @@ +in vec2 vert; +in vec4 color; + +out vec4 frag_color; + +vec4 linear_to_srgb(vec4 linear_color) { + vec3 linear = linear_color.rgb; + vec3 selector = ceil(linear - 0.0031308); + vec3 less_than_branch = linear * 12.92; + vec3 greater_than_branch = pow(linear, vec3(1.0/2.4)) * 1.055 - 0.055; + return vec4( + mix(less_than_branch, greater_than_branch, selector), + linear_color.a + ); +} + +void main() { + frag_color = linear_to_srgb(color); +} \ No newline at end of file diff --git a/shaders/hello.vert b/shaders/hello.vert new file mode 100644 index 0000000..03311ef --- /dev/null +++ b/shaders/hello.vert @@ -0,0 +1,29 @@ +uniform mat4 projection; +uniform mat4 view; + +const vec2 verts[3] = vec2[3]( + vec2(0.5f, 1.0f), + vec2(0.0f, 0.0f), + vec2(1.0f, 0.0f) +); + +out vec2 vert; +out vec4 color; + +vec4 srgb_to_linear(vec4 srgb_color) { + // Calcuation as documented by OpenGL + vec3 srgb = srgb_color.rgb; + vec3 selector = ceil(srgb - 0.04045); + vec3 less_than_branch = srgb / 12.92; + vec3 greater_than_branch = pow((srgb + 0.055) / 1.055, vec3(2.4)); + return vec4( + mix(less_than_branch, greater_than_branch, selector), + srgb_color.a + ); +} + +void main() { + vert = verts[gl_VertexID]; + color = srgb_to_linear(vec4(vert, 0.5, 1.0)); + gl_Position = vec4(vert - 0.5, 0.0, 1.0); +} \ No newline at end of file diff --git a/shaders/ppi.frag b/shaders/ppi.frag new file mode 100644 index 0000000..3d44183 --- /dev/null +++ b/shaders/ppi.frag @@ -0,0 +1,32 @@ +#include "transform/polar.glsl" + +in float x; +in float y; + +in float value; +flat in vec4 vrange; + +out vec4 FragColor; + +void main() { + + vec4 inversed = inverse(x, y); + + + if (inversed.x < vrange.x || inversed.x > vrange.z) { + discard; + } + + vec4 result = ; + + if (result.w == 0.0) { + discard; + } + + // result = texture(colormap_2, 1.0); + + // vec4 result = vec4(value /10.0, value / 10.0, 1.0, value / 10.0); + + + FragColor = result; +} \ No newline at end of file diff --git a/shaders/ppi.geom b/shaders/ppi.geom new file mode 100644 index 0000000..d37cc1d --- /dev/null +++ b/shaders/ppi.geom @@ -0,0 +1,61 @@ +#include "transform/polar.glsl" + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +// conf: Range, Elevation, Resolution, 0.0 +uniform vec4 conf; +in float in_value[]; + +out float x; +out float y; +out float value; + +flat out vec4 vrange; + + +void main() { + vec4 reso = vec4(conf.x/2.0, conf.y/2.0 * radian, 0.0, 0.0); + vec4 loc; + float c = cos(reso.y); + + vec4 po = gl_in[0].gl_Position; + po.y = po.y * radian; + + vrange = vec4(po.x - reso.x, po.y - reso.y, po.x + reso.x, po.y + reso.y); + value = in_value[0]; + + gl_Position = po - reso; + loc = forward(gl_Position); + x = loc.x; + y = loc.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + vec4(reso.x, -reso.y, 0.0, 0.0); + gl_Position.x = gl_Position.x / c; + loc = forward(gl_Position); + x = loc.x; + y = loc.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + vec4(-reso.x, reso.y, 0.0, 0.0); + loc = forward(gl_Position); + x = loc.x; + y = loc.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + reso; + gl_Position.x = gl_Position.x / c; + loc = forward(gl_Position); + x = loc.x; + y = loc.y; + gl_Position = ; + EmitVertex(); + + EndPrimitive(); + +} + diff --git a/shaders/ppi.vert b/shaders/ppi.vert new file mode 100644 index 0000000..1cb4270 --- /dev/null +++ b/shaders/ppi.vert @@ -0,0 +1,8 @@ +// Layout +layout(location = 0) in vec3 position; +out float in_value; + +void main() { + gl_Position = vec4(position.x, position.y, 0.0, 1.0); + in_value = position.z; +} \ No newline at end of file diff --git a/src/components/program.rs b/src/components/program.rs index e926d4d..0e0f1f9 100644 --- a/src/components/program.rs +++ b/src/components/program.rs @@ -1,7 +1,8 @@ -use glow::HasContext; +use glow::{HasContext, NativeUniformLocation}; use super::shader::Shader; use super::snippets::{CodeType, Snippet}; +use crate::components::CodeComponent; use crate::graphics::transforms::{viewport::Viewport, Transform}; #[derive(Debug)] @@ -43,6 +44,7 @@ impl Program { pub fn set_hook(&mut self, hook: &str, code: &Snippet) { self.vertex.set_hook(hook, code); self.fragment.set_hook(hook, code); + self.geometry.as_mut().map(|g| g.set_hook(hook, code)); } pub fn set_transform(&mut self, value: &T) { @@ -55,25 +57,48 @@ impl Program { pub fn compile(&mut self, gl: &glow::Context) -> crate::errors::Result<()> { use crate::errors::Error; - unsafe { - // let vertex_array = gl - // .create_vertex_array() - // .expect("Cannot create vertex array"); + self.vertex.define("_GLUMPY__VERTEX_SHADER__"); + self.fragment.define("_GLUMPY__FRAGMENT_SHADER__"); + + unsafe { let program = gl.create_program().map_err(|e| Error::InvalidProgram(e))?; - let vertex_shader = - self.create_shader(gl, &self.vertex.to_string(),self.version, glow::VERTEX_SHADER); - let fragment_shader = - self.create_shader(gl, &self.fragment.to_string(),self.version, glow::FRAGMENT_SHADER); + let vertex_shader = self.vertex.compile(&self.version, gl); + let fragment_shader = self.fragment.compile(&self.version, gl); + + gl.attach_shader(program, vertex_shader); + gl.attach_shader(program, fragment_shader); + + // Geom Shader + let geom_shader = if let Some(geometry) = self.geometry.as_mut() { + geometry.define("_GLUMPY__GEOMETRY_SHADER__"); + let geometry_shader = geometry.compile(&self.version, gl); + + gl.attach_shader(program, geometry_shader); + + Some(geometry_shader) + } else { + None + }; gl.link_program(program); + if !gl.get_program_link_status(program) { return Err(Error::InvalidProgram(gl.get_program_info_log(program))); } gl.detach_shader(program, vertex_shader); gl.detach_shader(program, fragment_shader); + if let Some(_) = self.geometry.as_ref() { + gl.detach_shader(program, geom_shader.unwrap()); + gl.delete_shader(geom_shader.unwrap()); + } + + gl.delete_shader(vertex_shader); + gl.delete_shader(fragment_shader); + + gl.use_program(Some(program)); self.native_program = Some(program); } @@ -81,42 +106,24 @@ impl Program { Ok(()) } - fn create_shader( - &self, - gl: &glow::Context, - code: &str, - version: &'static str, - shader_type: u32, - ) -> ::Shader { - let shader = unsafe { - let shader = gl - .create_shader(glow::VERTEX_SHADER) - .expect("Cannot create shader"); - gl.shader_source( - shader, - &format!("{}\n{}", &format!("#version {}", self.version), code), - ); - gl.compile_shader(shader); - if !gl.get_shader_compile_status(shader) { - panic!("{}", gl.get_shader_info_log(shader)) - } - shader - }; - shader - } - pub fn destroy(&self, gl: &glow::Context) { unsafe { self.native_program.map(|p| gl.delete_program(p)); } } - pub fn render(&self, gl: &glow::Context) { - unsafe { - gl.clear_color(0.05, 0.05, 0.1, 1.0); - gl.clear(glow::COLOR_BUFFER_BIT); - gl.use_program(self.native_program); - } + pub fn get_uniform_location( + &self, + gl: &glow::Context, + name: &str, + ) -> Option { + self.native_program + .as_ref() + .map(|p| unsafe { + let location = gl.get_uniform_location(*p, name); + location + }) + .flatten() } } diff --git a/src/components/shader.rs b/src/components/shader.rs index 4f56c53..5b16341 100644 --- a/src/components/shader.rs +++ b/src/components/shader.rs @@ -6,14 +6,14 @@ use super::{ }; use crate::{ errors::{Error, Result}, - utils::{find_file, CodeBlock}, + utils::{find_file, Code, CodeBlock}, }; +use glow::HasContext; use log::{info, warn}; pub use utils::fetchcode; pub type ShaderType = u32; #[derive(Debug)] pub struct Shader { - code: String, target: u32, parsed: CodeBlock, pub hooks: Vec, @@ -27,7 +27,7 @@ impl std::fmt::Display for Shader { impl Shader { pub fn new>(target: ShaderType, code: CodeType) -> Result { - let mut code = match code { + let code = match code { CodeType::Code(code) => code.borrow().to_string(), CodeType::Path(path) => { let code = find_file(path).expect("Failed to find file"); @@ -35,21 +35,6 @@ impl Shader { } }; - match target { - - glow::VERTEX_SHADER => { - code.insert_str(0, "#define _GLUMPY__VERTEX_SHADER__\n"); - } - - glow::FRAGMENT_SHADER => { - code.insert_str(0, "#define _GLUMPY__FRAGMENT_SHADER__\n"); - } - - _ => { - warn!("Unknown shader type: {}", target); - } - } - let code = merge_includes(code).map_err(|e| Error::InvalidSnippet(e.to_string()))?; let parsed = CodeBlock::new(&code)?; @@ -58,17 +43,43 @@ impl Shader { Ok(Self { target, - code, parsed, hooks, }) } - pub fn compile(&self) {} + pub fn compile( + &self, + version: &str, + gl: &glow::Context, + ) -> ::Shader { + let shader = unsafe { + let shader = gl.create_shader(self.target).expect("Cannot create shader"); + gl.shader_source( + shader, + &format!("{}\n{}", &format!("#version {}", version), self.to_string()), + ); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + panic!("{}", gl.get_shader_info_log(shader)) + } + shader + }; + shader + } + + pub fn define(&mut self, s: &str) { + self.parsed + .insert(Code::new(&format!("#define {}\n", s)), 0); + } pub fn set_hook(&mut self, hook: &str, code: &Snippet) { self.parsed.set_hook(hook, code); } + + pub fn target(&self) -> u32 { + self.target + } } impl CodeComponent for Shader { diff --git a/src/data_loader/error.rs b/src/data_loader/error.rs new file mode 100644 index 0000000..ed2f9b5 --- /dev/null +++ b/src/data_loader/error.rs @@ -0,0 +1,14 @@ +use thiserror::Error; +#[derive(Debug, Error)] +pub enum ETWSError { + #[error("IO Error")] + IOError { + #[from] + source: std::io::Error, + }, + #[error("Format Error")] + FormatError { + #[from] + source: anyhow::Error, + }, +} diff --git a/src/data_loader/mod.rs b/src/data_loader/mod.rs new file mode 100644 index 0000000..40a69db --- /dev/null +++ b/src/data_loader/mod.rs @@ -0,0 +1,260 @@ +use crate::errors::*; +use crate::utils::geo_tools::calculate_coverage; +use ndarray::ArrayD; +pub mod error; +mod parser; + +use chrono::Utc; + +macro_rules! block_prepare { + ($data: ident, $_ty: ty, $shape:ident, $(($branch: tt),)+) => { + match $data { + $( + $branch(data) => ArrayD::from_shape_vec($shape.as_slice(), data.into_iter().map(|b| b as $_ty).collect::>()).unwrap(), + )+ + } + }; +} + +macro_rules! block_data_type_prepare { + ($data: ident, $($branch: tt => $data_type: tt,)+) => { + match $data { + $( + $branch => $data_type, + )+ + _ => DataType::Unknown + } + }; +} + +#[derive(Debug, Clone)] +pub struct Data { + pub filetime: chrono::DateTime, + pub radar_info: RadarInfo, + pub blocks: Vec, +} + +#[derive(Debug, Clone, Copy)] +pub enum DataType { + ET, + VIL, + EB, + DBZ, + VEl, + ZDR, + PHIDP, + KDP, + CC, + HCA, + QPE, + QPF, + Unknown, +} + +#[derive(Debug, Clone)] +pub struct Block { + pub data: ArrayD, + pub data_type: DataType, + pub coord_type: CoordType, + pub min_value: f32, + pub max_value: f32, + pub unvalid_value: f32, +} + +#[derive(Debug, Clone)] +pub enum CoordType { + Polar { + azimuth_range: [f64; 2], + r_range: [f64; 2], + elevation_range: [f64; 2], + azimuth: Vec, + r: Vec, + elevation: Vec, + }, + Cartesian { + lat_range: [f64; 2], + lon_range: [f64; 2], + hgt_range: [f64; 2], + lat: Vec, + lon: Vec, + hgt: Vec, + }, + + Other, +} + +#[derive(Debug, Clone)] +pub struct RadarInfo { + pub lat_range: [f32; 2], + pub lon_range: [f32; 2], + pub center: [f32; 3], +} + +impl Data { + pub fn from_path(path: impl AsRef) -> Result { + let record = parser::Record::parse_from_path(path)?; + + let mut radar_loc: [Option; 3] = [None, None, None]; + + let blocks = record + .blocks + .into_iter() + .map(|b| { + let vec_data = b.data; + use parser::ValueResult::*; + + let info = b.info; + + radar_loc = [info.radar_alt, info.radar_lat, info.radar_lon]; + let shape = info + .dimension_size + .into_iter() + .map(|s| s as usize) + .collect::>(); + + let new_data = block_prepare!( + vec_data, + f32, + shape, + (I64), + (F64), + (I32), + (F32), + (I16), + (U64), + (U32), + (I8), + (U8), + ); + + let dim_len = info.dimension_values.len(); + let dim_last = info.dimension_values.get(dim_len - 1).unwrap(); + let dim_minus_one = info.dimension_values.get(dim_len - 2).unwrap(); + let (dim_minus_two_range, dim_minus_two) = if dim_len == 3 { + let hgt = info.dimension_values.get(dim_len - 3).unwrap(); + ( + [hgt[0], hgt[hgt.len() - 1]], + hgt.iter().map(|v| *v as f32).collect(), + ) + } else { + ([0.0, 0.0], vec![]) + }; + + let dim_last_range = [dim_last[0], dim_last[dim_last.len() - 1]]; + let dim_minus_one_range = + [dim_minus_one[0], dim_minus_one[dim_minus_one.len() - 1]]; + + let coord_type = if info.dimension_des.contains(&format!("lat")) { + CoordType::Cartesian { + lat_range: dim_minus_one_range, + lon_range: dim_last_range, + hgt_range: dim_minus_two_range, + lat: dim_minus_one.iter().map(|v| *v as f32).collect(), + lon: dim_last.iter().map(|v| *v as f32).collect(), + hgt: dim_minus_two, + } + } else if info.dimension_des.contains(&format!("ele")) + || info.dimension_des.contains(&format!("el")) + || info.dimension_des.contains(&format!("elevation")) + { + CoordType::Polar { + azimuth_range: dim_minus_one_range, + r_range: dim_last_range, + elevation_range: dim_minus_two_range, + azimuth: dim_minus_one.iter().map(|v| *v as f32).collect(), + r: dim_last.iter().map(|v| *v as f32).collect(), + elevation: dim_minus_two, + } + } else { + CoordType::Other + }; + + use DataType::*; + let valuetype = info.value_type.as_str(); + + let data_type = block_data_type_prepare!(valuetype, + "ET" => ET, + "VIL" => VIL, + "EB" => EB, + "DBZ" =>DBZ, + "CR" => DBZ, + "R" => DBZ, + "V" => VEl, + "ZDR" => ZDR, + "PHIDP" => PHIDP, + "KDP" => KDP, + "CC" => CC, + "HCA" => HCA, + "QPE" => QPE, + "QPF" => QPF, + "FR" => DBZ, + ); + + Block { + data: new_data, + data_type, + coord_type, + min_value: 0.0, + max_value: 204.0, + unvalid_value: info.fill_value as f32, + } + }) + .collect::>(); + + let radar_info = match blocks.first().unwrap().coord_type { + CoordType::Cartesian { + lat_range, + lon_range, + .. + } => RadarInfo { + lat_range: [lat_range[0] as f32, lat_range[1] as f32], + lon_range: [lon_range[0] as f32, lon_range[1] as f32], + center: [ + lat_range[0] as f32 + (lat_range[1] - lat_range[0]) as f32 / 2.0, + lon_range[0] as f32 + (lon_range[1] - lon_range[0]) as f32 / 2.0, + 0.0, + ], + }, + CoordType::Polar { r_range, .. } => { + let (min_lat, max_lat, min_lon, max_lon) = + calculate_coverage(radar_loc[1].unwrap(), radar_loc[2].unwrap(), r_range[1]); + + RadarInfo { + lat_range: [min_lat as f32, max_lat as f32], + lon_range: [min_lon as f32, max_lon as f32], + center: [ + radar_loc[1].unwrap() as f32, + radar_loc[2].unwrap() as f32, + radar_loc[0].unwrap() as f32, + ], + } + } + _ => { + panic!("Unknown coord type"); + } + }; + + Ok(Self { + filetime: record.filetime, + blocks, + radar_info, + }) + } + + pub fn get_data_slice(&self, index: usize) -> Option<&[f32]> { + self.blocks.get(index).map(|b| b.data.as_slice().unwrap()) + } +} + +mod test { + use super::Data; + + #[test] + fn test_load() { + // let path = "/Volumes/data6/RadarArray/ShaoXing/radarData/OutputProducts/RadarProducts/FuseDataX/20030506/ZJSXAA_20030506200000_FR.dat.gz"; + let path = "/Users/tsuki/Desktop/ZJSXAA_20230627163400_VIL.dat.gz"; + + let data = Data::from_path(path).unwrap(); + println!("{:?}", data); + } +} diff --git a/src/data_loader/parser.rs b/src/data_loader/parser.rs new file mode 100644 index 0000000..6173d88 --- /dev/null +++ b/src/data_loader/parser.rs @@ -0,0 +1,388 @@ +use super::error::ETWSError; +use aligned_vec::AVec; +use byteorder::{BigEndian, ByteOrder, LittleEndian}; +use chrono::{DateTime, NaiveDateTime, Utc}; +use flate2::read::GzDecoder; +use nom::{ + bytes::complete::{tag, take}, + multi::count, + IResult, +}; +use nom_derive::*; +use serde::{Deserialize, Serialize}; +use std::fs::File; +use std::io::Read; +use std::path::Path; + +pub enum ValueResult { + I64(Vec), + F64(Vec), + I32(Vec), + F32(Vec), + I16(Vec), + U64(Vec), + U32(Vec), + I8(Vec), + U8(Vec), +} + +enum ValueTypes { + I64, + F64, + I32, + F32, + U64, + U32, + I16, + I8, + U8, +} + +#[derive(Clone, Copy)] +enum Order { + BigEndian, + LittleEndian, +} + +pub struct Record { + pub filetime: DateTime, + pub blocks: Vec, // Fill in generic types appropriately +} + +macro_rules! match_in_macro { + ($block:ident,$len:ident,$input:ident,$offset:ident,$scale:ident,$fill_value:ident,$(($branch:path, $t:ty, $bigger:ty,$raw_result:path, $bigger_result:path)),+) => { + { + use std::mem; + let need_trans = $offset != 0.0 || $scale != 1.0; + let trans_to_bigger = $offset.trunc() != $offset || $scale != 1.0; + match $block { + $( + $branch => { + let ratio = mem::size_of::<$t>() / mem::size_of::(); + let (input, result) = take($len * ratio)($input)?; + + let result = unsafe { + + let mut ptr = result.as_ptr() as *const u8; + let aligned = ptr.align_offset(mem::align_of::<$t>()); + + if aligned != 0 { + let p = AVec::::from_slice(mem::align_of::<$t>(), result); + ptr = p.into_raw_parts().0; + } + + let ptr = ptr.cast::<$t>(); + + let slice = std::slice::from_raw_parts(ptr, $len); + let slice = slice.to_vec(); + + if trans_to_bigger { + let offset = $offset as $bigger; + let scale = $scale as $bigger; + $bigger_result( + slice + .into_iter() + .map(|p| if (p as f64 - $fill_value).abs() < f64::EPSILON {p as $bigger} else {(p as $bigger - offset) / scale} ) + .collect::>(), + ) + } else { + $raw_result(if need_trans { + let offset = $offset as $t; + slice.into_iter().map(|p| if (p as f64 - $fill_value).abs() < f64::EPSILON {p} else {p - offset}).collect::>() + } else { + slice + }) + } + }; + Ok((input, result)) + }, + )+ + } + } + + }; +} + +impl Record { + pub fn parse_from_path(path: impl AsRef) -> Result { + let path = path.as_ref(); + if !(path.ends_with(".dat") || !path.ends_with(".dat.gz")) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Invalid file extension", + ) + .into()); + } + + if !path.exists() { + return Err(std::io::Error::new(std::io::ErrorKind::NotFound, "File not found").into()); + } + + let mut file = File::open(path)?; + let binary_data = if path.extension().unwrap() == "gz" { + let mut result: Vec = Vec::new(); + let mut decoder = GzDecoder::new(file); + decoder.read_to_end(&mut result)?; + result + } else { + let mut result = Vec::new(); + file.read_to_end(&mut result)?; + result + }; + + let (_, parsed) = + Self::_parse(binary_data.as_slice()).map_err(|_| anyhow::Error::msg("Parse error"))?; + + Ok(parsed) + } + + fn _parse(binary_data: &[u8]) -> IResult<&[u8], Record> { + let start_tag = b"UNI_DATA"; + let (input, _) = tag(start_tag)(binary_data)?; + let (input, order) = Self::_parse_split_fn(input, 8, 8, Self::_parse_order)?; + let (input, hlen) = take(4usize)(input)?; + + let hlen = match order { + Order::BigEndian => BigEndian::read_u32(hlen), + _ => LittleEndian::read_u32(hlen), + }; + let (input, record_info) = Self::_parse_split_fn(input, 0, 8, |input| { + let (input, p) = take(hlen)(input)?; + let p: RecordInfo = serde_json::from_slice(p).unwrap(); + Ok((input, p)) + })?; + + let (input, blocks) = + count(Self::_parse_block_fn(order), record_info.block_num as usize)(input)?; + + let data_time = + NaiveDateTime::parse_from_str(&record_info.file_time, r"%Y%m%d%H%M%S").unwrap(); + let filetime = data_time.and_utc(); + + Ok((input, Record { filetime, blocks })) + } + + fn _parse_order(input: &[u8]) -> IResult<&[u8], Order> { + let (input, order) = take(4usize)(input)?; + let result = if order == b"LEND" { + Order::LittleEndian + } else { + Order::BigEndian + }; + let (input, _) = take(4usize)(input)?; + Ok((input, result)) + } + + fn _parse_split(input: &[u8], s: usize, fore: usize, after: usize) -> IResult<&[u8], &[u8]> { + let (input, _) = take(fore)(input)?; + let (input, result) = take(s)(input)?; + let (input, _) = take(after)(input)?; + Ok((input, result)) + } + + fn _parse_split_fn IResult<&[u8], E>>( + input: &[u8], + fore: usize, + after: usize, + f: F, + ) -> IResult<&[u8], E> { + let (input, _) = take(fore)(input)?; + let (input, result) = (f)(input)?; + let (input, _) = take(after)(input)?; + Ok((input, result)) + } + + fn _parse_block_fn(order: Order) -> impl FnMut(&[u8]) -> IResult<&[u8], ParsedBlock> { + move |input| Self::_parse_split_fn(input, 0, 0, |input| Self::_parse_block(input, order)) + } + + fn _parse_block(input: &[u8], order: Order) -> IResult<&[u8], ParsedBlock> { + let (input, _) = take(8usize)(input)?; + let (input, hlen1) = Self::_parse_u32(input, order)?; + let (input, block_info) = Self::_parse_split_fn(input, 0, 8, |input| { + let (input, p) = take(hlen1)(input)?; + + let p: BlockJsonInfo = serde_json::from_slice(p).unwrap(); + Ok((input, p)) + })?; + + let (input, _) = take(8usize)(input)?; // skip 8 bytes + let (input, hlen2) = Self::_parse_u32(input, order)?; + let dimension_size = block_info.dimension_size.clone(); + let size = dimension_size.iter().fold(1, |acc, x| acc * x) as usize; + let value_type = block_info.value_type.clone(); + let value_type = Self::_parse_type(&value_type); + + let (input, data) = Self::_parse_matrix( + input, + value_type, + order, + size, + block_info.value_offset, + block_info.value_scale, + block_info.fill_value, + )?; + + Ok(( + input, + ParsedBlock { + info: block_info, + data, + }, + )) + } + + fn _parse_i32(input: &[u8], order: Order) -> IResult<&[u8], i32> { + let (input, hlen) = take(4usize)(input)?; + let hlen = match order { + Order::BigEndian => BigEndian::read_i32(hlen), + _ => LittleEndian::read_i32(hlen), + }; + + Ok((input, hlen)) + } + + fn _parse_u32(input: &[u8], order: Order) -> IResult<&[u8], u32> { + let (input, hlen) = take(4usize)(input)?; + let hlen = match order { + Order::BigEndian => BigEndian::read_u32(hlen), + _ => LittleEndian::read_u32(hlen), + }; + + Ok((input, hlen)) + } + + fn _parse_i64(input: &[u8], order: Order) -> IResult<&[u8], i64> { + let (input, hlen) = take(8usize)(input)?; + let hlen = match order { + Order::BigEndian => BigEndian::read_i64(hlen), + _ => LittleEndian::read_i64(hlen), + }; + + Ok((input, hlen)) + } + + fn _parse_u64(input: &[u8], order: Order) -> IResult<&[u8], u64> { + let (input, hlen) = take(8usize)(input)?; + let hlen = match order { + Order::BigEndian => BigEndian::read_u64(hlen), + _ => LittleEndian::read_u64(hlen), + }; + + Ok((input, hlen)) + } + + fn _parse_type<'a>(type_str: &'a str) -> ValueTypes { + match type_str { + "b" => ValueTypes::I8, + "B" => ValueTypes::U8, + "i" => ValueTypes::I32, + "I" => ValueTypes::U32, + "f" => ValueTypes::F32, + "d" => ValueTypes::F64, + "h" => ValueTypes::I16, + _ => panic!("Invalid type"), + } + } + + fn _parse_matrix( + input: &[u8], + type_: ValueTypes, + order: Order, + len: usize, + offset: f32, + scale: f32, + fill_value: f64, + ) -> IResult<&[u8], ValueResult> { + match_in_macro!( + type_, + len, + input, + offset, + scale, + fill_value, + ( + ValueTypes::I64, + i64, + f64, + ValueResult::I64, + ValueResult::F64 + ), + ( + ValueTypes::F64, + f64, + f64, + ValueResult::F64, + ValueResult::F64 + ), + ( + ValueTypes::U64, + u64, + f64, + ValueResult::U64, + ValueResult::F64 + ), + ( + ValueTypes::I32, + i32, + f32, + ValueResult::I32, + ValueResult::F32 + ), + ( + ValueTypes::F32, + f32, + f32, + ValueResult::F32, + ValueResult::F32 + ), + ( + ValueTypes::U32, + u32, + f32, + ValueResult::U32, + ValueResult::F32 + ), + ( + ValueTypes::I16, + i16, + f32, + ValueResult::I16, + ValueResult::F32 + ), + (ValueTypes::I8, i8, f32, ValueResult::I8, ValueResult::F32), + (ValueTypes::U8, u8, f32, ValueResult::U8, ValueResult::F32) + ) + } +} + +#[derive(Serialize, Deserialize, Debug)] +struct RecordInfo { + file_time: String, + block_num: i32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct BlockJsonInfo { + pub value_name: String, + pub value_des: String, + pub value_type: String, + pub dimension_size: Vec, + pub dimension: usize, + pub dimension_des: Vec, + pub dimension_start: Vec, + pub dimension_end: Vec, + pub dimension_values: Vec>, + pub fill_value: f64, + pub value_scale: f32, + pub value_offset: f32, + pub radar_alt: Option, + pub radar_lat: Option, + pub radar_lon: Option, + pub radar_name: Option, +} + +pub struct ParsedBlock { + pub info: BlockJsonInfo, + pub data: ValueResult, +} diff --git a/src/errors.rs b/src/errors.rs index 3a185eb..44ed315 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -12,4 +12,13 @@ pub enum Error { #[error("Invalid Program {0}")] InvalidProgram(String), + + #[error("Invalid Data")] + InvalidData { + #[from] + source: crate::data_loader::error::ETWSError, + }, + + #[error("Invalid CoordType")] + InvalidDataType, } diff --git a/src/final_pg.rs b/src/final_pg.rs index 8f0d9ff..87a48b8 100644 --- a/src/final_pg.rs +++ b/src/final_pg.rs @@ -7,62 +7,62 @@ use crate::{ }, }; -pub struct PPI { - transform: Trackball, - program: Program, -} +// pub struct PPI { +// transform: Trackball, +// program: Program, +// } -impl PPI { - pub fn new(version: &'static str) -> Self { - let trackball = Trackball::new().unwrap(); - let projection = Polar::new().unwrap(); - let position = Position::new().unwrap(); +// impl PPI { +// pub fn new(version: &'static str) -> Self { +// let trackball = Trackball::new().unwrap(); +// let projection = Polar::new().unwrap(); +// let position = Position::new().unwrap(); - let transform = trackball.chain(projection.chain(position)); +// // let transform = trackball.chain(projection.chain(position)); - let vertex = Shader::new( - glow::VERTEX_SHADER, - CodeType::<&'static str>::Path("agg-fast-path.vert".into()), - ) - .unwrap(); +// let vertex = Shader::new( +// glow::VERTEX_SHADER, +// CodeType::<&'static str>::Path("agg-fast-path.vert".into()), +// ) +// .unwrap(); - let fragment = Shader::new( - glow::FRAGMENT_SHADER, - CodeType::<&'static str>::Path("agg-fast-path.frag".into()), - ) - .unwrap(); +// let fragment = Shader::new( +// glow::FRAGMENT_SHADER, +// CodeType::<&'static str>::Path("agg-fast-path.frag".into()), +// ) +// .unwrap(); - let mut program = Program::new(vertex, fragment, None, version); +// let mut program = Program::new(vertex, fragment, None, version); - let viewport = Viewport::new().unwrap(); +// let viewport = Viewport::new().unwrap(); - program.set_transform(&transform); +// // program.set_transform(&transform); - program.set_viewport(&viewport); +// program.set_viewport(&viewport); - Self { transform, program } - } +// Self { transform, program } +// } - pub fn compile(&mut self, gl: &glow::Context) { - self.program.compile(gl); - } +// pub fn compile(&mut self, gl: &glow::Context) { +// self.program.compile(gl); +// } - pub fn program(&self) -> &Program { - &self.program - } +// pub fn program(&self) -> &Program { +// &self.program +// } - pub fn native_program(&self) -> Option<::Program> { - self.program.native_program - } -} +// pub fn native_program(&self) -> Option<::Program> { +// self.program.native_program +// } +// } mod test { use super::*; #[test] fn test_ppi() { - let ppi = PPI::new("450"); + // let ppi = PPI::new("450"); - println!("{}", ppi.program.vertex()); + // println!("{}", ppi.program.vertex()); } } diff --git a/src/graphics/collections/agg_fast_path.rs b/src/graphics/collections/agg_fast_path.rs index 8f992fe..ca97129 100644 --- a/src/graphics/collections/agg_fast_path.rs +++ b/src/graphics/collections/agg_fast_path.rs @@ -1,6 +1,7 @@ use std::ops::{Deref, DerefMut}; use bytemuck::{Pod, Zeroable}; +use glow::{HasContext, NativeBuffer, NativeVertexArray}; use crate::components::{fetchcode, CodeComponent, CodeType, Program, Shader, Snippet}; use crate::errors::*; @@ -14,10 +15,13 @@ use super::Colletion; pub struct AggFastPath { program: Program, buffer: Vec, + + vao: Option, + vbo: Option, } impl AggFastPath { - pub fn new(transform: &T, viewport: &Viewport) -> Result { + pub fn new() -> Result { let vertex = Shader::new( glow::VERTEX_SHADER, CodeType::::Path("agg-fast-path.vert".into()), @@ -28,10 +32,14 @@ impl AggFastPath { CodeType::::Path("agg-fast-path.frag".into()), )?; - let input_snippet = Snippet::new("input",CodeType::Code(" + let input_snippet = Snippet::new( + "input", + CodeType::Code( + " layout(location = 0) in vec3 prev; layout(location = 1) in vec3 curr; layout(location = 2) in vec3 next; + layout(location = 3) in float id; uniform float linewidth; @@ -39,24 +47,63 @@ impl AggFastPath { uniform vec4 color; - ") ,false, None)?; + ", + ), + false, + None, + )?; let vertex = vertex.add_snippet_before(input_snippet); - let mut program = Program::new(vertex, fragment, None, "330 core"); + let program = Program::new(vertex, fragment, None, "330 core"); - program.set_transform(transform); - program.set_viewport(viewport); - - println!("{}", program.vertex()); - - println!("{}", program.fragment()); + // program.set_transform(transform); + // program.set_viewport(viewport); Ok(Self { program, buffer: Vec::with_capacity(128), + vao: None, + vbo: None, }) } + + pub fn set_transform(&mut self, transform: &T) { + self.program.set_transform(transform); + } + + pub fn set_viewport(&mut self, viewport: &Viewport) { + self.program.set_viewport(viewport); + } + + pub fn set_linecolor(&mut self, gl: &glow::Context, color: [f32; 4]) { + let loc = self.program.get_uniform_location(gl, "color"); + unsafe { + gl.uniform_4_f32(loc.as_ref(), color[0], color[1], color[2], color[3]); + } + } + + pub fn set_linewidth(&mut self, gl: &glow::Context, linewidth: f32) { + let loc = self.program.get_uniform_location(gl, "linewidth"); + unsafe { + gl.uniform_1_f32(loc.as_ref(), linewidth); + } + } + + pub fn set_anatialias(&mut self, gl: &glow::Context, antialias: f32) { + let loc = self.program.get_uniform_location(gl, "antialias"); + unsafe { + gl.uniform_1_f32(loc.as_ref(), antialias); + } + } + + pub fn program(&mut self) -> &mut Program { + &mut self.program + } + + pub fn program_ref(&self) -> &Program { + &self.program + } } impl Colletion for AggFastPath { @@ -68,17 +115,64 @@ impl Colletion for AggFastPath { } impl Graphics for AggFastPath { - fn compile(&mut self, gl: &glow::Context) -> Result<()> { - self.program.compile(gl) + use bytemuck::cast_slice; + self.program.compile(gl)?; + unsafe { + let vao = gl.create_vertex_array().unwrap(); + + gl.bind_vertex_array(Some(vao)); + + let vbo = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + cast_slice(&self.buffer), + glow::STATIC_DRAW, + ); + + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 40, 0); + + gl.enable_vertex_attrib_array(1); + gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 40, 12); + + gl.enable_vertex_attrib_array(2); + gl.vertex_attrib_pointer_f32(2, 3, glow::FLOAT, false, 40, 24); + + gl.enable_vertex_attrib_array(3); + gl.vertex_attrib_pointer_f32(3, 1, glow::FLOAT, false, 40, 36); + + self.vao = Some(vao); + self.vbo = Some(vbo); + + gl.bind_vertex_array(None); + } + + Ok(()) } + fn draw(&self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.clear(glow::COLOR_BUFFER_BIT); + gl.use_program(Some(self.program.native_program.unwrap())); + gl.bind_vertex_array(Some(self.vao.unwrap())); + gl.draw_arrays(glow::TRIANGLE_STRIP, 0, self.buffer.len() as i32); - fn draw(&self) -> Result<()> { + gl.bind_vertex_array(None); + } + + Ok(()) + } + + fn destroy(&mut self, gl: &glow::Context) -> Result<()> { + self.program.destroy(gl); + + unsafe { + self.vao.map(|vao| gl.delete_vertex_array(vao)); + self.vbo.map(|vbo| gl.delete_buffer(vbo)); + } - use bytemuck::cast_slice; - let b:&[u8] = cast_slice(&self.buffer); - Ok(()) } } @@ -89,6 +183,7 @@ pub struct Point { prev: [f32; 3], curr: [f32; 3], next: [f32; 3], + id: f32, } impl Ty for Point {} @@ -101,49 +196,38 @@ pub struct Path { } impl Default for Path { - fn default() -> Self { Self { points: Vec::with_capacity(500), is_closed: false, - is_empty: true + is_empty: true, } } - } pub struct PathBuilder { is_closed: bool, } -impl Default for PathBuilder{ - +impl Default for PathBuilder { fn default() -> Self { - Self { - is_closed: false - } + Self { is_closed: false } } - } impl PathBuilder { - - pub fn is_closed(&mut self , is_closed: bool) -> &mut Self { + pub fn is_closed(&mut self, is_closed: bool) -> &mut Self { self.is_closed = is_closed; self } - pub fn build(&self) -> Path { - Path { points: Vec::with_capacity(500), is_closed: self.is_closed, is_empty: true, } - } - } impl Path { @@ -159,19 +243,20 @@ impl Path { PathBuilder::default() } - pub fn push(&mut self, point: [f32; 3]) { if self.is_empty { self.points.push(Point { prev: point, curr: point, next: point, + id: 1.0, }); self.points.push(Point { prev: point, curr: point, next: point, + id: -1.0, }); self.is_empty = false; @@ -180,12 +265,21 @@ impl Path { let prev = self.points[len - 1].curr; let curr = point; let next = point; - self.points.push(Point { prev, curr, next }); - self.points[len - 1].next = curr; + self.points.push(Point { + prev, + curr, + next, + id: 1.0, + }); + self.points.push(Point { + prev, + curr, + next, + id: -1.0, + }); - if len == 2 { - self.points[0].next = curr; - } + self.points[len - 1].next = curr; + self.points[len - 2].next = curr; } } @@ -195,20 +289,28 @@ impl Path { let curr = self.points.first().unwrap().curr; let prev = self.points[len - 1].curr; let next = self.points[1].next; - self.points.push(Point { prev, curr, next }); + self.points.push(Point { + prev, + curr, + next, + id: 1.0, + }); + self.points.push(Point { + prev, + curr, + next, + id: -1.0, + }); self.points[len - 1].next = curr; + self.points[len - 2].next = curr; } - - self.points.push(self.points.last().unwrap().clone()); } pub fn len(&self) -> usize { - self.points.len() - 2 + self.points.len() } - } - impl Deref for Path { type Target = [u8]; @@ -225,7 +327,6 @@ impl DerefMut for Path { } } - mod test { use crate::graphics::transforms::{polar::Polar, position::Position, trackball::Trackball}; @@ -234,7 +335,6 @@ mod test { #[test] fn test_path() { - let mut path = Path::builder().is_closed(false).build(); path.push([9.0, 9.0, 9.0]); @@ -248,16 +348,14 @@ mod test { #[test] fn test_agg() { + // let viewport = Trackball::new().unwrap(); + // let trans = Polar::new().unwrap(); + // let position = Position::new().unwrap(); - let viewport = Trackball::new().unwrap(); - let trans = Polar::new().unwrap(); - let position = Position::new().unwrap(); + // let transform = viewport.chain(trans.chain(position)); - let transform = viewport.chain(trans.chain(position)); - - let viewport = &Viewport::new().unwrap(); - - let agg_path = AggFastPath::new(&transform, &viewport).unwrap(); + // let viewport = &Viewport::new().unwrap(); + // let agg_path = AggFastPath::new(&transform, &viewport).unwrap(); } -} \ No newline at end of file +} diff --git a/src/graphics/colormap/linear.rs b/src/graphics/colormap/linear.rs new file mode 100644 index 0000000..bcc7de6 --- /dev/null +++ b/src/graphics/colormap/linear.rs @@ -0,0 +1,129 @@ +use glow::HasContext; + +use crate::components::{CodeType, Program, Snippet}; +use crate::errors::*; + +use super::ColorMap; + +pub struct LinearColormap { + snippet: Snippet, + colors: Vec<[u8; 4]>, + + color_changed: bool, + texture: Option, + + pub min: f32, + pub max: f32, +} + +impl LinearColormap { + pub fn new() -> Result { + let snippet = Snippet::new( + "linear", + CodeType::<&'static str>::Path("colormap.glsl".into()), + true, + None, + )?; + + Ok(Self { + snippet, + colors: vec![], + texture: None, + color_changed: true, + min: 0.0, + max: 1.0, + }) + } + + pub fn set_colors(&mut self, colors: Vec<[u8; 4]>) { + self.colors = colors; + self.color_changed = true; + } + + pub fn set_range(&mut self, min: f32, max: f32) { + self.min = min; + self.max = max; + } +} + +impl ColorMap for LinearColormap { + fn attach_with_program( + &mut self, + gl: &glow::Context, + program: &crate::components::Program, + ) -> crate::errors::Result<()> { + use bytemuck::cast_slice; + unsafe { + if self.color_changed { + let texture = gl.create_texture().unwrap(); + gl.bind_texture(glow::TEXTURE_1D, Some(texture)); + gl.tex_image_1d( + glow::TEXTURE_1D, + 0, + glow::RGBA as i32, + self.colors.len() as i32, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(cast_slice(&self.colors)), + ); + + gl.tex_parameter_i32( + glow::TEXTURE_1D, + glow::TEXTURE_MIN_FILTER, + glow::NEAREST as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_1D, + glow::TEXTURE_MAG_FILTER, + glow::NEAREST as i32, + ); + + let name = self.snippet.find_symbol("conf").unwrap(); + let location = program.get_uniform_location(gl, &name); + + // gl.uniform_2_f32(location.as_ref(), 0); + gl.uniform_4_f32( + location.as_ref(), + self.min, + self.max, + self.colors.len() as f32, + 125.0, + ); + + self.texture = Some(texture); + } + } + + Ok(()) + } + + fn bind_texture(&self, gl: &glow::Context, program: &Program) -> crate::errors::Result<()> { + unsafe { + gl.active_texture(glow::TEXTURE0); + gl.bind_texture(glow::TEXTURE_1D, self.texture); + let name = self.snippet.find_symbol("colormap").unwrap(); + let location = program.get_uniform_location(gl, &name); + gl.uniform_1_i32(location.as_ref(), 0); + } + + Ok(()) + } + + fn snippet_ref(&self) -> &crate::components::Snippet { + &self.snippet + } +} + +mod test { + #[test] + + fn test() { + use super::LinearColormap; + + let mut colormap = LinearColormap::new().unwrap(); + + // colormap.set_colors(vec![[0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 1.0]]); + colormap.set_range(0.0, 1.0); + } +} diff --git a/src/graphics/colormap/mod.rs b/src/graphics/colormap/mod.rs new file mode 100644 index 0000000..9587ef7 --- /dev/null +++ b/src/graphics/colormap/mod.rs @@ -0,0 +1,15 @@ +use crate::components::Program; + +pub mod linear; + +pub trait ColorMap { + fn attach_with_program( + &mut self, + gl: &glow::Context, + program: &crate::components::Program, + ) -> crate::errors::Result<()>; + + fn bind_texture(&self, gl: &glow::Context, program: &Program) -> crate::errors::Result<()>; + + fn snippet_ref(&self) -> &crate::components::Snippet; +} diff --git a/src/graphics/hello.rs b/src/graphics/hello.rs new file mode 100644 index 0000000..f6b63ef --- /dev/null +++ b/src/graphics/hello.rs @@ -0,0 +1,241 @@ +use std::ops::{Deref, DerefMut}; + +use bytemuck::{Pod, Zeroable}; +use glow::{HasContext, NativeBuffer, NativeVertexArray}; + +use crate::components::{fetchcode, CodeComponent, CodeType, Program, Shader, Snippet}; +use crate::errors::*; +use crate::graphics::transforms::viewport::Viewport; +use crate::graphics::transforms::Transform; +use crate::graphics::ty::Ty; +use crate::graphics::Graphics; + +pub struct Hello { + program: Program, + buffer: Vec, + + vao: Option, +} + +impl Hello { + pub fn new() -> Result { + let vertex = Shader::new( + glow::VERTEX_SHADER, + CodeType::::Path("hello.vert".into()), + )?; + + let fragment = Shader::new( + glow::FRAGMENT_SHADER, + CodeType::::Path("hello.frag".into()), + )?; + + let program = Program::new(vertex, fragment, None, "330 core"); + + println!("Vertex:\n{}", program.vertex()); + println!("Fragment:\n{}", program.fragment()); + + Ok(Self { + program, + buffer: Vec::with_capacity(128), + vao: None, + }) + } + + pub fn program(&mut self) -> &mut Program { + &mut self.program + } + + pub fn program_ref(&self) -> &Program { + &self.program + } +} + +impl Graphics for Hello { + fn compile(&mut self, gl: &glow::Context) -> Result<()> { + self.program.compile(gl)?; + unsafe { + let vertex_array = gl + .create_vertex_array() + .expect("Cannot create vertex array"); + + self.vao = Some(vertex_array); + } + + Ok(()) + } + + fn draw(&self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.clear_color(0.05, 0.05, 0.1, 1.0); + gl.clear(glow::COLOR_BUFFER_BIT); + gl.use_program(Some(self.program.native_program.unwrap())); + gl.bind_vertex_array(self.vao); + gl.draw_arrays(glow::TRIANGLES, 0, 3); + } + + Ok(()) + } + + fn destroy(&mut self, gl: &glow::Context) -> Result<()> { + self.program.destroy(gl); + + unsafe { + self.vao.map(|vao| gl.delete_vertex_array(vao)); + } + + Ok(()) + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Zeroable, Pod)] +pub struct Point { + prev: [f32; 3], + curr: [f32; 3], + next: [f32; 3], +} + +impl Ty for Point {} + +#[derive(Debug)] +pub struct Path { + points: Vec, + is_closed: bool, + is_empty: bool, +} + +impl Default for Path { + fn default() -> Self { + Self { + points: Vec::with_capacity(500), + is_closed: false, + is_empty: true, + } + } +} + +pub struct PathBuilder { + is_closed: bool, +} + +impl Default for PathBuilder { + fn default() -> Self { + Self { is_closed: false } + } +} + +impl PathBuilder { + pub fn is_closed(&mut self, is_closed: bool) -> &mut Self { + self.is_closed = is_closed; + self + } + + pub fn build(&self) -> Path { + Path { + points: Vec::with_capacity(500), + is_closed: self.is_closed, + is_empty: true, + } + } +} + +impl Path { + pub fn new(is_closed: bool) -> Self { + Self { + points: Vec::with_capacity(500), + is_closed, + is_empty: true, + } + } + + pub fn builder() -> PathBuilder { + PathBuilder::default() + } + + pub fn push(&mut self, point: [f32; 3]) { + if self.is_empty { + self.points.push(Point { + prev: point, + curr: point, + next: point, + }); + + self.is_empty = false; + } else { + let len = self.points.len(); + let prev = self.points[len - 1].curr; + let curr = point; + let next = point; + self.points.push(Point { prev, curr, next }); + self.points[len - 1].next = curr; + + if len == 2 { + self.points[0].next = curr; + } + } + } + + pub fn finish(&mut self) { + if self.is_closed { + let len = self.points.len(); + let curr = self.points.first().unwrap().curr; + let prev = self.points[len - 1].curr; + let next = self.points[1].next; + self.points.push(Point { prev, curr, next }); + self.points[len - 1].next = curr; + } + } + + pub fn len(&self) -> usize { + self.points.len() + } +} + +impl Deref for Path { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + use bytemuck::cast_slice; + cast_slice(&self.points) + } +} + +impl DerefMut for Path { + fn deref_mut(&mut self) -> &mut Self::Target { + use bytemuck::cast_slice_mut; + cast_slice_mut(&mut self.points) + } +} + +mod test { + + use crate::graphics::transforms::{polar::Polar, position::Position, trackball::Trackball}; + + use super::*; + + #[test] + fn test_path() { + let mut path = Path::builder().is_closed(false).build(); + + path.push([9.0, 9.0, 9.0]); + + path.push([9.0, 19.0, 9.0]); + + path.finish(); + + println!("{:?}, len: {}", path, path.len()); + } + + #[test] + fn test_agg() { + // let viewport = Trackball::new().unwrap(); + // let trans = Polar::new().unwrap(); + // let position = Position::new().unwrap(); + + // let transform = viewport.chain(trans.chain(position)); + + // let viewport = &Viewport::new().unwrap(); + + // let agg_path = AggFastPath::new(&transform, &viewport).unwrap(); + } +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index c3b9352..e2537f0 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,14 +1,28 @@ pub mod collections; +pub mod colormap; mod colormesh; +pub mod hello; +pub mod ppi; pub mod tools; pub mod transforms; pub mod ty; -use crate::errors::*; +use crate::{components::Program, errors::*}; pub use colormesh::ColorMesh; pub trait Graphics { - fn draw(&self) -> Result<()>; + fn draw(&self, gl: &glow::Context) -> Result<()>; fn compile(&mut self, gl: &glow::Context) -> Result<()>; + + fn destroy(&mut self, gl: &glow::Context) -> Result<()>; +} + +pub trait AttaWithProgram { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()>; +} + +pub trait AttaWithBuffer { + type Data; + fn attach_with_buffer(&mut self, gl: &glow::Context, data: &Self::Data) -> Result<()>; } diff --git a/src/graphics/ppi.rs b/src/graphics/ppi.rs new file mode 100644 index 0000000..cc59e73 --- /dev/null +++ b/src/graphics/ppi.rs @@ -0,0 +1,251 @@ +use bytemuck::cast_slice; +use glow::{HasContext, NativeBuffer, NativeVertexArray}; +use ndarray::{s, IndexLonger}; + +use crate::components::{CodeType, Program, Shader, Snippet}; +use crate::data_loader::{CoordType, Data, DataType}; +use crate::errors::*; + +use super::colormap::ColorMap; +use super::transforms::viewport::Viewport; +use super::transforms::Transform; +use super::{ty, AttaWithBuffer, Graphics}; + +pub struct PPI<'a> { + program: Program, + layer: isize, + vao: Option, + vbo: Option, + + cmap: &'a mut dyn ColorMap, + + buffer: Vec<[f32; 3]>, +} + +impl<'a> PPI<'a> { + pub fn new(cmap: &'a mut dyn ColorMap) -> Result { + let vertex = Shader::new( + glow::VERTEX_SHADER, + CodeType::::Path("ppi.vert".into()), + )?; + + let geom = Shader::new( + glow::GEOMETRY_SHADER, + CodeType::::Path("ppi.geom".into()), + )?; + + let fragment = Shader::new( + glow::FRAGMENT_SHADER, + CodeType::::Path("ppi.frag".into()), + )?; + + let mut program = Program::new(vertex, fragment, Some(geom), "330 core"); + + program.set_hook("colormap", cmap.snippet_ref()); + + Ok(Self { + program, + layer: 0, + vao: None, + vbo: None, + buffer: Vec::with_capacity(180 * 50), + cmap, + }) + } + + pub fn set_transform(&mut self, transform: &T) { + self.program.set_transform(transform); + } + + pub fn set_viewport(&mut self, viewport: &Viewport) { + self.program.set_viewport(viewport); + } + + pub fn set_colormap(&mut self, colormap: &'a mut dyn ColorMap) { + self.cmap = colormap; + // self.program.set_hook("colormap", colormap.snippet_ref()); + } + + pub fn program(&mut self) -> &mut Program { + &mut self.program + } + + fn set_conf(&self, gl: &glow::Context, dpir: f32, dpie: f32) { + let location = self.program.get_uniform_location(gl, "conf"); + unsafe { + gl.uniform_4_f32(location.as_ref(), dpir, dpie, 0f32, 0f32); + } + } + + pub fn add_ppi_layer(&mut self, layer: isize) { + self.layer = self.layer + layer; + self.layer.clamp(0, 23); + } + + pub fn program_ref(&self) -> &Program { + &self.program + } + + fn bake_data(&self, data: &Data) -> Result> { + let first_block = data.blocks.get(0).unwrap(); + let first_block_data = first_block.data.view(); + if let CoordType::Polar { + r_range, + azimuth, + r, + .. + } = &first_block.coord_type + { + let azimuth_len = azimuth.len(); + let r_len = r.len(); + + let mut vertices = Vec::with_capacity(azimuth_len * r_len); + + for azi_idx in 0..azimuth_len { + for r_idx in 0..r_len { + let azi = azimuth.get(azi_idx).unwrap(); + let r = r.get(r_idx).unwrap() / r_range[1] as f32; + let dt = first_block_data + .get([self.layer as usize, azi_idx, r_idx]) + .unwrap(); + vertices.push([r, *azi, *dt]); + } + } + return Ok(vertices); + } else { + return Err(Error::InvalidDataType); + } + } + + fn data_info(&self, data: &Data) -> Result<(f32, f32, DataType)> { + let first_block = data.blocks.get(0).unwrap(); + if let CoordType::Polar { + azimuth, + r, + r_range, + .. + } = &first_block.coord_type + { + let mut sorted_azimuth = azimuth.clone(); + sorted_azimuth.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Greater)); + let azi_step = max_step(&sorted_azimuth); + let r_step = min_step(r) / (r_range[1]) as f32; + return Ok((r_step, azi_step, first_block.data_type)); + } else { + return Err(Error::InvalidDataType); + } + } +} + +fn min_step(data: &Vec) -> f32 { + // 计算相邻元素之间的间距 + let mut min_gap = f32::MAX; + for window in data.windows(2) { + if let [a, b] = window { + let gap = b - a; + if gap < min_gap { + min_gap = gap; + } + } + } + return min_gap; +} + +fn max_step(data: &Vec) -> f32 { + // 计算相邻元素之间的间距 + let mut max_gap = f32::MIN; + for window in data.windows(2) { + if let [a, b] = window { + let gap = b - a; + if gap > max_gap { + max_gap = gap; + } + } + } + return max_gap; +} + +impl<'a> Graphics for PPI<'a> { + fn compile(&mut self, gl: &glow::Context) -> Result<()> { + self.program.compile(gl)?; + self.cmap.attach_with_program(gl, &self.program)?; + unsafe { + let vao = gl.create_vertex_array().unwrap(); + gl.bind_vertex_array(Some(vao)); + let vbo = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 12, 0); + + self.vao = Some(vao); + self.vbo = Some(vbo); + gl.bind_vertex_array(None); + } + + // let location = self.program.get_uniform_location(gl, "conf"); + let origin = self.program.get_uniform_location(gl, "polar_origin"); + + unsafe { + // gl.uniform_4_f32(location.as_ref(), dpir, dpie, 0.0, 0.0); + gl.uniform_1_f32(origin.as_ref(), 90.0f32.to_radians()); + } + + Ok(()) + } + + fn destroy(&mut self, gl: &glow::Context) -> Result<()> { + self.program.destroy(gl); + + unsafe { + self.vao.map(|vao| gl.delete_vertex_array(vao)); + self.vbo.map(|vbo| gl.delete_buffer(vbo)); + } + + Ok(()) + } + + fn draw(&self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.clear(glow::COLOR_BUFFER_BIT); + gl.use_program(Some(self.program.native_program.unwrap())); + self.cmap.bind_texture(gl, &self.program)?; + gl.depth_mask(false); + gl.bind_vertex_array(Some(self.vao.unwrap())); + gl.draw_arrays(glow::POINTS, 0, self.buffer.len() as i32); + gl.depth_mask(true); + gl.bind_vertex_array(None); + gl.use_program(None); + } + Ok(()) + } +} + +impl<'a> AttaWithBuffer for PPI<'a> { + type Data = Data; + + fn attach_with_buffer(&mut self, gl: &glow::Context, data: &Self::Data) -> Result<()> { + let (rdpi, adpi, data_type) = self.data_info(data)?; + let baked_buffer = self.bake_data(data)?; + self.buffer = baked_buffer; + unsafe { + gl.use_program(self.program.native_program); + self.set_conf(gl, rdpi, adpi); + gl.bind_vertex_array(self.vao); + gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + cast_slice(&self.buffer), + glow::STATIC_DRAW, + ); + } + + Ok(()) + } +} + +mod test { + #[test] + fn test_ppi() { + use super::*; + // let ppi = PPI::new().unwrap(); + } +} diff --git a/src/graphics/transforms/mod.rs b/src/graphics/transforms/mod.rs index bbfe261..56d69f7 100644 --- a/src/graphics/transforms/mod.rs +++ b/src/graphics/transforms/mod.rs @@ -2,12 +2,50 @@ pub mod polar; pub mod position; pub mod trackball; pub mod viewport; -use crate::components::Snippet; +use crate::components::{Program, Snippet}; -pub trait Transform { +use super::AttaWithProgram; + +pub struct ChainedTransform { + snippet: Snippet, + chain: Vec>, +} + +impl ChainedTransform { + pub fn from(transform: T) -> Self { + let snippet = transform.snippet().clone(); + // let snippet = transform.snippet().to_owned(); + Self { + snippet, + chain: vec![Box::new(transform)], + } + } + + pub fn chain(mut self, other: impl Transform + 'static) -> Self { + let new_snippet = self.snippet.clone().chain(other.snippet().to_owned()); + self.snippet = new_snippet; + self.chain.push(Box::new(other)); + self + } +} + +impl Transform for ChainedTransform { + fn snippet(&self) -> &Snippet { + &self.snippet + } +} + +impl AttaWithProgram for ChainedTransform { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> super::Result<()> { + for transform in &self.chain { + transform.attach_with_program(gl, program)?; + } + + Ok(()) + } +} +pub trait Transform: AttaWithProgram { fn snippet(&self) -> &Snippet; - - fn chain(self, other: impl Transform) -> Self; } mod test { @@ -16,11 +54,11 @@ mod test { #[test] fn test_transform() { let polar = polar::Polar::new().unwrap(); - let trackball = trackball::Trackball::new().unwrap(); - let polar_trackball = polar.chain(trackball); + // let trackball = trackball::Trackball::new().unwrap(); - println!("{}", polar_trackball.snippet().prepare_code()); + // let chained = ChainedTransform::from(polar).chain(trackball); - // println!("{}", polar_trackball.snippet().call(vec![])); + // println!("{}", chained.snippet().prepare_code()); + // println!("{}", chained.snippet().call(&vec![]).unwrap()); } } diff --git a/src/graphics/transforms/polar.rs b/src/graphics/transforms/polar.rs index 9b3377d..1a8cd43 100644 --- a/src/graphics/transforms/polar.rs +++ b/src/graphics/transforms/polar.rs @@ -1,6 +1,7 @@ use crate::{ - components::{CodeType, Snippet}, + components::{CodeType, Program, Snippet}, errors::*, + graphics::AttaWithProgram, }; use super::Transform; @@ -30,11 +31,11 @@ impl Transform for Polar { fn snippet(&self) -> &Snippet { &self.snippet } +} - fn chain(mut self, other: impl Transform) -> Self { - let new_snippet = self.snippet.chain(other.snippet().to_owned()); - self.snippet = new_snippet; - self +impl AttaWithProgram for Polar { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + Ok(()) } } diff --git a/src/graphics/transforms/position.rs b/src/graphics/transforms/position.rs index 209774d..201bc2c 100644 --- a/src/graphics/transforms/position.rs +++ b/src/graphics/transforms/position.rs @@ -1,7 +1,8 @@ use super::Transform; use crate::{ - components::{CodeType, Snippet}, + components::{CodeType, Program, Snippet}, errors::*, + graphics::AttaWithProgram, }; pub struct Position { snippet: Snippet, @@ -24,11 +25,11 @@ impl Transform for Position { fn snippet(&self) -> &Snippet { &self.snippet } +} - fn chain(mut self, other: impl Transform) -> Self { - let new_snippet = self.snippet.chain(other.snippet().to_owned()); - self.snippet = new_snippet; - self +impl AttaWithProgram for Position { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + Ok(()) } } diff --git a/src/graphics/transforms/trackball.rs b/src/graphics/transforms/trackball.rs index d8478a7..c4e1ffe 100644 --- a/src/graphics/transforms/trackball.rs +++ b/src/graphics/transforms/trackball.rs @@ -1,10 +1,144 @@ -use crate::components::{CodeType, Snippet}; +use crate::components::{CodeType, Program, Snippet}; use crate::errors::Result; +use crate::graphics::AttaWithProgram; use super::Transform; +use glow::HasContext; +use nalgebra::{Matrix4, Quaternion, Translation3, Unit, UnitQuaternion, Vector3}; + +pub struct TrackballModel { + rotation: UnitQuaternion, + count: usize, + model: Matrix4, + renorm_count: usize, + trackball_size: f32, + x: f32, + y: f32, + theta: f32, + phi: f32, +} + +impl TrackballModel { + pub fn new(theta: f32, phi: f32) -> Self { + let mut trackball = Self { + rotation: UnitQuaternion::identity(), + count: 0, + model: Matrix4::identity(), + renorm_count: 97, + trackball_size: 0.8, + x: 0.0, + y: 0.0, + theta, + phi, + }; + trackball.set_orientation(theta, phi); + trackball + } + + pub fn drag_to(&mut self, x: f32, y: f32, dx: f32, dy: f32) { + let q = self.rotate(x, y, dx, dy); + self.rotation *= q; + self.count += 1; + if self.count > self.renorm_count { + self.rotation = UnitQuaternion::new_normalize(*self.rotation.clone()); + self.count = 0; + } + self.model = self.rotation.to_homogeneous(); + } + + pub fn model(&self) -> &Matrix4 { + &self.model + } + + pub fn theta(&self) -> f32 { + self.theta + } + + pub fn set_theta(&mut self, theta: f32) { + self.set_orientation(theta % 360.0, self.phi % 360.0); + } + + pub fn phi(&self) -> f32 { + self.phi + } + + pub fn set_phi(&mut self, phi: f32) { + self.set_orientation(self.theta % 360.0, phi % 360.0); + } + + fn get_orientation(&self) -> (f32, f32) { + let q = self.rotation.quaternion(); + let ax = (2.0 * (q.w * q.i + q.j * q.k) / (1.0 - 2.0 * (q.i * q.i + q.j * q.j))).atan() + * 180.0 + / std::f32::consts::PI; + let az = (2.0 * (q.w * q.k + q.i * q.j) / (1.0 - 2.0 * (q.j * q.j + q.k * q.k))).atan() + * 180.0 + / std::f32::consts::PI; + (-az, ax) + } + + fn set_orientation(&mut self, theta: f32, phi: f32) { + self.theta = theta; + self.phi = phi; + + let angle = self.theta * (std::f32::consts::PI / 180.0); + let sine = (0.5 * angle).sin(); + let xrot = + UnitQuaternion::from_quaternion(Quaternion::new((0.5 * angle).cos(), sine, 0.0, 0.0)); + + let angle = self.phi * (std::f32::consts::PI / 180.0); + let sine = (0.5 * angle).sin(); + let zrot = + UnitQuaternion::from_quaternion(Quaternion::new((0.5 * angle).cos(), 0.0, 0.0, sine)); + + self.rotation = xrot * zrot; + self.model = self.rotation.to_homogeneous(); + } + + fn project(&self, r: f32, x: f32, y: f32) -> f32 { + let d = (x * x + y * y).sqrt(); + if d < r * 0.70710678118654752440 { + (r * r - d * d).sqrt() + } else { + let t = r / 1.41421356237309504880; + t * t / d + } + } + + fn rotate(&self, x: f32, y: f32, dx: f32, dy: f32) -> UnitQuaternion { + if dx == 0.0 && dy == 0.0 { + return UnitQuaternion::identity(); + } + + let last = Vector3::new(x, y, self.project(self.trackball_size, x, y)); + let new = Vector3::new( + x + dx, + y + dy, + self.project(self.trackball_size, x + dx, y + dy), + ); + + let a = new.cross(&last); + let d = last - new; + let t = d.norm() / (2.0 * self.trackball_size); + let t = t.clamp(-1.0, 1.0); + + let phi = 2.0 * t.asin(); + UnitQuaternion::from_axis_angle(&Unit::new_normalize(a), phi) + } +} + pub struct Trackball { snippet: Snippet, + + znear: f32, + zfar: f32, + zoom: f32, + aspect: f32, + model: TrackballModel, + + projection: nalgebra_glm::Mat4x4, + view: nalgebra::Matrix4, } impl Trackball { @@ -16,7 +150,84 @@ impl Trackball { None, )?; - Ok(Self { snippet: snippets }) + let model = TrackballModel::new(45.0, 45.0); + + let aspect = 1.0; + let fovy = 45.0; + let near = 2.0; + let far = 1000.0; + + let projection = nalgebra_glm::perspective(aspect, fovy, near, far); + + let mut view: Matrix4 = Matrix4::identity(); + + let distance: f32 = 8.0; + + let translation = Translation3::new(0.0, 0.0, -distance.abs()); + view = translation.to_homogeneous() * view; + + Ok(Self { + snippet: snippets, + znear: near, + zfar: far, + zoom: fovy, + aspect, + model, + projection, + view, + }) + } + + pub fn on_mouse_drag( + &mut self, + gl: &glow::Context, + program: &mut Program, + x: f32, + y: f32, + dx: f32, + dy: f32, + ) { + self.model.drag_to(x, y, dx, dy); + unsafe { + let model = self.snippet.find_symbol("trackball_model").unwrap(); + let l = program.get_uniform_location(gl, &model); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); + } + } + + pub fn on_mouse_scroll( + &mut self, + gl: &glow::Context, + program: &mut Program, + x: f32, + y: f32, + dz: f32, + ) { + self.zoom += dz; + self.projection = nalgebra_glm::perspective(self.aspect, self.zoom, self.znear, self.zfar); + unsafe { + let model = self.snippet.find_symbol("trackball_projection").unwrap(); + let l = program.get_uniform_location(gl, &model); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); + } + } + + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + unsafe { + let model = self.snippet.find_symbol("trackball_model").unwrap(); + let l = program.get_uniform_location(gl, &model); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); + + let projection = self.snippet.find_symbol("trackball_projection").unwrap(); + let l = program.get_uniform_location(gl, &projection); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.projection.as_slice()); + + let view = self.snippet.find_symbol("trackball_view").unwrap(); + let l = program.get_uniform_location(gl, &view); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.view.as_slice()); + } + + Ok(()) } } @@ -24,11 +235,11 @@ impl Transform for Trackball { fn snippet(&self) -> &Snippet { &self.snippet } +} - fn chain(mut self, other: impl Transform) -> Self { - let new_snippet = self.snippet.chain(other.snippet().to_owned()); - self.snippet = new_snippet; - self +impl AttaWithProgram for Trackball { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + self.attach_with_program(gl, program) } } @@ -37,8 +248,7 @@ mod test { #[test] fn test_trackball() { - let trackball = Trackball::new().unwrap(); - - println!("{}", trackball.snippet); + // let trackball = Trackball::new().unwrap(); + // println!("{}", trackball.snippet); } } diff --git a/src/graphics/transforms/viewport.rs b/src/graphics/transforms/viewport.rs index 432db40..751ded3 100644 --- a/src/graphics/transforms/viewport.rs +++ b/src/graphics/transforms/viewport.rs @@ -1,9 +1,15 @@ +use glow::HasContext; + use crate::{ - components::{self, CodeType, Snippet}, + components::{self, CodeType, Program, Snippet}, errors::*, + graphics::AttaWithProgram, }; +#[derive(Debug, Clone)] pub struct Viewport { snippet: Snippet, + viewport_global: [f32; 4], + viewport_local: Option<[f32; 4]>, } impl Viewport { @@ -15,10 +21,71 @@ impl Viewport { None, )?; - Ok(Self { snippet: snippets }) + Ok(Self { + snippet: snippets, + viewport_global: [0.0, 0.0, 0.0, 0.0], + viewport_local: None, + }) } pub fn snippet(&self) -> &Snippet { &self.snippet } + + pub fn set_global(&mut self, x: f32, y: f32, width: f32, height: f32) { + self.viewport_global = [x, y, width, height]; + } + + pub fn create_local(&self, x: f32, y: f32, width: f32, height: f32) -> Self { + let mut l = self.clone(); + l.viewport_local = Some([x, y, width, height]); + l + } + + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + unsafe { + let global = self.snippet.find_symbol("viewport_global").unwrap(); + let l = program.get_uniform_location(gl, &global); + gl.uniform_4_f32( + l.as_ref(), + self.viewport_global[0], + self.viewport_global[1], + self.viewport_global[2], + self.viewport_global[3], + ); + + let local = self.snippet.find_symbol("viewport_local").unwrap(); + + if let Some([x, y, z, w]) = self.viewport_local { + let l = program.get_uniform_location(gl, &local); + let l = l.as_ref(); + gl.uniform_4_f32(l, x, y, z, w); + } else { + let l = program.get_uniform_location(gl, &local); + let l = l.as_ref(); + gl.uniform_4_f32( + l, + self.viewport_global[0], + self.viewport_global[1], + self.viewport_global[2], + self.viewport_global[3], + ); + } + + let viewport = self.snippet.find_symbol("viewport_transform").unwrap(); + let l = program.get_uniform_location(gl, &viewport); + gl.uniform_1_f32(l.as_ref(), 0.0); + + let viewport = self.snippet.find_symbol("viewport_clipping").unwrap(); + let l = program.get_uniform_location(gl, &viewport); + gl.uniform_1_f32(l.as_ref(), 0.0); + } + Ok(()) + } +} + +impl AttaWithProgram for Viewport { + fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { + self.attach_with_program(gl, program) + } } diff --git a/src/main.rs b/src/main.rs index 9de5286..9c993ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,10 @@ +use data_loader::Data; +use graphics::AttaWithBuffer; use imgui::Condition; mod camera; mod components; +mod data_loader; mod errors; mod graphics; mod support; @@ -12,8 +15,10 @@ mod final_pg; fn main() { env_logger::init(); let choices = ["test test this is 1", "test test this is 2"]; + let path = "/Users/tsuki/Desktop/ZJSXAA_20230113070200_R.dat.gz"; + let data = Data::from_path(path).unwrap(); let mut value = 0; - support::supporter::init(move |_, ui| { + support::supporter::init(move |_, ui, program, window, gl| { ui.window("Hello world") .size([300.0, 110.0], Condition::FirstUseEver) .build(|| { @@ -31,25 +36,18 @@ fn main() { "Mouse Position: ({:.1},{:.1})", mouse_pos[0], mouse_pos[1] )); - }); - ui.window("Hello world") - .size([300.0, 110.0], Condition::FirstUseEver) - .build(|| { - ui.text_wrapped("Hello world!"); - ui.text_wrapped("こんにちは世界!"); - if ui.button(choices[value]) { - value += 1; - value %= 2; + if ui.button("Add Layer") { + program.add_ppi_layer(1); + program.attach_with_buffer(gl, &data).unwrap(); + window.request_redraw(); } - ui.button("This...is...imgui-rs!"); - ui.separator(); - let mouse_pos = ui.io().mouse_pos; - ui.text(format!( - "Mouse Position: ({:.1},{:.1})", - mouse_pos[0], mouse_pos[1] - )); + if ui.button("Remove Layer") { + program.add_ppi_layer(-1); + program.attach_with_buffer(gl, &data).unwrap(); + window.request_redraw(); + } }); }); } diff --git a/src/support/supporter.rs b/src/support/supporter.rs index 5ce1e6b..154a7ab 100644 --- a/src/support/supporter.rs +++ b/src/support/supporter.rs @@ -1,5 +1,8 @@ use crate::camera::Camera; -use crate::graphics::Graphics; +use crate::graphics::colormap::linear::LinearColormap; +use crate::graphics::ppi::PPI; +use crate::graphics::transforms::{position, ChainedTransform}; +use crate::graphics::{hello, AttaWithBuffer, AttaWithProgram, Graphics}; use crate::{ graphics::{ collections::agg_fast_path::AggFastPath, @@ -34,28 +37,16 @@ use std::time::Instant; pub fn init(mut run_ui: FUi) where - FUi: FnMut(&mut bool, &mut Ui) + 'static, + FUi: FnMut(&mut bool, &mut Ui, &mut PPI, &Window, &glow::Context) + 'static, { let (event_loop, window, surface, context) = create_window(); let (mut winit_platform, mut imgui_context) = imgui_init(&window); - { - let dpi_mode = if let Ok(factor) = std::env::var("IMGUI_EXAMPLE_FORCE_DPI_FACTOR") { - // Allow forcing of HiDPI factor for debugging purposes - match factor.parse::() { - Ok(f) => HiDpiMode::Locked(f), - Err(e) => panic!("Invalid scaling factor: {}", e), - } - } else { - HiDpiMode::Default - }; - - winit_platform.attach_window(imgui_context.io_mut(), &window, dpi_mode); - } - let gl = unsafe { let gl = glow_context(&context); gl.enable(glow::DEPTH_TEST); + gl.enable(glow::BLEND); + gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); gl }; @@ -64,30 +55,37 @@ where .expect("failed to create renderer"); let mut last_frame = Instant::now(); - let tri_renderer = Triangler::new(ig_renderer.gl_context(), "#version 330"); + let transform = Position::new().unwrap(); - let viewport = Trackball::new().unwrap(); - let trans = Polar::new().unwrap(); - let position = Position::new().unwrap(); + let mut viewport = Viewport::new().unwrap(); + let mut cmap = LinearColormap::new().unwrap(); - let transform = viewport.chain(trans.chain(position)); + cmap.set_colors(vec![ + [170, 170, 170, 255], + [0, 34, 255, 255], + [1, 160, 246, 255], + [0, 236, 236, 255], + [0, 216, 0, 255], + [1, 144, 0, 255], + [255, 255, 0, 255], + [231, 192, 0, 255], + [255, 144, 0, 255], + [255, 0, 0, 255], + [214, 0, 0, 255], + [192, 0, 0, 255], + [255, 0, 240, 255], + [150, 0, 180, 255], + ]); + cmap.set_range(0.0, 70.0); - let viewport = Viewport::new().unwrap(); + let mut ppi = PPI::new(&mut cmap).unwrap(); + ppi.set_transform(&transform); + ppi.set_viewport(&viewport); + ppi.compile(ig_renderer.gl_context()).unwrap(); - let mut agg_path = AggFastPath::new(&transform, &viewport).unwrap(); - - agg_path.compile(ig_renderer.gl_context()).unwrap(); - - let program = tri_renderer.program(); - let mut camera = Camera::new( - Vec3::new(0.5, 0.5, 1.0), // Camera position (world location - Vec3::new(0.0, 1.0, 0.0), // Upward vector - Vec3::new(0.0, 0.0, -1.0), // Look at vector - ); - - let mut last_position: Option> = None; - let mut yaw = -90.0; - let mut pitch = 0.0; + transform + .attach_with_program(ig_renderer.gl_context(), ppi.program_ref()) + .unwrap(); event_loop .run(move |event, window_target| { @@ -115,40 +113,26 @@ where unsafe { let gl = ig_renderer.gl_context(); - - gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT); - - let loc = gl.get_uniform_location(program, "projection"); - let size = window.inner_size(); - let projection = - perspective(size.width as f32 / size.height as f32, 45.0, 0.1, 100.0); - gl.uniform_matrix_4_f32_slice(loc.as_ref(), false, projection.as_slice()); - - let loc = gl.get_uniform_location(program, "view"); - let view = camera.get_view_matrix(); - gl.uniform_matrix_4_f32_slice(loc.as_ref(), false, view.as_slice()); + gl.clear(glow::DEPTH_BUFFER_BIT); } - - tri_renderer.render(ig_renderer.gl_context()); - + ppi.draw(ig_renderer.gl_context()).unwrap(); let ui = imgui_context.frame(); - if ui.is_mouse_pos_valid(ui.io().mouse_pos) { let mouse_pos = ui.io().mouse_pos; if ui.is_mouse_dragging(imgui::MouseButton::Right) { - mouse_callback( - &mut last_position, - PhysicalPosition::new(mouse_pos[0] as f64, mouse_pos[1] as f64), - 0.05, - &mut pitch, - &mut yaw, - &mut camera, - ); + // mouse_callback( + // &mut last_position, + // PhysicalPosition::new(mouse_pos[0] as f64, mouse_pos[1] as f64), + // 0.05, + // &mut pitch, + // &mut yaw, + // &mut camera, + // ); } } let mut run = true; - run_ui(&mut run, ui); + run_ui(&mut run, ui, &mut ppi, &window, ig_renderer.gl_context()); if !run { window_target.exit(); @@ -182,12 +166,23 @@ where NonZeroU32::new(new_size.width).unwrap(), NonZeroU32::new(new_size.height).unwrap(), ); + + viewport.set_global( + 0f32, + 0f32, + new_size.width as f32, + new_size.height as f32, + ); + + viewport + .attach_with_program(ig_renderer.gl_context(), ppi.program_ref()) + .unwrap(); } winit_platform.handle_event(imgui_context.io_mut(), &window, &event); } winit::event::Event::LoopExiting => { let gl = ig_renderer.gl_context(); - tri_renderer.destroy(gl); + ppi.destroy(gl).unwrap(); } event => { winit_platform.handle_event(imgui_context.io_mut(), &window, &event); @@ -302,11 +297,20 @@ fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { imgui_context.set_ini_filename(None); let mut winit_platform = WinitPlatform::init(&mut imgui_context); - winit_platform.attach_window( - imgui_context.io_mut(), - window, - imgui_winit_support::HiDpiMode::Rounded, - ); + + { + let dpi_mode = if let Ok(factor) = std::env::var("IMGUI_EXAMPLE_FORCE_DPI_FACTOR") { + // Allow forcing of HiDPI factor for debugging purposes + match factor.parse::() { + Ok(f) => HiDpiMode::Locked(f), + Err(e) => panic!("Invalid scaling factor: {}", e), + } + } else { + HiDpiMode::Default + }; + + winit_platform.attach_window(imgui_context.io_mut(), &window, dpi_mode); + } imgui_context .fonts() diff --git a/src/utils/geo_tools.rs b/src/utils/geo_tools.rs new file mode 100644 index 0000000..a5558fa --- /dev/null +++ b/src/utils/geo_tools.rs @@ -0,0 +1,17 @@ +use geo::{algorithm::haversine_destination::HaversineDestination, Point}; +pub fn calculate_coverage(lat_deg: f64, lon_deg: f64, radius_km: f64) -> (f64, f64, f64, f64) { + let center = Point::new(lon_deg, lat_deg); + + // 计算四个方向(北、南、东、西)的点 + let north = center.haversine_destination(0.0, radius_km); + let south = center.haversine_destination(180.0, radius_km); + let east = center.haversine_destination(90.0, radius_km); + let west = center.haversine_destination(270.0, radius_km); + + let min_lat = south.y(); + let max_lat = north.y(); + let min_lon = west.x(); + let max_lon = east.x(); + + (min_lat, max_lat, min_lon, max_lon) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c15fa30..23b5d6f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,6 +2,7 @@ mod parser; use include_dir::{include_dir, Dir}; pub use parser::*; use std::{num::NonZeroU32, path::Path}; +pub mod geo_tools; use glow::HasContext; use glutin::{ diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 6052a1c..77c7363 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -14,12 +14,12 @@ use nom::{ branch::alt, bytes::complete::{tag, take_till, take_until, take_while, take_while1}, character::complete::{ - alpha1, char, digit1, multispace0, multispace1, none_of, space0, space1, + alpha1, char, digit0, digit1, multispace0, multispace1, none_of, space0, space1, }, combinator::{cut, map, map_res, opt, recognize, verify}, multi::{fold_many0, many0, many0_count, many1, separated_list0, separated_list1}, sequence::{delimited, pair, preceded, separated_pair, terminated, tuple}, - IResult, InputIter, + Finish, IResult, InputIter, }; use crate::{components::Snippet, errors::*}; @@ -143,8 +143,10 @@ pub enum Modifier { Static, Extern, Uniform, - In(Option), + Layout(Option>), + In, Out, + Flat, } impl Display for Modifier { @@ -154,9 +156,18 @@ impl Display for Modifier { Modifier::Static => write!(f, "static"), Modifier::Extern => write!(f, "extern"), Modifier::Uniform => write!(f, "uniform"), - Modifier::In(Some(v)) => write!(f, "layout(location = {}) in", v), - Modifier::In(None) => write!(f, "in"), + Modifier::In => write!(f, "in"), + Modifier::Layout(Some(v)) => write!( + f, + "layout({})", + v.iter() + .map(|v| v.to_string()) + .collect::>() + .join(",") + ), + Modifier::Layout(None) => write!(f, "layout"), Modifier::Out => write!(f, "out"), + Modifier::Flat => write!(f, "flat"), } } } @@ -176,24 +187,22 @@ fn modifier(input: &str) -> IResult<&str, Modifier> { Ok::>(Modifier::Uniform) }), map_res( - pair( - opt(tuple(( - tag("layout"), - multispace0::<&str, nom::error::Error<&str>>, - delimited( - char('('), - tuple((tag("location"), multispace0, char('='), space0, digit1)), - char(')'), - ), - space0, - ))), - tag("in"), - ), - |(a, _)| { - let c = a.map(|(_, _, (_, _, _, _, v), _)| v.parse::().unwrap()); - Ok::>(Modifier::In(c)) - }, + tuple(( + tag("layout"), + opt(delimited( + char('('), + separated_list0(char(','), ws(alt((parse_assignment, parse_variable)))), + char(')'), + )), + )), + |(_, v)| Ok::>(Modifier::Layout(v)), ), + map_res(tag("flat"), |_| { + Ok::>(Modifier::Flat) + }), + map_res(tag("in"), |_| { + Ok::>(Modifier::In) + }), map_res(tag("out"), |_| { Ok::>(Modifier::Out) }), @@ -217,7 +226,8 @@ impl Display for ShareVariable { self.modif .iter() .map(|v| format!("{}", v)) - .collect::(), + .collect::>() + .join(" "), self.typ, self.name, self.value @@ -228,17 +238,19 @@ impl Display for ShareVariable { } } +fn array_parse(input: &str) -> IResult<&str, Option> { + let (input, v) = delimited(pair(char('['), space0), digit0, ws(char(']')))(input)?; + Ok((input, v.parse().ok())) +} + fn _share_variable(input: &str) -> IResult<&str, ShareVariable> { - let (input, modifier) = many0(modifier)(input)?; - let (input, _) = multispace1(input)?; + let (input, modifier) = many0(terminated(modifier, multispace1))(input)?; + // let (input, _) = multispace1(input)?; let (input, typ) = type_name(input)?; let (input, _) = multispace1(input)?; - let (input, name) = identifier(input)?; + let (input, name) = recognize(pair(identifier, opt(array_parse)))(input)?; - let (input, value) = opt(preceded( - ws(char('=')), - ws(take_till(|c| c == ';' || c == '\n')), - ))(input)?; + let (input, value) = opt(preceded(ws(char('=')), ws(take_till(|c| c == ';'))))(input)?; Ok(( input, ShareVariable { @@ -250,6 +262,11 @@ fn _share_variable(input: &str) -> IResult<&str, ShareVariable> { )) } +fn geom_layout(input: &str) -> IResult<&str, Vec> { + let (input, modifier) = separated_list1(space1, modifier)(input)?; + Ok((input, modifier)) +} + #[derive(Debug, PartialEq, Clone, Eq, Hash)] pub enum PreprocessorDirective { IfDef { condition: String }, @@ -441,7 +458,7 @@ fn hook(input: &str) -> IResult<&str, Hook> { separated_list1(char('.'), identifier), opt(delimited( char('('), - separated_list0(ws(char(',')), ws(identifier)), + separated_list0(char(','), ws(expression)), char(')'), )), ), @@ -481,6 +498,40 @@ pub enum Code { PreprocessorDirective(Rc>, Box>), Macro(Rc>), ShareVariable(Rc>), + GeomLayout(Rc>>), +} + +impl Code { + pub fn parse(input: &str) -> IResult<&str, Self> { + ws(alt(( + map( + tuple(( + alt((parse_ifdef, parse_ifndef)), + many0(Self::parse), + cut(parse_endif), + )), + |(pre, inner, _)| { + Code::PreprocessorDirective(Rc::new(RefCell::new(pre)), Box::new(inner)) + }, + ), + map(parse_macro, |v| Code::Macro(Rc::new(RefCell::new(v)))), + map(include, |v| Code::Include(Rc::new(RefCell::new(v)))), + map(function, |v| Code::Function(Rc::new(RefCell::new(v)))), + map(terminated(parse_struct, pair(space0, char(';'))), |s| { + Code::Struct(Rc::new(RefCell::new(s))) + }), + map(terminated(_share_variable, char(';')), |v| { + Code::ShareVariable(Rc::new(RefCell::new(v))) + }), + map(terminated(geom_layout, char(';')), |v| { + Code::GeomLayout(Rc::new(RefCell::new(v))) + }), + )))(input) + } + + pub fn new(input: &str) -> Self { + Self::parse(input).finish().unwrap().1 + } } #[derive(Debug, Clone)] @@ -664,7 +715,7 @@ impl Display for Statement { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Expression { Binary { left: Box, @@ -694,6 +745,10 @@ pub enum Expression { base: Box, member: String, }, + ArrayAccess { + base: Box, + member: Box, + }, Hook(Hook), } @@ -740,6 +795,9 @@ impl Display for Expression { Expression::Hook(hook) => write!(f, "{}", hook), Expression::StructMemberAccess { base, member } => write!(f, "{}.{}", base, member), Expression::StructPointerAccess { base, member } => write!(f, "{}->{}", base, member), + Expression::ArrayAccess { base, member } => { + write!(f, "{}[{}]", base, member) + } } } } @@ -879,13 +937,31 @@ fn parse_arith(input: &str) -> IResult<&str, Expression> { )(input) } +fn parse_array_access(input: &str) -> IResult<&str, Expression> { + let inn = delimited( + char('['), + alt((map(parse_integer, Expression::Literal), parse_variable)), + char(']'), + ); + let (input, rs) = pair(parse_variable, inn)(input)?; + + Ok(( + input, + Expression::ArrayAccess { + base: Box::new(rs.0), + member: Box::new(rs.1), + }, + )) +} + fn parse_factor(input: &str) -> IResult<&str, Expression> { delimited( multispace0, alt(( delimited(char('('), expression, char(')')), - parse_struct_pointer_access, parse_struct_member_access, + parse_struct_pointer_access, + parse_array_access, parse_unary, parse_function_call, parse_assignment, @@ -957,7 +1033,10 @@ fn parse_struct_member_access(input: &str) -> IResult<&str, Expression> { map( separated_pair( alt(( + // parse_struct_member_access, + // parse_struct_pointer_access, map(hook, Expression::Hook), + parse_array_access, map(identifier, |v| Expression::Variable(v.to_string())), )), char('.'), @@ -1142,6 +1221,20 @@ impl Display for Code { } Code::Macro(v) => write!(f, "{}", *v.borrow()), Code::ShareVariable(v) => write!(f, "{};", *v.borrow()), + Code::GeomLayout(v) => { + write!( + f, + "{}", + v.borrow() + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(" ") + )?; + writeln!(f, ";")?; + + Ok(()) + } } } } @@ -1210,27 +1303,7 @@ impl CodeBlock { } fn _parse(input: &str) -> IResult<&str, Vec> { - many1(ws(alt(( - map( - tuple(( - alt((parse_ifdef, parse_ifndef)), - Self::_parse, - cut(parse_endif), - )), - |(pre, inner, _)| { - Code::PreprocessorDirective(Rc::new(RefCell::new(pre)), Box::new(inner)) - }, - ), - map(parse_macro, |v| Code::Macro(Rc::new(RefCell::new(v)))), - map(include, |v| Code::Include(Rc::new(RefCell::new(v)))), - map(function, |v| Code::Function(Rc::new(RefCell::new(v)))), - map(terminated(parse_struct, pair(space0, char(';'))), |s| { - Code::Struct(Rc::new(RefCell::new(s))) - }), - map(terminated(_share_variable, char(';')), |v| { - Code::ShareVariable(Rc::new(RefCell::new(v))) - }), - ))))(input) + many1(Code::parse)(input) } pub fn public_variables(&self) -> Vec<&RFC> { @@ -1291,7 +1364,10 @@ impl CodeBlock { } } - Expression::FunctionCall { parameters, .. } => { + Expression::FunctionCall { parameters, name } => { + if let Some(new) = map.get(name) { + *name = new.clone(); + } for para in parameters.iter_mut() { _expression_mangling(para, map); } @@ -1302,12 +1378,24 @@ impl CodeBlock { _expression_mangling(right, map); } + Expression::Binary { left, right, .. } => { + _expression_mangling(left, map); + _expression_mangling(right, map); + } + + Expression::Unary { right, .. } => { + _expression_mangling(right, map); + } + Expression::StructMemberAccess { base, .. } => { _expression_mangling(base, map); } - Expression::StructPointerAccess { base, .. } => { + Expression::StructPointerAccess { base, .. } => _expression_mangling(base, map), + + Expression::ArrayAccess { base, member } => { _expression_mangling(base, map); + _expression_mangling(member, map); } _ => {} @@ -1331,6 +1419,15 @@ impl CodeBlock { _mangling_block(block, map); } + Statement::Else { block } => { + if let Statement::If { condition, block } = block.as_mut() { + _expression_mangling(condition, map); + _mangling_block(block, map); + } else { + _mangling_block(block, map); + } + } + Statement::While { condition, block } => { _expression_mangling(condition, map); _mangling_block(block, map); @@ -1420,6 +1517,10 @@ impl CodeBlock { pub fn find_variable(&self, name: &str) -> Option<&RFC> { self.snippet.find_variable(name) } + + pub fn insert(&mut self, code: Code, index: usize) { + self.codes.insert(index, code); + } } impl SnippetCode { @@ -1706,10 +1807,16 @@ impl SnippetCode { Self::_check_hook_exp(old, code, v, valid); } } + Statement::Expression(v) => { Self::_check_hook_exp(old, code, v, valid); } + Statement::Return(v) => { + v.as_mut() + .map(|v| Self::_check_hook_exp(old, code, v, valid)); + } + _ => {} } } @@ -1731,57 +1838,59 @@ impl SnippetCode { #[test] fn test() { let input = r#" - // ----------------------------------------------------------------------------- -// Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved. -// Distributed under the (new) BSD License. -// ----------------------------------------------------------------------------- -uniform vec4 viewport_local; -uniform vec4 viewport_global; -uniform int viewport_transform; -uniform int viewport_clipping; + #include "transform/polar.glsl" -#ifdef _GLUMPY__VERTEX_SHADER__ -void transform() -{ - if (viewport_transform == 0) return; + layout(points) in; + layout(triangle_strip, max_vertices = 4) out; - vec4 position = gl_Position; + // conf: Elevation, Range, Resolution, 0.0 + uniform vec4 conf; - float w = viewport_local.z / viewport_global.z; - float h = viewport_local.w / viewport_global.w; - float x = 2.0*(viewport_local.x / viewport_global.z) - 1.0 + w; - float y = 2.0*(viewport_local.y / viewport_global.w) - 1.0 + h; + out float eth; + out float rng; - gl_Position = vec4((x + w*position.x/position.w)*position.w, - (y + h*position.y/position.w)*position.w, - position.z, position.w); -} -#endif + out vec4 vrange; -#ifdef _GLUMPY__FRAGMENT_SHADER__ -void clipping() -{ - if (viewport_clipping == 0) return; - vec2 position = gl_FragCoord.xy; - if( position.x < (viewport_local.x)) discard; - else if( position.x > (viewport_local.x+viewport_local.z)) discard; - else if( position.y < (viewport_local.y)) discard; - else if( position.y > (viewport_local.y+viewport_local.w)) discard; + void main() { - /* - if( length(position.x - viewport_local.x) < 1.0 ) - gl_FragColor = vec4(0,0,0,1); - else if( length(position.x - viewport_local.x - viewport_local.z) < 1.0 ) - gl_FragColor = vec4(0,0,0,1); - else if( length(position.y - viewport_local.y) < 1.0 ) - gl_FragColor = vec4(0,0,0,1); - else if( length(position.y - viewport_local.y - viewport_local.w) < 1.0 ) - gl_FragColor = vec4(0,0,0,1); - */ -} -#endif + // Resolution + vec4 reso = vec4(conf.x/2.0, conf.y/2.0, 0.0, 0.0); + float c = cos(reso.x); + vec4 po = gl_in[0].gl_Position; + + vrange = vec4(po.x - reso.x, po.y - reso.y, po.x + reso.x, po.y + reso.y); + + gl_Position = po - reso; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + vec4(-reso.x, reso.y, 0.0, 0.0); + gl_Position.y = gl_Position.y / c; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + reso; + gl_Position.y = gl_Position.y / c; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + vec4(reso.x, -reso.y, 0.0, 0.0); + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + EndPrimitive(); + + } "#; @@ -1792,64 +1901,72 @@ void clipping() #[test] fn test_expression() { - let input = " + let input = r#" + void main() { - void main () - { - fetch_uniforms(); - v_linewidth = linewidth; - v_antialias = antialias; - v_color = color; + vec4 reso = vec4(conf.x/2.0, conf.y/2.0, 0.0, 0.0); + float c = cos(reso.x); - vec4 prev_ = transform_6(forward_5(position_7(forward_2(prev.x), forward_3(prev.y), forward_4(prev.z)))); - vec4 curr_ = transform_6(forward_5(position_7(forward_2(curr.x), forward_3(curr.y), forward_4(curr.z)))); - vec4 next_ = transform_6(forward_5(position_7(forward_2(next.x), forward_3(next.y), forward_4(next.z)))); + vec4 po = gl_in[0].gl_Position; - vec2 _prev = NDC_to_viewport(prev_, .zw); - vec2 _curr = NDC_to_viewport(curr_, .zw); - vec2 _next = NDC_to_viewport(next_, .zw); + vrange = vec4(po.x - reso.x, po.y - reso.y, po.x + reso.x, po.y + reso.y); - float w = linewidth/2.0 + 1.5*antialias; - float z; - vec2 P; - if( curr == prev) { - vec2 v = normalize(_next.xy - _curr.xy); - vec2 normal = normalize(vec2(-v.y,v.x)); - P = _curr.xy + normal*w*id; - } else if (curr == next) { - vec2 v = normalize(_curr.xy - _prev.xy); - vec2 normal = normalize(vec2(-v.y,v.x)); - P = _curr.xy + normal*w*id; - } else { - vec2 v0 = normalize(_curr.xy - _prev.xy); - vec2 v1 = normalize(_next.xy - _curr.xy); - vec2 normal = normalize(vec2(-v0.y,v0.x)); - vec2 tangent = normalize(v0+v1); - vec2 miter = vec2(-tangent.y, tangent.x); - float l = abs(w / dot(miter,normal)); - P = _curr.xy + miter*l*sign(id); - } + gl_Position = po - reso; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); - if( abs(id) > 1.5 ) v_color.a = 0.0; + gl_Position = po + vec4(-reso.x, reso.y, 0.0, 0.0); + gl_Position.y = gl_Position.y / c; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); - v_distance = w*id; - gl_Position = viewport_to_NDC(P, .zw, curr_.z / curr_.w); + gl_Position = po + reso; + gl_Position.y = gl_Position.y / c; + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + gl_Position = po + vec4(reso.x, -reso.y, 0.0, 0.0); + eth = gl_Position.x; + rng = gl_Position.y; + gl_Position = ; + EmitVertex(); + + EndPrimitive(); - ; } - - "; + + "#; let result = ws(function)(input).unwrap(); - println!("{:?}", result.1); + println!("{}", result.1); } #[test] fn test_expression_2() { let input = r#" - + "#; - let result = ws(expression)(input).unwrap(); + let result = ws(hook)(input).unwrap(); + + println!("{}", result.1); +} + +#[test] +fn test_shared_variable() { + let input = r#" + in float in_value[]; + layout(points) in; + + + "#; + + let result = ws(_share_variable)(input).unwrap(); println!("{}", result.1); } @@ -1857,12 +1974,15 @@ fn test_expression_2() { #[test] fn test_function() { let input = r#" - vec4 forward(float rho, float theta, float z, float w) - { - return vec4(rho * cos(theta + polar_origin), - rho * sin(theta + polar_origin), - z, w); + float norm_rad(float rad) { + float result = mod(angle, M_2_PI); + if(result < 0.0) { + result = M_2_PI + result; } + + return result; +} + "#; let result = ws(function)(input).unwrap();